2 var zlib = require('zlib');
3 var layouts = require('../layouts');
4 var levels = require('../levels');
5 var dgram = require('dgram');
6 var util = require('util');
7 var debug = require('../debug')('GELF Appender');
9 var LOG_EMERG=0; // system is unusable
10 var LOG_ALERT=1; // action must be taken immediately
11 var LOG_CRIT=2; // critical conditions
12 var LOG_ERR=3; // error conditions
13 var LOG_ERROR=3; // because people WILL typo
14 var LOG_WARNING=4; // warning conditions
15 var LOG_NOTICE=5; // normal, but significant, condition
16 var LOG_INFO=6; // informational message
17 var LOG_DEBUG=7; // debug-level message
19 var levelMapping = {};
20 levelMapping[levels.ALL] = LOG_DEBUG;
21 levelMapping[levels.TRACE] = LOG_DEBUG;
22 levelMapping[levels.DEBUG] = LOG_DEBUG;
23 levelMapping[levels.INFO] = LOG_INFO;
24 levelMapping[levels.WARN] = LOG_WARNING;
25 levelMapping[levels.ERROR] = LOG_ERR;
26 levelMapping[levels.FATAL] = LOG_CRIT;
31 * GELF appender that supports sending UDP packets to a GELF compatible server such as Graylog
33 * @param layout a function that takes a logevent and returns a string (defaults to none).
34 * @param host - host to which to send logs (default:localhost)
35 * @param port - port at which to send logs to (default:12201)
36 * @param hostname - hostname of the current host (default:os hostname)
37 * @param facility - facility to log to (default:nodejs-server)
39 /* jshint maxstatements:21 */
40 function gelfAppender (layout, host, port, hostname, facility) {
41 var config, customFields;
42 if (typeof(host) === 'object') {
46 hostname = config.hostname;
47 facility = config.facility;
48 customFields = config.customFields;
51 host = host || 'localhost';
53 hostname = hostname || require('os').hostname();
54 layout = layout || layouts.messagePassThroughLayout;
56 var defaultCustomFields = customFields || {};
59 defaultCustomFields._facility = facility;
62 client = dgram.createSocket("udp4");
64 process.on('exit', function() {
65 if (client) client.close();
69 * Add custom fields (start with underscore )
70 * - if the first object passed to the logger contains 'GELF' field,
71 * copy the underscore fields to the message
75 function addCustomFields(loggingEvent, msg){
77 /* append defaultCustomFields firsts */
78 Object.keys(defaultCustomFields).forEach(function(key) {
79 // skip _id field for graylog2, skip keys not starts with UNDERSCORE
80 if (key.match(/^_/) && key !== "_id") {
81 msg[key] = defaultCustomFields[key];
85 /* append custom fields per message */
86 var data = loggingEvent.data;
87 if (!Array.isArray(data) || data.length === 0) return;
88 var firstData = data[0];
90 if (!firstData.GELF) return; // identify with GELF field defined
91 // Remove the GELF key, some gelf supported logging systems drop the message with it
92 delete firstData.GELF;
93 Object.keys(firstData).forEach(function(key) {
94 // skip _id field for graylog2, skip keys not starts with UNDERSCORE
95 if (key.match(/^_/) || key !== "_id") {
96 msg[key] = firstData[key];
100 /* the custom field object should be removed, so it will not be looged by the later appenders */
101 loggingEvent.data.shift();
104 function preparePacket(loggingEvent) {
106 addCustomFields(loggingEvent, msg);
107 msg.short_message = layout(loggingEvent);
110 msg.timestamp = msg.timestamp || new Date().getTime() / 1000; // log should use millisecond
112 msg.level = levelMapping[loggingEvent.level || levels.DEBUG];
116 function sendPacket(packet) {
117 client.send(packet, 0, packet.length, port, host, function(err) {
118 if (err) { console.error(err); }
122 return function(loggingEvent) {
123 var message = preparePacket(loggingEvent);
124 zlib.gzip(new Buffer(JSON.stringify(message)), function(err, packet) {
126 console.error(err.stack);
128 if (packet.length > 8192) {
129 debug("Message packet length (" + packet.length + ") is larger than 8k. Not sending");
138 function configure(config) {
141 layout = layouts.layout(config.layout.type, config.layout);
143 return gelfAppender(layout, config);
146 function shutdown(cb) {
153 exports.appender = gelfAppender;
154 exports.configure = configure;
155 exports.shutdown = shutdown;