Feedback
 
Did this article resolve your question/issue?

   

Your feedback is appreciated.

Please tell us how we can make this article more useful. Please provide us a way to contact you, should we need clarification on the feedback provided or if you need further assistance.

Characters Remaining: 1025

 


Article

Sample Code for Analyzing PASOE Agent Log for Possible Memory Leaks

« Go Back

Information

 
Article Number000074263
EnvironmentProduct: OpenEdge
Version: 11.6
OS: All Supported Platforms
Other: Progress Application Server for OpenEdge (PASOE)
Question/Problem Description
Sample Code for Analyzing PASOE Agent Log for Possible Memory Leaks
Steps to Reproduce
Clarifying Information
Error Message
Defect/Enhancement Number
Cause
Resolution
// This Program Walks Through A PASOE AppServer Agent Log File And Produces
// A Report Showing All DynObjects That Were Created But Not Deleted.
// 
// Please Note That You Should Not Use This Code Against A Log File Where
// The PASOE Instance Was Shut Down Normally As Then It Won't Show Anything
// Useful Because All Left Over DynObjects Will Get Deleted At Shutdown
// And The Log File Will Contain Deleted Entries For Each Left Over Object.
// 
// One Future Enhancement To This Code Will Implement A User Defined Time Check
// In Minutes Between Object Creation and Object Deletion To Determine Whether
// To Report An Object That Hung Around Longer Than <N> Minutes As A Potential
// Problem. This Will Allow This Program To Be Used Against A Log File Where
// The PASOE Instance Was Shut Down.  A Second Future Enhancement To This Code
// Will Handle The Allocated/Deallocated Logging Which DynObjects.* Writes To
// The Agent Log.
// 
// NOTE: The PASOE AppServer Must Have The Following Values Set
//       In The <PAS-Instance>\conf\openedge.properties file:
// 
//       AgentLoggingLevel=4
//       AgenLogEntryTypes=ASPlumbing,DB.Connects,DynObjects.*

DEFINE TEMP-TABLE TTObject NO-UNDO
    FIELD CreateLine       AS INTEGER   FORMAT "ZZZ,ZZZ,ZZ9"
    FIELD DeleteLine       AS INTEGER   FORMAT "ZZZ,ZZZ,ZZ9"
    FIELD LogDateTime      AS CHARACTER FORMAT "X(28)"
    FIELD ProcessID        AS CHARACTER FORMAT "X(20)"
    FIELD ThreadID         AS CHARACTER FORMAT "X(20)"
    FIELD ObjectType       AS CHARACTER FORMAT "X(50)"
    FIELD Created          AS LOGICAL
    FIELD Deleted          AS LOGICAL
    FIELD Allocated        AS LOGICAL
    FIELD Deallocated      AS LOGICAL
    FIELD ObjectHandle     AS INTEGER
    FIELD ObjectDetails    AS CHARACTER
    INDEX HandleIndex      AS UNIQUE ProcessID ThreadID ObjectType ObjectHandle
    INDEX MainIndex        AS UNIQUE CreateLine.
        
DEFINE VARIABLE ILineNumber AS INTEGER   NO-UNDO.
DEFINE VARIABLE CData       AS CHARACTER NO-UNDO.

// Change This To Correlate To The Date Format Used By Your <PasInstance>.Agent.log File

SESSION:DATE-FORMAT = "YMD".

// Change This To Point To Your <PasInstance>.Agent.log File

INPUT FROM C:\DLCWORK\OEPAS1\logs\OEPAS1.Agent.log.
REPEAT:
    ASSIGN ILineNumber = ILineNumber + 1.
    IMPORT UNFORMATTED CData.
    IF INDEX(CData, 'DYNOBJECTS') > 0 THEN
        // Grab Object Action From Line & Append To Prefix Then Run As Internal Procedure
        // Ignoring Any Error That May Arise Because We Haven't Implemented An Internal
        // Procedure For Said Object Action 
        RUN VALUE('Handle' + TRIM(SUBSTRING(CData, 74, 11))) IN THIS-PROCEDURE NO-ERROR.
END.    
INPUT CLOSE.

RUN ProduceReport IN THIS-PROCEDURE.

QUIT.

PROCEDURE HandleCreated:
    DO TRANSACTION:
        CREATE TTObject.
        ASSIGN TTObject.CreateLine    = ILineNumber
               TTObject.LogDateTime   = SUBSTRING(CData, 2, 26)
               TTObject.ProcessID     = TRIM(ENTRY(2, CData, ' '))
               TTObject.ThreadID      = TRIM(ENTRY(3, CData, ' '))
               TTObject.ObjectType    = TRIM(SUBSTRING(CData, 89, (INDEX(CData, 'Handle:') - 89)))
               TTObject.Created       = TRUE
               TTObject.ObjectHandle  = INTEGER(ENTRY(1, SUBSTRING(CData, (INDEX(CData, 'Handle:') + 7), 20), ' '))
               TTObject.ObjectDetails = CData.
   END.
END PROCEDURE.

PROCEDURE HandleDeleted:
    DEFINE VARIABLE LVProcessID    AS CHARACTER NO-UNDO FORMAT "X(20)".
    DEFINE VARIABLE LVThreadID     AS CHARACTER NO-UNDO FORMAT "X(20)".
    DEFINE VARIABLE LVObjectType   AS CHARACTER NO-UNDO FORMAT "X(50)".
    DEFINE VARIABLE LVObjectHandle AS INTEGER   NO-UNDO.

    ASSIGN LVProcessID    = TRIM(ENTRY(2, CData, ' '))
           LVThreadID     = TRIM(ENTRY(3, CData, ' '))
           LVObjectType   = TRIM(SUBSTRING(CData, 89, (INDEX(CData, 'Handle:') - 89)))
           LVObjectHandle = INTEGER(ENTRY(1, SUBSTRING(CData, (INDEX(CData, 'Handle:') + 7), 20), ' ')).
    
    FIND TTObject WHERE TTObject.ProcessID    = LVProcessID    AND 
                        TTObject.ThreadID     = LVThreadID     AND 
                        TTObject.ObjectType   = LVObjectType   AND 
                        TTObject.ObjectHandle = LVObjectHandle AND 
                        TTObject.Created      = TRUE           NO-ERROR.
                        
    IF AVAILABLE(TTObject) THEN
        DO TRANSACTION:
            ASSIGN TTObject.DeleteLine = ILineNumber
                   TTObject.Deleted    = TRUE.
        END.
    ELSE 
        MESSAGE 'Cannot Find Record That Matches Deletion. Possible Partial Log File?' VIEW-AS ALERT-BOX.
END PROCEDURE.

PROCEDURE HandleAllocated:
    // Not Yet Implemented
END PROCEDURE.

PROCEDURE HandleDeallocated:
    // Not Yet Implemented
END PROCEDURE.

PROCEDURE ProduceReport:
    // Produce Simple Report Showing Objects That Were Created But Not Deleted.
    // This Report Can Be Changed to Report by ProcessID and ThreadID If Required.
    
    OUTPUT TO DynObjectReport.txt.
    FOR EACH TTObject NO-LOCK WHERE TTObject.Deleted = FALSE BY TTObject.CreateLine:
        PUT UNFORMATTED 'File Line (Creation) = ' TTObject.CreateLine SKIP
                        'Date/Time Stamp      = ' TTObject.LogDateTime SKIP
                        'Process ID           = ' TTObject.ProcessID SKIP 
                        'Thread ID            = ' TTObject.ThreadID SKIP 
                        'Object Type          = ' TTObject.ObjectType SKIP 
                        'Object Handle Value  = ' TTObject.ObjectHandle SKIP 
                        'Full Line From Log   = ' TTObject.ObjectDetails SKIP(1).
    END.
    OUTPUT CLOSE.
END PROCEDURE.

 
Workaround
Notes
This code is a work in progress.  It currently does not handle the Allocate/Deallocate logging that DynObjects.* provides, nor does it handle a PASOE agent log file where the PASOE instance was shut down since that will cause delete logging for all left over DynObjects.* output and the current code will be able to match each create with its corresponding delete and consequently will not report potential leaks.

Reference to other documentation:

Progress Article(s):

000012302, How to check for leaked dynamic objects?
000084455, Detect PASOE memory leaks with Dynamic Objects Logging
Attachment 
Last Modified Date11/6/2017 8:35 AM