Logging in Progress OpenEdge apps: LOG-MANAGER and Logger Framework overview

2024 12 13 · 7 min read

When developing applications in Progress OpenEdge, logging is essential for tracking runtime behavior, debugging, and generating reports. The LOG-MANAGER system handle and the OpenEdge Logger Framework are two powerful tools for managing logging in OpenEdge applications.  

This blog explores the methods of implementing logging in OpenEdge, focusing on both the LOG-MANAGER system handle and the OpenEdge Logger Framework, comparing their features and providing practical examples of usage. 

Understanding the LOG-MANAGER system handle 

The LOG-MANAGER system handles OpenEdge controls logging settings for both the OpenEdge client and the DataServer client contexts. It offers flexibility in controlling the type and amount of logged information using a combination of log entry types and logging levels. It allows developers to programmatically control logging while executing an ABL (Advanced Business Language) program or components within the Progress Application Server (PAS) for OpenEdge.  

Key attributes and methods 

  1. LOG-ENTRY-TYPES: this attribute defines the types of information that can be written in the log file. It is a comma-separated list of valid entry types, such as “4GLMessages:2,4GLTrace:3” where each entry type corresponds to a category of log information; 
  1. LOGGING-LEVEL: represents the amount of logging information to write to the log file. Logging levels range from minimal (level 0) to detailed trace information (higher levels). For example: 
LOG-MANAGER:LOGGING-LEVEL = 3. 
LOG-MANAGER:LOG-ENTRY-TYPES = "4GLMessages:2,4GLTrace:3,4GLTrans:2". 

  1. LOGFILE-NAME: specifies the log file name where Progress OpenEdge writes log messages and ABL stack trace information; 
  1. NUM-LOG-FILES: defines the number of rolled-over log files to keep on disk. The default value is 3, but you can adjust this using the -numlogfiles startup parameter; 
  1. LOG-THRESHOLD: defines the file size threshold for the log files. Once the threshold is reached, a new log file is created. This can be set via the -logthreshold startup parameter; 
  1. CLEAR-LOG() and CLOSE-LOG(): these methods allow you to clear or close the log file respectively. The CLOSE-LOG() method writes a message indicating that the log file was closed intentionally. 

Implementing the LOG-MANAGER 

To illustrate the practical application of LOG-MANAGER, let us consider a basic implementation that sets up logging parameters, writes various messages to the log, and then closes the log file. 

LOG-MANAGER:LOGFILE-NAME = "managerLogs.log". 
LOG-MANAGER:LOGGING-LEVEL = 3. 
LOG-MANAGER:LOG-ENTRY-TYPES = "4GLMessages,4GLTrace,4GLTrans". 
LOG-MANAGER:WRITE-MESSAGE("Application logging initialized with file: " + LOG-MANAGER:LOGFILE-NAME). 
LOG-MANAGER:WRITE-MESSAGE(LOG-MANAGER:ENTRY-TYPES-LIST). 
LOG-MANAGER:WRITE-MESSAGE(STRING(LOG-MANAGER:LOG-THRESHOLD), "CUSTOM"). 
LOG-MANAGER:WRITE-MESSAGE(STRING(LOG-MANAGER:NUM-LOG-FILES), "CUSTOM-2"). 

LOG-MANAGER:CLOSE-LOG(). 

Output written to managerLogs.log 

[24/12/06@13:19:55.080+0100] P-010008 T-014460 1 4GL -- Logging level set to = 2 
[24/12/06@13:19:55.082+0100] P-010008 T-014460 1 4GL -- No entry types are activated 
[24/12/06@13:19:55.082+0100] P-010008 T-014460 1 4GL -- Logging level set to = 3 
[24/12/06@13:19:55.082+0100] P-010008 T-014460 1 4GL -- Log entry types activated: 4GLMessages,4GLTrace,4GLTrans 
[24/12/06@13:19:55.082+0100] P-010008 T-014460 1 4GL APPL           Application logging initialized with file: managerLogs.log 
[24/12/06@13:19:55.082+0100] P-010008 T-014460 1 4GL APPL           4GLMessages,4GLTrace,4GLTrans,Actional,ASK,DB.Connects,DB.Encryption,DS.Cursor,DS.QryInfo,DS.Performance,DynObjects.Class,DynObjects.DB,DynObjects.Other,DynObjects.UI,DynObjects.XML,FileID,IgnoredOps,MSASAdmin,MSASCRTInterposed,MSASSessions,MSASSignals,MSASSockets,MSASWebSocket,MSASDebugger,ProEvents.UI.Char,ProEvents.UI.Command,ProEvents.Other,QryInfo,SAX,Temp-Tables,TTStats,WSO 
[24/12/06@13:19:55.082+0100] P-010008 T-014460 1 4GL CUSTOM         0 
[24/12/06@13:19:55.082+0100] P-010008 T-014460 1 4GL CUSTOM-2       3 
[24/12/06@13:19:55.082+0100] P-010008 T-014460 1 4GL ----------     Log file closed at user's request 

Challenges and findings 

  • Limited customisation: the LOG-MANAGER system handle doesn’t allow direct customisation of log message formats. For more advanced formatting, developers might need to use workarounds, such as the OpenEdge Logger Framework; 
  • Entry types: certain entry types, such as QryInfo, are designed to log query information. However, they exclude simple queries like FIND or FOR EACH statement; 
  • File handling: by specifying a log file using the -clientlog startup parameter and assigning a file name in code with the LOG-MANAGER system handle, OpenEdge will write logs to the file specified by the LOGFILE-NAME attribute; 
  • Log level control: to turn off logging completely, set the LOGGING-LEVEL to 0. This disables logging without modifying other settings. 

Evaluation 

The LOG-MANAGER system handle is effective for standard logging and reporting runtime activities. It is useful for basic logging, tracing, and debugging but lacks the flexibility for more advanced logging configurations. 

Exploring the OpenEdge Logger Framework 

The OpenEdge Logger Framework provides a more flexible and configurable solution for logging in Progress OpenEdge applications. It enables developers to define custom log messages at various severity levels, format them, and store them in log files based on configuration settings. This framework allows logging behaviour to be controlled without modifying the application code. 

Framework components 

  1. ILogWriter Interface: the core interface for logging. It provides methods such as Error(), Info(), Debug(), etc., to define log messages at different severity levels; 
  2. Logger Class: this class processes log events based on the configurations defined in the logging.config file; 
  3. LoggerBuilder: a factory class that instantiates the Logger class with the appropriate configurations; 
  4. LogEvent: each log message generates a LogEvent object that contains details like the log message, timestamp, and severity level; 
  5. Filters: the Logger framework supports custom filters to process, format, and write log events. These filters can be tailored to meet specific needs; 
  6. LogLevelEnum: this defines the log levels (OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE), which correspond to methods in the ILogWriter interface. 

Implementing basic logging 

To get started with the OpenEdge Logger Framework, follow these steps: 

1. Create a logging.config File 

The logging.config file contains logging configurations in JSON format. It should be placed in the application’s PROPATH directory. Each configuration defines log levels and filters for specific ABL classes. 

Example of basic logging.config file: 

{ 
  "logger": { 
    "com.example.myapp": { 
      "logLevel": "DEBUG", 
      "filters": ["json", "file"] 
    } 
  } 
} 

2. Define Log Messages in Your ABL Code 

To use the Progress OpenEdge Logger framework in your ABL code: 

  • Ensure that the OpenEdge.Logging package is included in the PROPATH
  • Import the necessary classes: ILogWriter and LoggerBuilder
  • Instantiate the Logger using the LoggerBuilder:GetLogger() method; 
  • Write log messages using methods like logger:Info(), logger:Error(), logger:Debug(), etc. 

Example

DEFINE VARIABLE logger AS ILogWriter NO-UNDO. 
logger = LoggerBuilder:GetLogger("com.example.myapp"). 
logger:Info("This is an informational message"). 
logger:Error("An error occurred"). 

Logging Filters 

Logging filters in the OpenEdge Logger Framework are essential for maintaining secure and efficient logging practices, especially when dealing with sensitive information. Filters allow developers to exclude, mask or modify data from log entries, ensuring compliance with security standards and protecting user privacy.  You can apply custom rules to modify log output dynamically by configuring the Filter property in your logger definition. 

Configuration 

To configure a logging filter, you will need to define it in your logging configuration file. Here is an example configuration snippet: 

{ 
  "logger": { 
    "myLog": { 
      "logLevel": "INFO", 
      "filters": [ 
        "MDC_FORMAT", 
        { 
          "name": "ANON_FORMAT", 
          "hashAlgo": "SHA-512", 
          "tokensToAnon": "mdc.custId" 
        }, 
        "REPLACE_TOKENS_FORMAT", 
        "FULL_TEXT_FORMAT", 
        { 
          "name": "NAMED_FILE_WRITER", 
          "fileName": "${session.temp-dir}/test.log", 
          "appendTo": false 
        } 
      ] 
    } 
  } 
} 

Code example 

Here is a sample implementation of a custom logging filter that masks Customer ID: 

DEFINE VARIABLE oLogger AS ILogWriter NO-UNDO. 
oLogger = LoggerBuilder:GetLogger('myLog'). 
oLogger:Info("Log Message without Sensitive Info."). 
FIND FIRST Customer NO-LOCK NO-ERROR. 
IF AVAILABLE Customer THEN 
DO: 
    OpenEdge.Logging.MDC:Put("custId", STRING(Customer.CustNum)). 
    oLogger:Info("Customer found. Customer ID: $~{mdc.custId}"). 
END. 
ELSE oLogger:Error("Customer not found!"). 

Output 

After applying the filter, log messages containing sensitive data will be hashed. For example: 

[2024-12-06T13:48:48.029+02:00] myLog INFO: Log Message without Sensitive Info. 
[2024-12-06T13:48:48.035+02:00] myLog INFO: Customer found. Customer ID: $6$3RKhDX5uMJ7PFFeLeOhJ0A$89ER86Klq8W8yTUDio9Nsvz6M7vxyXIOi4QD7OM0ybnH1n/MA+3lsZtIabcdSPU4qnT7ucLvLX1isN1m2wI8NQ== 

Challenges and findings 

  • Version Dependency: the Logger framework is available from OpenEdge version 11.6.0 onward. Some advanced features, like the ability to extract JSON data from log events, are only available in OpenEdge 12.7; 
  • Error Handling: if the Logger cannot find a matching configuration in the logging.config file, it will either instantiate a void logger (which discards log events) or default to using the LOG-MANAGER system handle; 
  • Filter Chains: if one filter in the chain fails, the entire chain will break, preventing further logging. 

Evaluation  

The OpenEdge Logger Framework provides a robust and flexible logging solution that allows for detailed configuration and customized log handling. It is ideal for applications that require advanced logging, such as managing different log levels, filtering messages, and separating log concerns between development and operations. 

Both the LOG-MANAGER system handle and the OpenEdge Logger Framework offer valuable logging capabilities for Progress OpenEdge applications. The LOG-MANAGER system handle is simple and effective for basic logging needs, while the OpenEdge Logger Framework provides a more flexible, configurable approach to logging, allowing for advanced filtering, message formatting, and greater control over log behaviour. 

For most scenarios requiring detailed and customisable logging, the OpenEdge Logger Framework is the recommended choice. However, the LOG-MANAGER system handle can be sufficient for simple logging tasks or when using legacy systems. By understanding the strengths and limitations of both options, you can choose the best approach for your OpenEdge application’s logging requirements.  

Are you looking for some guidance in Progress OpenEdge development? Feel free to reach out to Baltic Amadeus.   

Let’s work together

Want to discuss potential opportunities? Pick the most suitable way to contact us.

Book a call

+370 5 2 780 400
info@ba.lt

     privacy policy