Filters process log events that satisfy the log level defined in the same configuration. The OpenEdge Logger framework provides a number of built-in filters. They fall into two broad categories:

  • Format filters that format the log message. You can define multiple format filters in the same logging configuration. In this case, the filters are applied to each log event sequentially, in the order in which you define them.
  • Writer filters that write the log message to a file or console. Just like format filters, you can define multiple writer filters in the same logging configuration. In this case, the log message gets written by each writer filter.

You must use at least one format filter before a writer filter. Here is a list of built-in filters for each category:

Format Filters

ABL_SUBSTITUTE_FORMAT
Use this filter if the log event's LogMessage object contains arguments whose values are retrieved from elements in an array. Specify the filter name as shown in this example. No additional properties need to be set.
"filters": [
   "ABL_SUBSTITUTE_FORMAT",
   ...
   ...
] 
ANON_FORMAT
Use this filter to make values anonymous using a hash function.
"filters": [
  {
    "name": "ANON_FORMAT",
    "hashAlgo": "MD5|SHA-1|SHA-256|SHA-512", // SHA-256 is the default
    "hashSalt": "",    // any character value; may be a token (eg {t.mtime} 
                       // to return time-based salts). Default i
    "tokensToAnon": "" // Defaults to CP.UID, CP.QUID (user-id and 
                       //qualified-uid from the current client-principal)
  }
]
For a qualified user id, the output is:
"Current user: $5$0rVLIngRtJGZFNBlVJOMHA$ZkCPPsMV5S7RTnoiNuFDwLfOKFP0ly8GJq+
 Uizi2amM="
Table 1. Where:
Value Description
5 The SHA-256 algorithm.
0rVLIngRtJGZFNBlVJOMHA The salt.
ZkCPPsMV5S7RTnoiNuFDwLfOKFP0ly8GJq+Uizi2amM= The hashed value.
Note: Hashed values cannot be reversed. If potential input values are known, the hash can be recalculated to provide the same value.
For more information on the hash function, see https://en.wikipedia.org/wiki/Crypt_(C)
ERROR_FORMAT
This filter applies only to log events produced by the Error() method. The log event that is produced includes a property named Error. This property (populated only for log events produced by Error()), is of the type Progress.Lang.Error and contains a description of the error.
Note: Using the ERROR_FORMAT filter sets the session's error-stack-trace property to true.
Specify this filter as shown in this example. No additional properties need to be set.
"filters": [
    "ERROR_FORMAT",
    ...
    ...
]
FULL_TEXT_FORMAT
This filter produces a predefined format that includes the timestamp, message group (if available), log level, the logging configuration name, and the log message. Here is a sample output:
[2018-11-02T14:20:29.021-04:00] CUSTOMER-MESSAGE-GROUP INFO: This is a test message
Specify this filter as shown in this example. No additional properties need to be set.
"filters": [
    "FULL_TEXT_FORMAT",
    ...
    ...
]
LOG_MANAGER_FORMAT
Use this filter if you want the same log message format that is used in the Log-Manager. In this format, the log level is prefixed in the log message. Specify the filter name as shown in this example. No additional properties need to be set.
"filters": [
    "LOG_MANAGER_FORMAT",
    ...
    ...
]
STACK_WRITER_FORMAT
This filter applies to log events produced by the Debug() method. The log event that is produced includes a property named CallStack. This property (populated only for log events produced by Debug()) contains log stack information about the classes and methods that led to the log event. Specify this filter as shown in this example. No additional properties need to be set.
"filters": [
    "STACK_WRITER_FORMAT",
    ...
    ...
]
Note: In addition to log events produced by the Debug() method, the STACK_WRITER_FORMAT gets used if the debug-alert flag on the session handle is set to true (SESSION:DEBUG-ALERT = TRUE).
TOKEN_FORMAT
Use this filter if you want to use tokens in the log message. A token is like a placeholder or a variable name, whose value is 'resolved' at runtime. For example, if you use the token ${t.now}, the TOKEN_FORMAT filter resolves the token to the current timestamp (the time at which the filter was applied). You cannot add tokens while defining log messages in the ABL class. You can, however, define a token in the TOKEN_FORMAT filter as shown in this example.
"filters": [
    {
       "name": "TOKEN_FORMAT",
       "format": "${t.now} ${msg.level} ${msg}"
    }
]
The msg token gets its value from the log message defined in the ABL class. The output looks something like this:
2018-11-05T14:00:07.054-05:00 INFO Customer found.
If the token cannot be resolved, the Logger framework prints the token as is. This also means that you can specify any custom strings, such as XML tags, in the token format. Here is an example:
"filters": [
    {
       "name": "TOKEN_FORMAT",
       "format": "<LogEntry>${t.now} ${msg.notARealProperty}</LogEntry>"
    }
]
The output, based on this format, would look like this:
<LogEntry>2018-11-05T14:00:07.054-05:00 ${msg.notARealProperty}</LogEntry>
For information about ABL application logging, see ABL Application Logging. For a complete list of all tokens, see Logging tokens section.

Writer filters

DEFAULT_WRITER
Use this filter to use the default logging system. For PAS for OpenEdge, this resolves to the LOG_MANAGER_WRITER. For other client types, it resolves to VOID_WRITER.
JSON_LOG_WRITER
Use this filter to write all log messages in a structured JSON format.
"filters": [
    "JSON_LOG_WRITER"
]
In the file-based configuration, the JSON data must be extracted from the logger, using ABL code.
define variable cnt as integer no-unfo.
define variable loop as integer no-unfo.
define variable logger as ILogWriter no-undo.
define variable logData as JsonArray no-undo.
        
   cnt = extent(logger:LogFilters).
   do loop = 1 to cnt
   while not valid-object(logData):
       if type-of(logger:LogFilters[loop], JsonLogWriter) then
           assign logData = return cast(logger:LogFilters[loop], JsonLogWriter):LogData.
   end.
The JSON structure consists of an array of JSON objects; these objects are in the order in which the messages are logged. For example:
[
      {
        "loggedAt": "<iso-date that the message was logged at>",
        "level": "<logging level: FATAL|ERROR|WARN|INFO|DEBUG|TRACE>",
        "msg": "<the message after passing through the configured filters 
                (ie formatted/resolved/enhanced)>",
        "hasError": true|false,
        "error": {
          "_errors": [
            {
              "_errorMsg": "<error message text, per GetMessage()>",
              "_errorNum": <error message text, per GetMessageNum()>
            }
          ],
          "_sev": 0
        },
        "loggerName": "<the name of the logger>",
        "msgStack": [
          "<array of the message call stack>"
        ],
        "baseText": "<message text before token resolution>",
        "tokens": {
            "<token-name>": null|"<token-value>"
        }
      },
      // additional messages
    ]
Note: This filter is intended for testing and troubleshooting.
LOG_MANAGER_WRITER
Use this filter to write log messages to the log files used by the ABL Log-Manager (typically the PAS for OpenEdge agent log). Specify this filter as shown in this example.
"filters": [
    "FULL_TEXT_FORMAT",
    "LOG_MANAGER_WRITER"
]
NAMED_FILE_WRITER
Use this filter to specify the name of a log file to write the log message to. Specify this filter as shown in this example.
"filters": [
    "FULL_TEXT_FORMAT",
    {
       "name": "NAMED_FILE_WRITER",
       "fileName": "CustomerLog.log",
       "appendTo": true
    }
]
You use the fileName property to set the log file name. By default, if no path is specified, as in this example, the log file gets created in the PAS for OpenEdge instance's work directory. You can also use tokens in the filename to set up rotating log files. Here is an example:
"filters": [
    "FULL_TEXT_FORMAT",
    {
       "name": "NAMED_FILE_WRITER",
       "fileName": "${session.temp-dir}/${t.today}-CustomerLog.log",
       "appendTo": true
    }
]
The ${session.temp-dir} token is substituted by the pathname of the temp directory used by PAS for OpenEdge at runtime. The ${t.today} token is replaced by the date.
VOID_WRITER
Use this filter if you want to turn off writing log messages. The VOID_WRITER filter acts as a sink for the LogEvent object.