Sending logging data to a Graylog Server using the Agent Loggly library

There are limited options for sending logging messages to an external logging Server available in the standard Agent libraries. There only seems to be support for logging to a SolarWinds Loggly server (Loggly.class.nut:1.1.0). Luckily, Graylog supports a very similar logging message format to Loggly (GELF) allowing the Loggly library to be used with a few simple changes to the code.

The Loggly library builds and posts a JSON object to Loggly which is similar to the JSON Post object accepted by a GELF HTTP Listener on a Graylog Server. There are only a few differences between the two.

  1. Loggly uses a different HTTP URL to a Graylog GELF HTTP Listener.
    Loggly - https://logs-01.loggly.com/bulk/[token]/tag/[tag]/
    Graylog - http[s]://[graylog-server]:12201/gelf

  2. Loggly uses textual logging levels whereas GELF uses numeric syslog levels.

  3. Loggly uses an ISO date and time format timestamp whereas GELF uses a Unixtime timestamp. Sending the Graylog GELF Listener an empty string timestamp caused Graylog to create a timestamp for the current received date and time in Unixtime format.

  4. A Graylog GELF Listener uses some extra fields in the JSON Object.
    “version”(required), “host”(required), “facility”(optional)
    Also, GELF allows additional user defined fields which must start with an underscore.

  5. A Graylog GELF Listener uses the field “short_message” to hold the text of a logging message.

The existing Loggly library can be used with Squirrel Inheritance to create a class that can be used in the exactly the same way as the Loggly class with no changes in the calling code.

Include the Loggly library at the top of your Agent code as before.

#require "Loggly.class.nut:1.1.0"

Create a new class that extends the Loggly class.

class logGELF extends Loggly {
    static LOG_URL = "http://<graylog-server>:12201/gelf"; // See Note 1 above
    static LOG = 6;  // See Note 2 above
    static WARN = 4; // See Note 2 above
    static ERR = 3;  // See Note 2 above
    static function ISODateTime(ts = null) { return ""; } // See Note 3 above
    function _push(level, msg, argv = []) {
        local newmsg = msg;
        newmsg["version"] <- "1.1";				// See Note 4 above
        newmsg["host"] <- split(http.agenturl(), "/")[1];	// See Note 4 above
        newmsg["facility"] <- 1,				// See Note 4 above
        base._push(level, newmsg, argv);
    }
}

Create a class instance to use the new class.
The [token] is ignored using the new class and can be empty.

loggly <- logGELF("[token]", {"debug" : false});

Then use the class instance to send messages.

loggly.log( { "short_message" : "Text of message", "_myfield" : "mydata" } ); // See Notes 4 & 5

I hope this may be of interest!
Thanks, Richard