Code Monkey home page Code Monkey logo

Comments (11)

afawcett avatar afawcett commented on August 14, 2024

Yeah i'd been wondering about integrating with stuff like the query profiler, to let folks know if the rollup criteria is leveraging indexes or not, for example. What other examples do you have in mind?

from fflib-apex-common.

tmowbrey avatar tmowbrey commented on August 14, 2024

I was more thinking on the Debugging side, so creating a DiagnosticsMain class of sorts that would allow for being able to pop a class start and push diagnostic messages so that all details end up at the end of the log cycle. It would also be setup so that messages would happen at INFO or WARN so that individuals could reduce logging levels to see debug information (I think this would be super helpful in conjunction with debugging the queryfactory as it creates considerable log bloat). I'll fork out the project and do a pull request with some code for us to review. Hopefully we can get it hardened enough to release within the library.

from fflib-apex-common.

afawcett avatar afawcett commented on August 14, 2024

Sorry crossed projects earlier, i thought you where talking about DLRS diagnostic for a mo! Doh! Look forward to seeing some early ideas, please share early though, even rough mockup of the method signatures and some example usage would be good to get the conversation going.

from fflib-apex-common.

tmowbrey avatar tmowbrey commented on August 14, 2024

I was thinking something similar to the following:

public class fflib_Diagnostics 
{

public static Boolean DiagnosticsEnabled = true;

private static List<DiagnosticEntry> DiagnosticLog;
private static Integer CurrentLevel = 0;

private static List<String> stacktrace = new List<String>();
public static string ExceptionTrace = '';

private class DiagnosticEntry
{
    Integer level;
    String description;

    public DiagnosticEntry(string entrydescription)
    {
        level = CurrentLevel;
        description = entrydescription;
    }
}

public static void Push(String functionname)
{
    Debug('Entering: ' + functionname);
    CurrentLevel += 1;
    Stacktrace.add(functionname);
}

public static void Debug(String debugstring)
{
    if(!DiagnosticsEnabled)
    {
        return;
    }
    if(DiagnosticLog == null) 
    {
        DiagnosticLog = new List<DiagnosticEntry>();
    }
    DiagnosticLog.add(new DiagnosticEntry(debugstring));
}

public static void DebugException(Exception ex, SObject debugObject, Schema.SObjectField debugField)
{
    String exceptioninfo = 'Exception occurred line ' + ex.getLineNumber() + ' - ' + ex.getMessage() + ' stack: ' + ex.getStackTraceString();

    Debug(exceptioninfo);

    debugObject dbg = new debugObject.newSObject();
    dbg.put(debugField.getDescribe().getName(), CurrentLog());

    ExceptionTrace = ' Exception occurred line ' + ex.getLineNumber() + ' - ' + ex.getMessage();
    for(String st : stacktrace) 
    {
        ExceptionTrace += ' | ' + st;   
    }       
    ExceptionTrace += ' |\n ';

    if(DiagnosticsEnabled) 
    {
        insert dbg;
    }

}

public static void Pop(String functionname)
    {
        if(CurrentLevel > 0) 
        {
            Debug('Exiting: ' + functionname);
            CurrentLevel-=1;    
        }        
        if(CurrentLevel == 0) 
        {
            System.Debug(LoggingLevel.Info, 'Diagnostic Log\n' + CurrentLog());
        }
        if(StackTrace.size() > 0) 
        {
            StackTrace.remove(StackTrace.size() - 1);
        }
    }

public static void PopAll()
{
    CurrentLevel = 0;
    Pop();
}

public static String CurrentLog()
{
    if(DiagnosticLog == null) 
    {
        return null;
    }
    String spaces = '                                                                        ';
    String result = '';
    for(DiagnosticEntry de : DiagnosticLog)
    {
        Integer endindex = 3 * de.level;
        if(endindex >= spaces.length()) 
        {
            endindex = spaces.length() - 1;
        }
        result += spaces.substring(0,endindex) + de.description + '\n';
    }
    return result;
}
}

from fflib-apex-common.

afawcett avatar afawcett commented on August 14, 2024

Ah yes i see, interesting, do you have a demo use case / example, perhaps with a few classes?

@capeterson whats your thoughts?

from fflib-apex-common.

tmowbrey avatar tmowbrey commented on August 14, 2024

Hello,

Here are some examples of how this class could be used:

public class Accounts extends fflib_SObjectDomain
{
    public Accounts(List<Contact> sObjectList)
    {
        super(sObjectList);
    }

    public override void onAfterInsert()
    {
        fflib_Diagnostics.Push('Accounts.onAfterInsert()');
        testDiagnostics();
        fflib_Diagnostics.Pop('Accounts.onAfterInsert()');
    }

    public void testDiagnostics()
    {
        fflib_Diagnostics.Push('Accounts.testDiagnostics()');
        List<Account> myAccounts = new AccountsSelector().getAccountsByName(new Set<String>{'Archive'});
        for(Account acc : myAccounts)
        {
            fflib_Diagnostics.Debug('Account.Name = ' + acc.Name);
        }
        fflib_Diagnostics.Pop('Accounts.testDiagnostics()');
    }

    public class Constructor implements fflib_SObjectDomain.IConstructable
    {
       public fflib_SObjectDomain construct(List<SObject> sObjectList)
       {
           return new Accounts(sObjectList);
       }
   }
}

@isTest
private class AccountsTest 
{
    @isTest
private static void testDiagnostics()
    {
        List<Account> accountsForInsert = new List<Account>();
        for(Integer i = 0; i < 10; i++)
        {
            accountsForInsert.add(new Account(Name = 'Archive'));
        }

        test.startTest();

        insert accountsForInsert;

        test.stopTest();

    }
}

debug capture

You'll see the MainEntry lines which have been added to the fflib_SObjectDomain class before and after calling the trigger handler at about line 299.

This help centralize the debugging process so that any updates to standard text or additional logic that needs to happen pre and post debug scripts can happen in one location. We also see that this allows us to move all debugging up and down the logging levels thereby helping to decrease log size and making debugging cleaner and easier to use.

I did not do a test case for logging exceptions as I think the case is pretty straight forward. It allows for logging details of exceptions (including the entire stacktrace) to a custom object and field. This could be expanded to include the current user and other details. This would have far reaching effects for those creating managed packages as you can now find the entire exception stack in the subscriber org, when it happened, and for who without needing to have a user replicate the exact issue. It should also help those that are managing single and multiple orgs for those hard to diagnose errors as well as jump on issues proactively as you can suppress exceptions for the user, review logs and action fixes before they become larger issues.

I look forward to hearing back on thoughts and changes (I've also updated my original class post to add exit details in the pop method).

Might also be worth exploring some added functionality from https://github.com/scottbcovert/Centralized-Salesforce-Dev-Framework/blob/master/src/classes/DiagnosticsInstrumentation.cls

Tyler

from fflib-apex-common.

afawcett avatar afawcett commented on August 14, 2024

Thanks for sharing that debug stream does look cleaner for sure.

Keen to get some views also from @capeterson

from fflib-apex-common.

tmowbrey avatar tmowbrey commented on August 14, 2024

Thanks!

I've also found that adding the push/pop statements in the onhandleXXX methods helps quite a bit as well as adding the debugexception method within the QueryFactory try/catch for commit work. I'm sure there are various other area's it could be incorporated within the library.

from fflib-apex-common.

tmowbrey avatar tmowbrey commented on August 14, 2024

Just wanted to bump this post and see if there are further ideas or if I should continue on integrating this into the framework and then complete a pull request?

from fflib-apex-common.

afawcett avatar afawcett commented on August 14, 2024

I'm torn by this, i feel the need, but then also worry about the over head in Apex CPU, and the need to seed it around the library and other code in a solution. Compared to the benifits it's giving. Its true that the debug logs can be a pain at times, though Salesforce are taking steps to improve things with class level filters (and i'm seeing some new stuff in Winter'16 not yet explored). Then there is of course the Apex Interactive Debugger, which is getting more real.

As regards dumping stuff into a custom object also interesting, though if its a governor exception we never get a chance to route through this method. If we do, implementing logs via custom objects in apex requires some careful thought around savepoints to avoid allowing partially completed DML's to be committed along with the log. Finally there is also the sad fact that in a managed contexted in a subscriber org, even the managed code cannot get its own full stack dump, so that benefit is eroded also.

So i'm afraid, on this occasion i have to say, thank you very much, but no thanks regarding your submission idea. That said, please do feel if you want to chat more, please do, always open to be convinced otherwise on stuff! 👍

BTW, i did notice the other day that Salesforce captures full logs even when not logged into subscriber support, regular users appear to see the managed debug missing, but then when later a subscriber support login reviews them stuff magically reappears.

from fflib-apex-common.

afawcett avatar afawcett commented on August 14, 2024

Oh and really sorry for keeping you hanging this long! My bad.

from fflib-apex-common.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.