LogBox : Enterprise Logging & Messaging
5.x
5.x
  • Introduction
  • Intro
    • Introduction
      • What's New With 5.4.0
      • What's New With 5.3.0
      • What's New With 5.0.0
      • What's New With 2.1.0
      • What's New With 2.0.0
      • About This Book
      • Author
  • Getting Started
    • Features at a Glance
    • Installation
      • LogBox Refcard
    • Need For Logging
    • How Does LogBox Work?
      • LogBox
      • Appender
      • Logger
        • Logger Category Inheritance
        • Security Levels
        • Dynamic Appenders
      • Layout
  • Configuration
    • Configuring LogBox
      • LogBox DSL
      • Adding Appenders
      • Adding Categories to Specific Loggin Levels
      • Adding Categories Granularly
      • Configuring The Root Logger
  • Usage
    • Using LogBox
    • Using a Logger Object
      • Can Methods For Performance
      • $toString() and ExtraInfo Argument
    • Appender Properties
      • CFAppender
      • ConsoleAppender
      • DBAppender
      • EmailAppender
      • FileAppender
      • RollingFileAppender
      • ScopeAppender
      • SocketAppender
      • TraceAppender
    • LogBox in a ColdBox Application
      • Configuration Within ColdBox
      • Benefits of using LogBox in a ColdBox application
      • Where is LogBox stored in a ColdBox app?
      • LogBox from the ColdBox Proxy
      • The LogBox Injection DSL
  • Extending LogBox
    • Creating Custom Appenders
      • Helper Methods
      • Instance Members
      • Dealing With Custom Layouts
      • Registering Appenders at Runtime
    • Creating a Custom Layout
      • Instance Members
Powered by GitBook
On this page
  • init()
  • logMessage()
  • onRegistration() & onUnregistration()

Was this helpful?

Edit on Git
Export as PDF
  1. Extending LogBox

Creating Custom Appenders

In order to create your own appenders, you will have to create a cfc that extends logbox.system.logging.AbstractAppender and implement the following methods:

Method

Description

init()

Your constructor. Make sure to call super.init( argumentCollection=arguments );

logMessage()

The method that is called when a message is received.

onRegistration()

An interceptor that fires when the appender gets created and initialized. It can be used for preparing the appender for operation.

onUnRegistration()

An interceptor that fires when the appender is removed from a logger.

init()

The signature of the init method is the following:

<---  Init --->
<cffunction name="init" access="public" returntype="AbstractAppender" hint="Constructor called by a Concrete Appender" output="false" >
    <---  ************************************************************* --->
    <cfargument name="name"         type="string"  required="true" hint="The unique name for this appender."/>
    <cfargument name="properties"     type="struct"  required="false" default="#structnew()#" hint="A map of configuration properties for the appender"/>
    <cfargument name="layout"         type="string"  required="false" default="" hint="The layout class to use in this appender for custom message rendering."/>
    <cfargument name="levelMin"      type="numeric" required="false" default="0" hint="The default log level for this appender, by default it is 0. Optional. ex: LogBox.logLevels.WARN"/>
    <cfargument name="levelMax"      type="numeric" required="false" default="4" hint="The default log level for this appender, by default it is 5. Optional. ex: LogBox.logLevels.WARN"/>
    <---  ************************************************************* --->

</cffunction>

As you can see each appender receives a name, a structure of properties, an optional layout class, and an optional levelMin and levelMax severity levels. The properties and layout are both optional, but you must call the super.init( argumentCollection = arguments ) method in order to have full ok operation on the appender. You can then do your own constructor as you see fit. Here is an example:

<---  Constructor --->
<cffunction name="init" access="public" returntype="FileAppender" hint="Constructor" output="false">
    <---************************************************************** --->
    <cfargument name="name"         type="string"  required="true" hint="The unique name for this appender."/>
    <cfargument name="properties"     type="struct"  required="false" default="#structnew()#" hint="A map of configuration properties for the appender"/>
    <cfargument name="layout"     type="string"  required="true"  default="" hint="The layout class to use in this appender for custom message rendering."/>
    <cfargument name="levelMin"      type="numeric" required="false" default="0" hint="The default log level for this appender, by default it is 0. Optional. ex: LogBox.logLevels.WARN"/>
    <cfargument name="levelMax"      type="numeric" required="false" default="4" hint="The default log level for this appender, by default it is 5. Optional. ex: LogBox.logLevels.WARN"/>
        <---************************************************************** --->
    <cfscript>
        super.init(argumentCollection=arguments);

        // Setup Properties
        if( NOT propertyExists("filepath") ){
            $throw(message="Filepath property not defined",type="FileAppender.PropertyNotFound");
        }
        if( NOT propertyExists("autoExpand") ){
            setProperty("autoExpand",true);
        }
        if( NOT propertyExists("filename") ){
            setProperty("filename",getName());
        }
        if( NOT propertyExists("fileEncoding") ){
            setProperty("fileEncoding","UTF-8");
        }

        // Setup the log file full path
        instance.logFullpath = getProperty("filePath");
        // Clean ending slash
        if( right(instance.logFullpath,1) eq "/" OR right(instance.logFullPath,1) eq "\"){
            instance.logFullPath = left(instance.logFullpath, len(instance.logFullPath)-1);
        }
        instance.logFullPath = instance.logFullpath & "/" & getProperty("filename") & ".log";

        // Do we expand the path?
        if( getProperty("autoExpand") ){
            instance.logFullPath = expandPath(instance.logFullpath);
        }

        //lock information
        instance.lockName = getname() & "logOperation";
        instance.lockTimeout = 25;

        return this;
    </cfscript>
</cffunction>

logMessage()

The signature of the logMessage method is the following:

<---  logMessage --->
<cffunction name="logMessage" access="public" output="false" returntype="void">
    <cfargument name="logEvent" type="logbox.system.logging.LogEvent" required="true" hint="The logging event to log.">
</cffunction>

As you can see it is a very simple method that receives a LogBox logging event object. This object keeps track of the following properties with its appropriate getters and setters:

  • timestamp

  • category

  • message

  • severity

  • extraInfo

You can then use this logging event object to log to whatever destination you want. Here is a snippet from our scope appender:

<---  Log Message --->
<cffunction name="logMessage" access="public" output="true" returntype="void" hint="Write an entry into the appender.">
    <---************************************************************** --->
    <cfargument name="logEvent" type="logbox.system.logging.LogEvent" required="true" hint="The logging event"/>
    <---************************************************************** --->
    <cfscript>
        var logStack = "";
        var entry = structnew();
        var limit = getProperty('limit');
        var loge = arguments.logEvent;

        // Verify storage
        ensureStorage();

        // Check Limits
        logStack = getStorage();

        if( limit GT 0 and arrayLen(logStack) GTE limit ){
            // pop one out, the oldest
            arrayDeleteAt(logStack,1);
        }

        // Log Away
        entry.id = createUUID();
        entry.logDate = loge.getTimeStamp();
        entry.appenderName = getName();
        entry.severity = severityToString(loge.getseverity());
        entry.message = loge.getMessage();
        entry.extraInfo = loge.getextraInfo();
        entry.category = loge.getCategory();

        // Save Storage
        arrayAppend(logStack, entry);
        saveStorage(logStack);
    </cfscript>
</cffunction>

onRegistration() & onUnregistration()

Finally, both the onRegistration and onUnregistration methods have to be void methods with no arguments.

<cffunction name="onRegistration" access="public" hint="Runs after the appender has been created and registered. Implemented by Concrete appender" output="false" returntype="void">
</cffunction>

<cffunction name="onUnRegistration" access="public" hint="Runs before the appender is unregistered from LogBox. Implemented by Concrete appender" output="false" returntype="void">
</cffunction>

These are great for starting or stopping your appenders if they so need to. Here is a sample from our socket appender:

<---  onRegistration --->
<cffunction name="onRegistration" output="false" access="public" returntype="void" hint="When registration occurs">
    <cfif getProperty("persistConnection")>
        <cfset openConnection()>
    </cfif>
</cffunction>

<---  onRegistration --->
<cffunction name="onUnRegistration" output="false" access="public" returntype="void" hint="When Unregistration occurs">
    <cfif getProperty("persistConnection")>
        <cfset closeConnection()>
    </cfif>
</cffunction>
PreviousThe LogBox Injection DSLNextHelper Methods

Last updated 7 years ago

Was this helpful?