HydraExpress User Guide : PART II The HydraExpress Agent : Chapter 6 Logging : The Agent Logger
The Agent Logger
The Agent start-up instantiates a global logger. The Agent uses this logger to record significant events related to general Agent processes and service execution. You have access to this logger in custom HydraExpress server-side code. You can also create your own loggers if you want to log information to locations other than the default log output file.
You can log information from any custom service that you write. In many cases, logging is simply added to an existing service to log specific data, but you might also create a separate service just to log some information.
Agent Logging Fundamentals
The default Agent logger is defined in the file <installdir>\conf\loggers.xml. Let’s examine this file:
 
<loggers xmlns="http://www.roguewave.com/rwsf/loggers">
<!-- To stdout --> 1
<logger name="stdout.info" class="rwsf_core.createLogLevelFilter">
<property name="logger" value="stdout"/>
<property name="filter" value="info"/>
</logger>
 
<!-- To the file agent.log --> 2
<!--logger name="rwsf.agent.logfile"
class="rwsf_core.createRotatingFileLogger">
<property name="filename" value="${RWSF_HOME}/logs/agent.log"/>
<property name="formatter" value="rwsf_core.createLogTimeFormatter"/>
<property name="mode" value="append"/>
<property name="measurement" value="mb"/>
<property name="measuresize" value="1"/>
<property name="cleanup" value="y"/>
<property name="logfilenum" value="10"/>
<property name="logdir" value="${RWSF_HOME}/logs"/>
</logger-->
 
<logger name="rwsf.agent.logfile" class="rwsf_core.createFileLogger"> 3
<property name="filename" value="${RWSF_HOME}/logs/agent.log"/>
<property name="formatter" value="rwsf_core.createLogTimeFormatter"/>
<property name="mode" value="overwrite"/>
</logger>
 
<!-- Filter the previously created file logger. --> 4
<logger name="rwsf.agent.logfile.verbose"
class="rwsf_core.createLogLevelFilter">
<property name="logger" value="rwsf.agent.logfile"/>
<property name="filter" value="verbose"/>
</logger>
<!-- Create logger that writes to two locations --> 5
<logger name="rwsf.agent.log" class="rwsf_core.createLogSplitter"
default="true">
<property name="logger1" value="stdout.info"/>
<property name="logger2" value="rwsf.agent.logfile.verbose"/>
</logger>
</loggers>
//1 Creates a logger that writes to stdout at the level INFO or above (more critical). See below for more information on levels. Both the logger and the level filter can be created in a single entry for stdout and stderr.
//2 Creates a rotating log file that allows you to set files size and number limitations, designate when log files should be archived and timestamped, and perform cleanup when old timestamped files should be removed. This section is currently commented out so that you can use the default log file writing functionality. If you wish to keep old log files, you can do so but also limit the size of the log files to keep by setting the measurement, measuresize, cleanup, logfilenum, and logdir values. To use this functionality, remove the comment tags from this section and comment out the default logger functionality just below it. The mode is append, which maintains log entries across Agent restarts.
//3 To write to a file, you must first create a file logger, then define the filter in a subsequent entry. This logger writes to installdir\logs\agent.log.
The formatter appends a timestamp to the entry. Currently, rwsf_core.createLogTimeFormatter is the only valid value for the formatter property, although you can create a custom formatter by deriving from the rwsf::LogFormatter class.
The mode creates a new, empty log every time the Agent is restarted. The alternative mode is append, which maintains log entries across Agent restarts.
//4 Creates a filter for the file logger just defined that writes at the VERBOSE level or above.
//5 Creates a logger that passes log messages to the two previously defined loggers. This is the default logger for the Agent.
The defined log levels are:
NONE
No logging
FATAL
Fatal messages only
ERROR
Error and Fatal
WARN
Warn, Error, and Fatal
INFO
Info, Warn, Error, and Fatal
VERBOSE [default]
Verbose, Info, Warn, Error, and Fatal
DEBUG
Debug, Verbose, Info, Warn, Error, and Fatal
The default Agent logger is set to VERBOSE.
Using the Default Logger in a Service
From within a HydraExpress service, you can access the default Agent logger from the rwsf::LogManager singleton. For example, this code gets the default Agent logger and logs a message:
 
#include <rwsf/core/LogManager.h>
#include <rwsf/core/Logger.h>
 
rwsf::Logger logger = rwsf::LogManager.getLogger();
logger.info("My log message.");
NOTE >> The Agent logger cannot be used by the client or standalone services. See Chapter 12, “Web Service Logging,” in the HydraExpress Web Service Development Guide.
Creating and Using Custom Loggers
There are two approaches to using a custom logger:
Configure a custom logger in the main <installdir>\conf\loggers.xml file and make it the default, or add it to the splitter that defines the default. In this approach, all logged messages, from the Agent and from your code, will be written to the same places.
Configure a custom logger in the main <installdir>\conf\loggers.xml file and acquire it by name to log your messages to a non-default log file. In this case, your log messages will be separate from those coming out of the Agent.
Defining Your Logger
The first step is to define your logger in <installdir>\conf\loggers.xml. Here is an example:
 
<!-- Define a file logger --> 1
<logger name="mylog" class="rwsf_core.createFileLogger">
<property name="filename" value="c:/logs/mylog.log"/>
<property name="formatter"
value="rwsf_core.createLogTimeFormatter"/>
<property name="mode" value="overwrite"/>
</logger>
 
<!-- Filter your file logger. --> 2
<logger name="mylog.info" class="rwsf_core.createLogLevelFilter">
<property name="logger" value="mylog"/>
<property name="filter" value="info"/>
</logger>
//1 Defines a logger named mylog that writes to the file c:\logs\mylog.log.
//2 Defines essentially a new logger, based on the file logger just defined, which writes log messages at the level INFO and above. You could define yet another logger, say mylog.error, which wrote messages only at the ERROR or FATAL levels.
Using Your Logger
You can either make your logger an Agent default logger, or a separate logger for logging just your messages.
Making Your Logger a Default Logger
The easiest way to do this is by adding your logger to the splitter definition in loggers.xml that defines the multiple outputs for the Agent default logger. A splitter definition can only name two loggers in its properties, so you must either replace one of the existing properties, or create a secondary splitter.
Here is how you would make your logger the alternative to writing log output to <installdir>\logs\agent.log:
 
<logger name="rwsf.agent.log" class="rwsf_core.createLogSplitter"
default="true">
<property name="logger1" value="stdout.info"/>
<property name="logger2" value="mylog.info"/>
</logger>
If you still want Agent output written to agent.log, but want it also to go to your log file, you must create a secondary splitter that is referenced from the main one:
 
<logger name="rwsf.agent.log" class="rwsf_core.createLogSplitter"
default="true">
<property name="logger1" value="stdout.info"/>
<property name="logger2" value="rwsf.agent.log2"/>
</logger>
 
<logger name="rwsf.agent.log2" class="rwsf_core.createLogSplitter"
default="true">
<property name="logger1" value="rwsf.agent.logfile.verbose"/>
<property name="logger2" value="mylog.info"/>
</logger>
With these definitions in place, you would now write your messages to the default Agent logger exactly as described in “Using the Default Logger in a Service.”.
Separating Your Log Messages from the Agent Messages
To log your messages separately from Agent messages, you need to define your logger as described in “Defining Your Logger”, but you do not have to add anything else to loggers.xml.
To use a custom logger named mylog.info in a custom C++ service, do the following:
 
#include <rwsf/core/LogManager>
#include <rwsf/core/Logger>
 
Logger logger = rwsf::LogManager::getLogger("mylog.info");
logger.info("My log message");
All messages logged with logger go to the output file defined for mylog.info. These messages do not go to the outputs defined for Agent messages, and Agent messages do not go to the output file defined for your logger.
Creating a Rotating Log File
A rotating log is one that allows you to set a file size limitation, limit the number of timestamped files, and perform cleanup on old timestamped files as specified. It maintains log entries across Agent restarts. You can designate the maximum size of files to maintain, the number of old timestamped files to keep in a directory, and whether or not to cleanup old timestamped entries.
The properties and their available values are:
mode
append or overwrite
measurement
bit, byte, kb, mb, gb
measuresize
Any number corresponding to the measurement type
cleanup
y or n
logfilenum
The number of timestamped log files to keep in a directory.
logdir
The name of the directory used to maintain log files.
To use the rotating log functionality, remove the comment tags from this section of the loggers.xml file and set the property values as desired.
 
<logger name="rwsf.agent.logfile"
class="rwsf_core.createRotatingFileLogger">
<property name="filename" value="${RWSF_HOME}/logs/agent.log"/>
<property name="formatter" value="rwsf_core.createLogTimeFormatter"/>
<property name="mode" value="append"/>
<property name="measurement" value="mb"/>
<property name="measuresize" value="1"/>
<property name="cleanup" value="y"/>
<property name="logfilenum" value="10"/>
<property name="logdir" value="${RWSF_HOME}/logs"/>
</logger>
For example, these settings will produce a maximum of 10 log files in the ${RWSF_HOME}/logs/ directory of up to 1 mb each, for a total of potentially 10 mb of log information at any one time. The value of cleanup is set to y, so that once the number of files or the file size exceeds the specified limit, old timestamped log files will be removed.
NOTE >> WARNING: If cleanup is set to n and mode is set to append, log files will continue to accumulate and user action is required to monitor their size and determine if cleanup is needed.