Highlighted
Super Contributor.
Super Contributor.
2227 views

FirstChanceException logging

Jump to solution

I have code like this for FirstChanceException:

 01  currDomain                type System.AppDomain.

SET currDomain TO type AppDomain::CurrentDomain.

ATTACH METHOD FirstChanceHander TO currDomain::FirstChanceException().

       method-id FirstChanceHander static
           attribute System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions.

       local-storage section.

       procedure division using by value sender as object e as type FirstChanceExceptionEventArgs.

           GOBACK.

       end method.

Does anyone know how to write to a log from this handler?  I tried updating my own ASCII log file but that causes an exception because this method is static.  I'm trying to log some of the e::Exception properties.

Phil Levin

Tags (1)
0 Likes
2 Solutions

Accepted Solutions
Highlighted
Micro Focus Expert
Micro Focus Expert

The following example works for me. This will attach a method to the firstchangeexception event and then will raise an exception to see it execute. The handler will write the exception to the event log. Because an event log should not be used immediately after it is created the example should be run twice.

You should also protect the static method using a mutex or the sync statement if this is a multi-threaded application.

      $set ilusing"System.Runtime.ExceptionServices" 
      $set ilusing"System.Diagnostics"
      $set ilusing"System.Threading"

       class-id testfirstexception.Class1.
       working-storage section.
       method-id main static.
       local-storage section.
       procedure division.

           attach method ExceptHandler to type AppDomain::CurrentDomain::FirstChanceException
            
           try 
              raise new ArgumentException("Thrown in " & type AppDomain::CurrentDomain::FriendlyName)
           catch ex as type ArgumentException 
              display "ArgumentException caught in " & 
                 type AppDomain::CurrentDomain::FriendlyName &
                 " " &
                 ex::Message
           end-try
           
           goback.
       end method.
       method-id ExceptHandler public static.
       procedure division using by value s as object, e as type FirstChanceExceptionEventArgs.
      
        *> Create the source, if it does not already exist.
           if not type EventLog::SourceExists("MySource")
              *>An event log source should not be created and immediately used.
              *>There is a latency time to enable the source, it should be created
              *>prior to executing the application that uses the source.
              *>Execute this sample a second time to use the new source.
             
              invoke type EventLog::CreateEventSource("MySource", "MyNewLog")
              display "CreatedEventSource"
              display "Exiting, execute the application a second time to use the source."
              *> The source is created.  Exit the application to allow it to be registered.
              goback
           else
              *> Create an EventLog instance and assign its source.
              declare myLog as type EventLog = new EventLog
              set myLog::Source to "MySource"
              *> Write an informational entry to the event log.    
              invoke myLog::WriteEntry("FirstChanceException event raised in " &
                 type AppDomain::CurrentDomain::FriendlyName & " " &
                 e::Exception::StackTrace)
           end-if
           goback.
       end method.
       end class.

View solution in original post

0 Likes
Highlighted
Micro Focus Expert
Micro Focus Expert

You can find SYNC documented under the General Reference-->Managed COBOL-->Statements section here

You can place SYNC on the method or you can surround a block of code like:

Within an object:

SYNC ON SELF
     <statements>
END-SYNC

or within a static method:

01 my-sync-object   string value "statClass" static.

SYNC ON my-sync-object
   <statements>
END-SYNC

View solution in original post

0 Likes
5 Replies
Highlighted
Micro Focus Expert
Micro Focus Expert

Are you using standard COBOL I-O statements when you try to update your own ASCII log file? What is the exact exception message that you are receiving?

I know that there was a problem with earlier product releases when trying to define COBOL files within a static class if a RunUnit was present but I am not sure that applies to your case here.

0 Likes
Highlighted
Super Contributor.
Super Contributor.

I think the problem is that my class is not static but the exception handler is.  I will need to restore the code to get you the exact exception.  Would you like me to do this?

I'm looking into using the .net EventLog class for doing this.  I want to log the exception's StackTrace property when a certain exception occurs.  We have been getting a lot of crashes on AccessViolationException.  When I look at these in the Event Viewer (eventvwr.msc in the Run dialog), it sometimes shows a stack trace and sometimes not.  I can determine the type of exception in my FirstChanceException handler and log information to my own event log.  If I cannot see what's causing the exception by looking at the stack trace, I can show it to the support people at DevExpress.  If they tell me it's not caused by DevExpress I can show it to someone at Micro Focus.  I think using the EventLog class might be easier than logging to an ASCII file.  What do you think?  Also, I'm looking into using other events do do my logging, namely Application.ThreadException and UnhandledException, but maybe FirstChanceException will catch everything.

Phil Levin

0 Likes
Highlighted
Micro Focus Expert
Micro Focus Expert

The following example works for me. This will attach a method to the firstchangeexception event and then will raise an exception to see it execute. The handler will write the exception to the event log. Because an event log should not be used immediately after it is created the example should be run twice.

You should also protect the static method using a mutex or the sync statement if this is a multi-threaded application.

      $set ilusing"System.Runtime.ExceptionServices" 
      $set ilusing"System.Diagnostics"
      $set ilusing"System.Threading"

       class-id testfirstexception.Class1.
       working-storage section.
       method-id main static.
       local-storage section.
       procedure division.

           attach method ExceptHandler to type AppDomain::CurrentDomain::FirstChanceException
            
           try 
              raise new ArgumentException("Thrown in " & type AppDomain::CurrentDomain::FriendlyName)
           catch ex as type ArgumentException 
              display "ArgumentException caught in " & 
                 type AppDomain::CurrentDomain::FriendlyName &
                 " " &
                 ex::Message
           end-try
           
           goback.
       end method.
       method-id ExceptHandler public static.
       procedure division using by value s as object, e as type FirstChanceExceptionEventArgs.
      
        *> Create the source, if it does not already exist.
           if not type EventLog::SourceExists("MySource")
              *>An event log source should not be created and immediately used.
              *>There is a latency time to enable the source, it should be created
              *>prior to executing the application that uses the source.
              *>Execute this sample a second time to use the new source.
             
              invoke type EventLog::CreateEventSource("MySource", "MyNewLog")
              display "CreatedEventSource"
              display "Exiting, execute the application a second time to use the source."
              *> The source is created.  Exit the application to allow it to be registered.
              goback
           else
              *> Create an EventLog instance and assign its source.
              declare myLog as type EventLog = new EventLog
              set myLog::Source to "MySource"
              *> Write an informational entry to the event log.    
              invoke myLog::WriteEntry("FirstChanceException event raised in " &
                 type AppDomain::CurrentDomain::FriendlyName & " " &
                 e::Exception::StackTrace)
           end-if
           goback.
       end method.
       end class.

View solution in original post

0 Likes
Highlighted
Super Contributor.
Super Contributor.

Thanks.  My application is multi-threaded and I got the mutex statement working.  I couldn't find a reference to the sync statement.  C# has a SyncLock statement.  Would that be it?

Phil Levin

0 Likes
Highlighted
Micro Focus Expert
Micro Focus Expert

You can find SYNC documented under the General Reference-->Managed COBOL-->Statements section here

You can place SYNC on the method or you can surround a block of code like:

Within an object:

SYNC ON SELF
     <statements>
END-SYNC

or within a static method:

01 my-sync-object   string value "statClass" static.

SYNC ON my-sync-object
   <statements>
END-SYNC

View solution in original post

0 Likes
The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.