1

I have a managed package since we cannot see the debug logs in client orgs we are writing them to a dedicated logging object. We have a problem where it is refusing to write anything. In the debug logs it shows that it is trying to write:

16:54:57:302 DML_BEGIN [18]|Op:Insert|Type:GLxero__XeroLog__c|Rows:1

I have checked all of the profile write permissions and field level security and I don't know why it is not writing.

        try{
            OnlineInvoiceURL = XeroAccountingApi.OnlineInvoiceURL(ExistingInvoiceId);
        }catch (exception e){
            system.debug('Error getting OnlineURL'+e);
            XeroLogger.log('Calling OnlineInvoiceURL function '+e.getStackTraceString(), null );
        }

In the logger class

global with sharing class XeroLogger {

global static void log( string e, string XeroId ) {
    system.debug('Error logged: '+e);

    XeroLog__c log = new XeroLog__c(
        summary__c = XeroId,
        detail__c = e
    );

    insert log;

}



 }
  • 1
    First things first, I would suggest you log in a "without sharing" class. Your logs are not a business object and a user's access to the object should not limit your logging capabilities. In fact, I would expect business users not to have access to the object because they should not be viewing it in the UI or making edits to it. – dsharrison Dec 13 '17 at 4:13
  • Thanks @dsharrison, that is a good point I'll fix that. I copied this from another pattern. It doesn't solve the problem at hand though. – Daniel Howell Dec 13 '17 at 4:55
  • Sorry to hear that didn't fix it. Is the overall apex execution successful or does it still end in an error? I see you are catching a specific exception here, but is the overall status of the operation context a success or an exception? – dsharrison Dec 13 '17 at 5:01
  • Overall is success, because the error is within a try context. But it's not logging the error so I can fix it. @ds – Daniel Howell Dec 13 '17 at 5:08
  • Also, if I call the method from the console it will create the log record "GLxero.XeroLogger.log('test','test');" – Daniel Howell Dec 13 '17 at 5:09
1

You mentioned seeing DML_BEGIN in the debug log. I assume there is also the corresponding DML_END to go with it.

One possibility is that the entire transaction is being rolled back for reasons that occur after your code.

E.g.

try{
    OnlineInvoiceURL = XeroAccountingApi.OnlineInvoiceURL(ExistingInvoiceId);
}catch (exception e){
    system.debug('Error getting OnlineURL'+e);
    XeroLogger.log('Calling OnlineInvoiceURL function '+e.getStackTraceString(), null );
    // DML completes and log record is entered here
}

// ... More stuff happens ...

// Something throws an unhandled exception or a limit is hit and the entire
// transaction rolls back. Including your log entry.

That could certainly explain how your DML appeared in the debug log but then the record no longer existed. It could even be more fine grained than that with a surrounding Database.setSavepoint() and Database.rollback() in play, in which case the main transaction wouldn't appear to fail.

If you want to persist in maintaining your own log you could look at something like Platform Events. Platform events aren't rolled back as part of a transaction. More details in - Can I store information even if the trigger throws an exception?. Andy Fawcett gave a presentation along these lines at Dreamforce 2017.

...since we cannot see the debug logs in client orgs...

Try and set setup with the License Management App. This will give you the ability to sign into a subscribers org and gain access to your namespaces full debug logs.

Alternatively you can ask support to activate "Managed namespaces to log in Apex Debug Log".

|improve this answer|||||
  • 1
    Thanks heaps Daniel. I have set up the licence management app so I can use that. – Daniel Howell Dec 14 '17 at 3:27
0

You can create a generic class where you can pass exception as a parameter to your generic class, moreover you can pass className as a parameter so that when you will see logs you will get Idea which Apex class has thrown the exception, in managed package sometimes class Name might not be available in stack trace. You can create different fields to store more details about exception. Please refer following code, and don't make this object available for business users, hope this will help you.

For more details check this Idea
1. Allow managed package owners to debug their code in customer orgs

More Information can be found here

  1. Logging from a deployed managed package

  2. Access to debug logs in managed package

/**
 * Description: Generic class to store exception logs in cutom object
                XeroLog__c. This class is called in catch block.
 * ==================================================================================================
 *   Version     Date               Comment
 * ==================================================================================================
 *   1.0                
 **/
public without sharing class XeroLogger {

    /**
     * @description: Method to insert Exception Log
     * @param: Exception, ClassName
     * @return: N/A
    **/
    public static void insertExceptionLog(Exception e,String className){
        if(e == null) return;

        List<XeroLog__c> exceptionLoggerList = new List<XeroLog__c >();//List to store error messages occured
        XeroLog__c  objException = new XeroLog__c ();
        objException.Cause__c = e.getMessage();
        objException.Line_Number__c = e.getLineNumber();
        objException.Error_Message__c = e.getMessage();
        objException.Stack_Trace__c = e.getStackTraceString();
        objException.TypeName__c = e.getTypeName();
        objException.Class_Name__c = String.isNotBlank(className) ? className : '';
        exceptionLoggerList.add(objException);
        if(exceptionLoggerList.isEmpty() == false){
            insert exceptionLoggerList;            
        }
    }//insertExceptionLog

    /**
     * @description: Method to insert Exception Log For Database.Error
     * @param: Database.Error , String ClassName
     * @return: XeroLog__c 
    **/
    public static XeroLog__c  insertExceptionLog(Database.Error err,String className){
      XeroLog__c  objException = new XeroLog__c ();
      objException.Error_Message__c = err.getMessage();
      objException.Class_Name__c = String.isNotBlank(className) ? className : '';
      return objException;        
    }//insertExceptionLog
}
|improve this answer|||||
  • Thank you for your detailed response. While your logging tool is now comprehensive it is still going to run into the same problem I have. It is hot writing to the log object even though it says it is in the debug logs. Do you have any ideas around that? – Daniel Howell Dec 13 '17 at 8:26
  • @DanielHowell did you check the necessary permissions for XeroLog__c object? are you able to create record manually in the target org by going through custom object tab ? is there any required field ? any exception that you are getting in your debug logs ? – Nachiket Deshpande Dec 13 '17 at 8:42
  • As above I can create them through the tab, through an apex insert and by calling this method. It doesn't seem to be a permission thing. I have no idea why it is in the logs but not inserting – Daniel Howell Dec 13 '17 at 18:53
  • @DanielHowell Edited my answer check if this helps you. – Nachiket Deshpande Dec 14 '17 at 4:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.