Logging

=Overview=

Logging in Prolog currently supports logging to console, file, event log, database table, PDC notification log (to be done). Logging is thread safe and even supported for several processes that are writing to the same log. Application can also simultaneously log to several logs including logging to several files and/or database tables. Logging performance does not depend on log type. It is very fast operation and done asynchronously meaning that logging message placed into the message queue, which is processed in background thread.

=Log configuration=

Log configuration file (has .XML format) defines where applications logs the information. Here is the log configuration file example:

Log configuration file may contain one or more named configurations:



...



Each configuration contains one or more appenders. Appender defines the log target and has the following parameters: LogLevel, Type, Target, PatternLayout, Filter, ConnectionString, ColumnInfo

 can be one of the following:
 * all
 * debug
 * info
 * warn
 * error
 * fatal
 * off

 can be one of the following:
 * console				logging to console
 * event				logging to the event log
 * file or fileAsync			logging to file synchronously or asynchronously
 * dbTable or dbTableAsync	logging errors to the internal database synchronously or           asynchronously
 * odbc or odbcAsync		logging to the database synchronously or asynchronously
 * service				logging to the PDC Notification log

 defines where to log for every log  and has the following values:
 *  if logging to the event log. Event source is usually application name
 * if logging to a file (environment variable allowed, ex: %TEMP%\my.log).
 * if logging to the ODBC db.

The  parameter may be omitted for everything else.

 parameter defines message-formatting rules. It can contain the following keys:
 * %lineno		Line number of logged message (starts from zero)
 * %userid		user ID (unknown if not logged in)
 * %username	user name (unknown if not logged in)
 * %proc		Process ID
 * %thread	Thread ID
 * %time		Time stamp
 * %datetime	Date/time stamp
 * %msg		Message itself
 * %msglevel	Message level
 * %newline	New line
 * %callerClassName	Caller class name
 * %callerPredicateName	Caller predicate name
 * %callerCursor		Caller module name with line/position values

For example: %userid(%username) \[%callerClassName/%callerPredicateName/%callerCursor\]%newline %proc:%thread time=%time dt=%datetime %msg(%msglevel) Logged message (2 lines): 145(Test User) \[0x600260 "serviceLog"/anonymous$o0$1$setproc_name/2np$serviceLog/sourceCursor("tools\\dashboard\\common\\Service.pro", 14, 17)\]

18244:4660 time=16:35:51.935 dt=2015/08/06 - 16:35:51.935 Call: workspace_GetDefaultDirContent(\{\})(debug)

 defines what messages will be filtered out (excluded) from the log. It can contain zero or more class names and/or zero or more method names separated by semicolon: class: ;method: 

For example: if filter is defined as following class:entityModel;method:getList all logging for class entityModel and method getList (no matter from which class) will be skipped.

 defines connection string for ODBC logging.

 defines set of columns where to log some information. The Name attribute defines column name, the Attribute defines what to log. Attributes can have the same values described in  section, except for skipped percentage sign (%) in the beginning.

Notes:

 * Log configuration file can have more than one appender that logs to a file or database table. Of course, in this case file names/database table names should be different. For example, critical errors can be logged to separate file and/or database table.

=Activating pfc\log from command line=

To use log package it is enough to specify one of the command lines parameters:

-LogConfig  <Configuration Name> For example: -LogConfig LogConfig.xml ConfigName1

=Using pfc\log programmatically=

==Loading log configuration file ==

Make the following calls: logConfig::loadConfig(ConfigFileName, ConfigName).

Where: ConfigFileName: log configuration file; ConfigName: configuration name define in log configuration;

If it is necessary to pass connection string (for db/odbc appenders) it is enough to enumerate activated appenders by name and set the connection string (in this example connection string is set for pfc\log\dbTable appender):

LogAppenders = log::getAcivatedAppenders(@"pfc\log\dbTableAppender"), foreach LogAppender in LogAppenders do   LogAppender:connectionString := db_connectionString end foreach

== Logging messages==

=== Use log::write(level Level, ...) and/or log::writef(level Level, string Format \[formatString\], ...) predicates to log messages.

For example: Log message "Start" with log level "all": log::write(log::all, "Start").

Log fatal error using formatted log: log::writef(log::fatal, "SQL ERROR during startup: %", NativeMessage).

Using log programmatically without log configuration file

Here is an example of using ODBC appender: ===

ODBC = odbcAppender::new,	<-- constructor ODBC:loglevel := log::all, 		<-- log level ODBC:columninfo := \[tuple("username", "username"), tuple("msg", "msg")\], <-- column info (write 'username' to the 'username' column, write 'msg' to the 'msg' column,       ODBC:connectionString := @"Driver=\{SQL Server\};Server=WEB1.dmz.hc\SQLEXPRESS;Database=Helpdesk_test;UID=leo;PWD=PdcPdcPdc1;app=HelpdeskDashboard",        log::activateAppender(true, ODBC), <-- activate appender        log::write(log::debug, "Example"),	<-- log

=List of ideas=

%siteURL                                              (URL of the service) %applicationName %projectName %programVersion %customerName %machineName
 * For critical errors - when we want to call PDC notification log, then we do also need:

I guess we should implement an expression is logging should be done, something like UserName in \["Leo","Alexander"\] and Time>17:00 or Level>info or Message %= "dfhj" - Where the Upper case names refer to the Variable.
 * Expressions: In log4j, there are a number of filtering facilities: http://logging.apache.org/log4j/2.x/log4j-users-guide.pdf


 * Reload log configuration from UI (App settings/utility/etc.) \[DONE\]

- analyze;
 * PDC Notification Log: \[DONE\]


 * Also I think there should be a state variable something like:

Enablelogging_if User="Leo" and Message contains "login"

Disablelogging_if User="Leo" and Message contains "logout"

This is not precise; I just thought it is needed with a mechanism to start and stop logging based on logical condition...