Name

global.GSLog

Description

Authors James Grinter, Chris Henson Make logging and debugging from Script easier by implementing levels of log output, selectable by per-caller identified sys_properties values. This implements both Log4j style logging and BSD Syslog style logging. As default, the logger will use BSD style logging. PLEASE CHOOSE ONE AND STICK TO IT (within a class anyhow) This can only be used server side. Log4j Style Logging Log4j logging levels are available, Trace, Debug, Info, Warn, Error and Fatal. Usage var this. _log = new GSLog( logging level property to lookup , class, method, script name logged as the caller ); _log.setLog4J(); //Tells the logging class you want to use Log4J style logging. To set the log level _log.setLevel(GSLog.TRACE); If you re logging at trace you re probably logging too much _log.setLevel(GSLog.DEBUG); _log.setLevel(GSLog.INFO); The default _log.setLevel(GSLog.WARN); _log.setLevel(GSLog.ERROR); _log.setLevel(GSLog.FATAL); If you use any of the BSD log levels not part of Log4J they will be set to the appropriate Log4J level. To log a message _log.trace( Message ); _log.debug( Message ); _log.info( Message ); _log.warn( Mesage ); _log.error( Mesasge ); _log.fatal( Message ); For some improvement in performance you can use the atLevel method to prevent string manipulations/concatenations in the logging method call if (_log.atLevel(GSLog.ERROR)) { _log.error( Message +x + +y+ + z); } Additional methods _log.getLevel(); // Returns the current logging level _log.debugOn(); //Sets the log level to debug _log.disableDatabaseLogs(); //Switches output to only use gs.print and not gs.log BSD Syslog Style Logging Logs can be at the level of Debug, Info, Notice, Warning, Err, Crit (after BSD syslog.h and followers). The default logging level would normally be Notice, so levels should be chosen accordingly. - caller (optional - a string), indicates who the caller is, and will be logged with every message. - message is written to the log if the current level is the same, or lower. (i.e. a level of notice will lead to emerg, alert, crit, err, warning, and notice level messages being logged) Status of Interface Evolving, subject to change. // Usage // use the level set in named property, and optionally set caller (can use this.type if calling from a Script Include Class) // Default threshold, if unspecified by the named property, is notice . var lu = new GSLog(property, caller); // log messages, at specific levels lu.logDebug(message); lu.logInfo(message); lu.logNotice(message); lu.logWarning(message); lu.logErr(message); // or lu.logError(message); lu.logCrit(message); lu.logAlert(message); lu.logEmerg(message); // log a message at loglevel // logLevel (a string) can be one of emerg , alert , crit , err , warning , notice , info , debug (after BSD syslog.h, and many followers) lu.log(loglevel, message); // change log threshold level lu.setLevel(loglevel); // get current log level var loglevel = lu.getLevel(); if (lu.debugOn()) // do more extensive debugging operations ...

Script

var GSLog = Class.create();

GSLog.prototype = {

  /* GSLog(traceProperty,caller): Instanciates a logging instance
   *
   * traceProperty: The name of the property containing the logging level for the targeted script/object
   * caller: The name of the script, object etc. calling the logger
   *
   * To use Log4J style logging:
   *      [this]._log = (new GSLog(traceProperty,caller))).setLog4J();
   */
  initialize : function(traceProperty,caller) {
      this.whoami = '';
      if (caller !== null)
          this.whoami = caller;
       
      this._logLevel = (typeof gs.logWarning == 'function');
      this._devel = true; // Look up the dev instance property?

      // support properties
      if (traceProperty)
          this.setLevel(gs.getProperty(traceProperty, ''));
      else
          this.setLevel(this._getCallerThreshold(caller));

      // Want to use log4j style logging?
      this._log4j = false;
      
      //Default logging to gs.log and not gs.print
      this._printLog = false;
  	
  	//Option to prefix each log message with a milliseconds value
  	this._timestampPrefix = false;

      // gs.print('GSLog.initialize: [' + this.whoami + '] level=' + this.logLevel + ' [' + this._levelOrder[this.logLevel] + ']');
  },

  // System Log has Debug, Error, Information, Warning
   
  logDebug: function(msg) {
       this.log('debug', msg);
  },

  logInfo: function(msg) {
       this.log('info', msg);
  },

  logNotice: function(msg) {
       this.log('notice', msg);
  },

  logWarning: function(msg) {
       this.log('warning', msg);
  },

  logErr: function(msg) {
       this.log('err', msg);
  },

  logError: function(msg) {
       this.log('err', msg);
  },
   
  logCrit: function(msg) {
       this.log('crit', msg);
  },

  logAlert: function(msg) {
       this.log('alert', msg);
  },

  logEmerg: function(msg) {
       this.log('emerg', msg);
  },

  // Log4j style logging
  trace: function(msg) {
      this.log('trace', msg);
  }, // If you're logging trace, you're probably logging too much.

  debug: function(msg) {
       this.log('debug', msg);
  },

  info: function(msg){
      this.log('info', msg);
  },

  warn: function(msg){
      this.log('warning', msg);
  },

  error: function(msg){
      this.log('err', msg);
  },

  fatal: function(msg){
      this.log('fatal', msg);
  },

  /* log(level,msg): Log a message at the specified level
   *
   * level: The level at which to log
   * msg: The message
   */
  log: function(level, msg) {
      // (always log a message at an invalid log level)
      if (typeof this._levelOrder[level] !== undefined && this._levelOrder[level] > this._levelOrder[this.logLevel] )
           return;

      var whomsg='';
      var scriptPrefix='*** Script';
      if (!this._logLevel && this._devel)
          scriptPrefix = '*** Script [' + this._logPrefix[level] + ']';
      else if (this.whoami) {
          whomsg = '[' + this.whoami + '] ';
          scriptPrefix = '*** Script [' + this.whoami + ']';
      }
       
      // override 'Script: ' prefix in log, and log at the given level if the right function exists 
      if (this._printLog)
  		//Removal of '*** Script' as gs.print prefixes this on.
      	gs.print(scriptPrefix.replace('*** Script','') + ': [' + this._logPrefix[level] + '] ' + msg);
      else {
      	var logFunction = gs.log;
      	switch (level) {
          	case 'debug': 
          		msg = '[' + this._logPrefix[level] + '] ' + msg;
          		break;
          	case 'warning':
          		if (typeof gs.logWarning == 'function')
          			logFunction = gs.logWarning;
          		break;
          	case 'err':
          	case 'error':
          		if (typeof gs.logError == 'function')
          			logFunction = gs.logError;
                  break;
              // case 'info':
          	default:
          		if (typeof gs.log == 'function')
          			logFunction = gs.log;
      	}
  		
  		if (this._timestampPrefix) {
  			var gdt = new GlideDateTime();
  			var gdtMs = gdt.getNumericValue().toString();
  			msg = gdt.getDisplayValueInternal() + "." + gdtMs.substr(gdtMs.length - 3) + " " + msg;
  		}

      	logFunction(msg, scriptPrefix);
      }
  },

  setLevel: function(level) {

      if (level.toString() == 'true')
           level = 'debug';    // compatibility with true|false logging properties
      else if (!level || level.toString() == 'false')
           level = 'notice'; // default
      else if (!this._levelOrder[level]) {
           level = 'notice'; // invalid, so set to default
      }

      /* If you want to use log4j style logging we have to cut down some of the error states.
       * Everything higher than an error -> FATAL, NOTICE -> INFO
       * We also have to disallow FATAL and TRACE for BSD style logging.  FATAL -> EMERG, TRACE->DEBUG
       */
      if (this._log4j) { //Only allow Log4J log levels
          switch (level) {
              case GSLog.EMERG:
              case GSLog.ALERT:
              case GSLog.CRIT:
                  level=GSLog.FATAL;
                  break;
              case GSLog.NOTICE:
                  level = GSLog.INFO;
                  break;
              default:
                  break;
          }
      } else {  //Only allow BSD log levels
          switch (level) {
              case GSLog.FATAL:
                  level=GSLog.EMERG;
                  break;
              case GSLog.TRACE:
                  level=GSLog.DEBUG;
                  break;
              default:
                  break;
          }
      }
      // gs.print('GSLog.setLevel: ' + level);
      this.logLevel = level; 
  },

  /* getLevel(): Returns the current logging level */
  getLevel: function(level) {
      return this.logLevel;
  },

  /* debugOn(): sets the log level to GSLog.DEBUG */
  debugOn: function() {
      return (this.logLevel == 'debug');
  },

  /* atLevel(logLevel) : Returns true if the logging level of the logger is the same as or above minLogLevel
   *
   * minLogLevel: The minimum logging level to compare against.
   */
  atLevel: function(minLogLevel) {
      if (!this._levelOrder[minLogLevel]) {
          return false;
      }

      if (this._levelOrder[minLogLevel]<=this._levelOrder[this.logLevel]) {
          return true;
      }
      return false;
  },

  /* setLog4J(): Switches the logging class into Log4J mode */
  setLog4J: function() {
      this._log4J = true;
      this.setLevel(this.logLevel); //Checking that the log levels are OK for Log4J style logging
      return this; // allows type to be set at instanciation without a sepperate parameter in the constructor.  Easier to understand.
  },
  
  /* disableDatabaseLogs(): Switches the output of the GSLog to use gs.print instead of gs.log */
  disableDatabaseLogs: function() {
      this._printLog = true;
      return this; // allows type to be set at instanciation without a separate parameter in the constructor.  Easier to understand.
  },
  
  includeTimestamp: function() {
  	this._timestampPrefix = true;
  },

  ///

  // logging levels
  _levelOrder: {
      fatal:   0,
      emerg:   1,
      alert:   2,
      crit:    3,
      err:     4,
      warning: 5,
      notice:  6,
      info:    7,
      debug:   8,
      trace:   9
  },
   
  // logging prefixes
   _logPrefix: {
       fatal:   'FATAL',
       emerg:   'EMERG',
       alert:   'ALERT',
       crit:    'CRIT ',
       err:     'ERROR',
       warning: 'WARN ',
       notice:  'NOTIC',
       info:    'INFO ',
       debug:   'DEBUG',
       trace:   'TRACE'
   },

  _getCallerThreshold: function(caller) {
       // TODO: consider performing a record lookup, on the caller name, to pick a log level
       return 'notice';
  },

  type: 'GSLog'

};

// BSD style log level constants
GSLog.EMERG  = "emerg";
GSLog.ALERT  = "alert";
GSLog.CRIT   = "crit";
GSLog.ERR    = "err";
GSLog.WARNING= "warning";
GSLog.NOTICE = "notice";
GSLog.INFO   = "info";
GSLog.DEBUG  = "debug";

// Additions for Log4j style logging
GSLog.FATAL = "fatal";
GSLog.TRACE = "trace";
GSLog.ERROR = GSLog.ERR;
GSLog.WARN  = GSLog.WARNING;

Sys ID

2e59987d0a0a2c3946f7118c070c03e3

Offical Documentation

Official Docs: