├── .gitignore ├── .travis.yml ├── binding.gyp ├── test ├── mocks │ └── journal_send.js └── index.js ├── package.json ├── index.js ├── LICENSE ├── log.js ├── src └── journal_send.cc └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | .* 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | dist: xenial 3 | node_js: 4 | - "10" 5 | - "12" 6 | - "14" 7 | - "16" 8 | before_install: 9 | sudo apt update && sudo apt install build-essential pkg-config libsystemd-dev 10 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ { 3 | "target_name": "journal_send", 4 | "sources": [ "src/journal_send.cc" ], 5 | "include_dirs": [ "", 11 | "license": "MIT", 12 | "main": "index.js", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/jue89/node-systemd-journald.git" 16 | }, 17 | "directories": { 18 | "test": "test" 19 | }, 20 | "scripts": { 21 | "test": "mocha", 22 | "pretest": "jshint *.js" 23 | }, 24 | "dependencies": { 25 | "@mapbox/node-pre-gyp": "^1.0.5", 26 | "node-addon-api": "^4.0.0" 27 | }, 28 | "devDependencies": { 29 | "jshint": "^2.11.0", 30 | "mocha": "^9.0.2", 31 | "mockery": "^1.7.0" 32 | }, 33 | "os": [ 34 | "linux" 35 | ], 36 | "jshintConfig": { 37 | "esversion": 5, 38 | "node": true, 39 | "strict": true, 40 | "loopfunc": true 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var log = require( './log.js' ); 4 | 5 | 6 | // Syslog log levels 7 | var levels = [ 8 | 'emerg', 9 | 'alert', 10 | 'crit', 11 | 'err', 12 | 'warning', 13 | 'notice', 14 | 'info', 15 | 'debug' 16 | ]; 17 | 18 | // Class for journald stuff 19 | function Journald( defaultFields ) { 20 | 21 | // Keep the default fields in an instance 22 | if( typeof defaultFields != 'object' ) defaultFields = {}; 23 | this._defaultFields = defaultFields; 24 | 25 | } 26 | 27 | // Create logging methods 28 | for( var l in levels ) { ( function( prio, name ) { 29 | 30 | // The static method is available for users without the need for default fields 31 | Journald[ name ] = function( message, fields ) { 32 | log( prio, message, fields ); 33 | }; 34 | 35 | // And the class method includes the default fields 36 | Journald.prototype[ name ] = function( message, fields ) { 37 | log( prio, message, fields, this._defaultFields ); 38 | }; 39 | 40 | } )( l, levels[ l ] ); } 41 | 42 | 43 | module.exports = Journald; 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Juergen Fitschen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /log.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var journal = require( './build/Release/journal_send.node' ); 4 | 5 | var stackTraceRE = /at ([^\ ]+) \(([^:]+):([0-9]+):[0-9]+\)$/; 6 | 7 | function obj2journalFields( journalFields, obj, prefix ) { 8 | 9 | if( prefix === undefined ) prefix = ''; 10 | 11 | // Go through all fields 12 | for( var o in obj ) { 13 | var name = o.toUpperCase(); 14 | if( obj[o] instanceof Buffer ) { 15 | journalFields[ prefix + name ] = obj[o].toString('hex'); 16 | } else if( typeof obj[o] === 'object' ) { 17 | if( obj[o] === null ) { 18 | journalFields[ prefix + name ] = 'null'; 19 | } else { 20 | obj2journalFields( journalFields, obj[o], prefix + name + "_" ); 21 | } 22 | } else if( obj[o] !== undefined && ( prefix.length > 0 || name != 'PRIORITY' ) ) { 23 | journalFields[ prefix + name ] = obj[o].toString(); 24 | } 25 | } 26 | 27 | } 28 | 29 | function log( priority, message, fields, defaultFields ) { 30 | 31 | // If we haven't got a message, throw an error 32 | if( message === undefined ) { 33 | throw new Error( "Please specify a message" ); 34 | } 35 | 36 | // Make sure fields is an object 37 | if( typeof fields != 'object' ) fields = {}; 38 | if( typeof defaultFields != 'object' ) defaultFields = {}; 39 | 40 | // Object holding all data handed over to journald 41 | var journalFields = {}; 42 | 43 | // If the message is an instnce of Error, extract its message 44 | if( message instanceof Error ) { 45 | 46 | var stack = message.stack.toString(); 47 | 48 | // Store stack trace and message 49 | journalFields.STACK_TRACE = stack; 50 | message = message.message; 51 | 52 | // Try to extract callee name, line and file 53 | var tmp = stack.split('\n'); 54 | if( tmp.length >= 2 ) { 55 | 56 | // Second line knows the error source 57 | var errSource = tmp[1]; 58 | 59 | // Match regular expression and add info to iovec 60 | var re = stackTraceRE.exec( errSource ); 61 | if( re !== null ) { 62 | journalFields.CODE_FILE = re[2]; 63 | journalFields.CODE_FUNC = re[1]; 64 | journalFields.CODE_LINE = re[3]; 65 | } 66 | 67 | } 68 | 69 | } else if( typeof message != 'string' ) { 70 | 71 | message = message.toString(); 72 | 73 | } 74 | 75 | // Add default journal fields 76 | obj2journalFields( journalFields, defaultFields ); 77 | 78 | // Add journal fields - they may override the default fields 79 | obj2journalFields( journalFields, fields ); 80 | 81 | // Add message 82 | journalFields.MESSAGE = message; 83 | 84 | // Convert journal fields to iovec 85 | var iovec = []; 86 | for( var key in journalFields ) { 87 | iovec.push( key + "=" + journalFields[ key ] ); 88 | } 89 | 90 | // Send it to our beloved journald 91 | journal.send.apply( null, [ parseInt( priority ) ].concat( iovec ) ); 92 | 93 | } 94 | 95 | module.exports = log; 96 | -------------------------------------------------------------------------------- /src/journal_send.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | // Instead of the locations being this file, let the user define their own 6 | // CODE_FILE, CODE_LINE and CODE_FUNC, via stack trace (ex: npm callsite) 7 | #define SD_JOURNAL_SUPPRESS_LOCATION 1 8 | #include 9 | 10 | // Priority is a special case as it needs to be taken from the syslog.h 11 | // preprocessor definitions, which aren't available from JavaScript. 12 | #include 13 | 14 | // Macros for int to string conversion 15 | #define TO_STR_H(x) "" #x 16 | #define TO_STR(x) TO_STR_H(x) 17 | 18 | // Create an array of all Syslog priority numbers 19 | #define SYSLOG_PRIO_CNT 8 20 | const char *const syslogPrio[] = { 21 | TO_STR( LOG_EMERG ), // jsPrio: 0 22 | TO_STR( LOG_ALERT ), // jsPrio: 1 23 | TO_STR( LOG_CRIT ), // jsPrio: 2 24 | TO_STR( LOG_ERR ), // jsPrio: 3 25 | TO_STR( LOG_WARNING ), // jsPrio: 4 26 | TO_STR( LOG_NOTICE ), // jsPrio: 5 27 | TO_STR( LOG_INFO ), // jsPrio: 6 28 | TO_STR( LOG_DEBUG ) // jsPrio: 7 29 | }; 30 | 31 | #define PRIO_FIELD_NAME "PRIORITY=" 32 | #define PRIO_FIELD_NAME_LEN 9 33 | 34 | Napi::Value Send( const Napi::CallbackInfo &info ) { 35 | Napi::Env env = info.Env(); 36 | Napi::HandleScope scope(env); 37 | int argc = info.Length(); 38 | struct iovec iov[ argc ]; 39 | 40 | // Make sure nobody forgot the arguments 41 | if( argc < 2 ) { 42 | Napi::TypeError::New( env, "Not enough arguments" ).ThrowAsJavaScriptException(); 43 | return env.Null(); 44 | } 45 | 46 | Napi::Number priorityArg = info[0].As(); 47 | 48 | // Make sure first argument is a number 49 | if( priorityArg.IsEmpty() ) { 50 | Napi::TypeError::New( env, "First argument must be a number" ).ThrowAsJavaScriptException(); 51 | return env.Null(); 52 | } 53 | 54 | // Get the priority 55 | int64_t jsPrio = priorityArg.Int64Value(); 56 | if( jsPrio < 0 || jsPrio >= SYSLOG_PRIO_CNT ) { 57 | Napi::TypeError::New(env, "Unknown priority").ThrowAsJavaScriptException(); 58 | return env.Null(); 59 | } 60 | 61 | // Convert JavaScript priority to Syslog priority 62 | size_t strLen = PRIO_FIELD_NAME_LEN + strlen( syslogPrio[jsPrio] ); 63 | iov[0].iov_len = strLen; 64 | iov[0].iov_base = (char*) malloc( strLen + 1 ); 65 | snprintf( (char*) iov[0].iov_base, strLen + 1, 66 | "%s%s", PRIO_FIELD_NAME, syslogPrio[jsPrio] ); 67 | 68 | // Copy all remaining arguments to the iovec 69 | for( int i = 1; i < argc; i++ ) { 70 | Napi::String strArg = info[i].As(); 71 | // First ensure that the argument is a string 72 | if( strArg.IsEmpty() ) { 73 | Napi::TypeError::New( env, "Arguments must be strings" ).ThrowAsJavaScriptException(); 74 | return env.Null(); 75 | } 76 | 77 | // Put string into the iovec 78 | Napi::String arg = strArg; 79 | std::string charVal = arg.As(); 80 | iov[i].iov_len = charVal.length(); 81 | iov[i].iov_base = strdup( charVal.c_str() ); 82 | } 83 | 84 | // Send to journald 85 | int ret = sd_journal_sendv( iov, argc ); 86 | 87 | // Free the memory again 88 | for( int i = 0; i < argc; i++ ) { 89 | free( iov[i].iov_base ); 90 | } 91 | 92 | Napi::Number returnValue = Napi::Number::New( env, ret ); 93 | return returnValue; 94 | } 95 | 96 | static Napi::Object Init( Napi::Env env, Napi::Object exports ) { 97 | exports.Set( Napi::String::New(env, "send"), Napi::Function::New(env, Send) ); 98 | return exports; 99 | } 100 | 101 | NODE_API_MODULE( journal_send, Init ) 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-systemd-journald 2 | 3 | [![Build Status](https://travis-ci.org/jue89/node-systemd-journald.svg?branch=master)](https://travis-ci.org/jue89/node-systemd-journald) 4 | 5 | Node.js module for native bindings to the ~~dearly beloved~~ systemd-journald. 6 | 7 | ## Example 8 | 9 | This example will start an ExpressJS server. Open your browser and visit: `http://localhost:3000/{a}/{b}` 10 | 11 | The server will return the result of `a` divided by `b`. You feel subversive and may want to try `b` equals zero?! ;) 12 | 13 | ```javascript 14 | // npm install express systemd-journald 15 | const Journald = require('systemd-journald'); 16 | const app = require('express')(); 17 | 18 | // This creates a new logging instance. The stated object defines default 19 | // journal fields attached to every logging entry. syslog_identifier is the 20 | // name displayed along with the log lines. 21 | const log = new Journald({syslog_identifier: 'awesome-divide'}); 22 | 23 | app.get('/:a/:b', (req, res) => { 24 | try { 25 | 26 | // Convert numbers 27 | let a = parseInt(req.params.a); 28 | let b = parseInt(req.params.b); 29 | 30 | // Divide a by b 31 | let q = a / b; 32 | 33 | // Throw an error if the result is not a number 34 | // Funny side fact: In the first place I checked: 35 | // if( typeof q != 'number' ) ... 36 | // Well, this was not working. Infinity is recognised as 'number' and, you 37 | // might already guessed it, NaN as well! Javascript as we know and love it. 38 | if(isNaN(q) || q === Infinity ) throw new Error('No number!'); 39 | 40 | // Send the result to the client 41 | res.end(q.toString()); 42 | 43 | // Log this request with priority 7 44 | log.debug('Just answered a request', { 45 | 'dividend' : a, 46 | 'divisor' : b, 47 | 'quotient' : q, 48 | 'remote_addr': req.connection.remoteAddress 49 | }); 50 | 51 | // Are you interested in the requests of a specific IP? Try: 52 | // $ journalctl -t awesome-divide REMOTE_ADDR={IP} 53 | // As you can see, you have to enter the field names in capital letters. 54 | 55 | } catch(e) { 56 | 57 | // The user screwed up! This will write the error message and stack trace to 58 | // the journal with priority 3. Checkout your journal: 59 | // $ journalctl -t awesome-divide -p 3 -o json-pretty 60 | log.err(e); 61 | 62 | res.status(400).end(e.message); 63 | 64 | } 65 | }); 66 | 67 | app.listen(3000); 68 | ``` 69 | 70 | 71 | ## Installation 72 | 73 | ### Install build dependencies 74 | Debian-flavoured Linux distributions: 75 | 76 | ```bash 77 | sudo apt-get install build-essential \ 78 | pkg-config \ 79 | libsystemd-dev 80 | ``` 81 | 82 | RHEL 7 flavoured Linux distributions: 83 | 84 | ```bash 85 | sudo yum install gcc gcc-c++ make git \ 86 | systemd-devel 87 | ``` 88 | 89 | ### NPM Install 90 | In all cases, once the build dependencies are installed: 91 | 92 | ```bash 93 | npm install systemd-journald --save 94 | ``` 95 | 96 | 97 | ## API 98 | 99 | ```javascript 100 | const Journald = require( 'systemd-journald' ); 101 | const log = new Journald( defaultFields ); 102 | 103 | // Corresponding syslog level: 104 | log.emerg( message, fields ); // - LOG_EMERG 105 | log.alert( message, fields ); // - LOG_ALERT 106 | log.crit( message, fields ); // - LOG_CRIT 107 | log.err( message, fields ); // - LOG_ERR 108 | log.warning( message, fields ); // - LOG_WARNING 109 | log.notice( message, fields ); // - LOG_NOTICE 110 | log.info( message, fields ); // - LOG_INFO 111 | log.debug( message, fields ); // - LOG_DEBUG 112 | ``` 113 | 114 | * `message`: String or instance of Error. 115 | * `fields`: Further key-value data attached to the journal. Nested objects will be also included in the journal. Keys will be converted to upper-case. `{'obj': {'nested': 'Chuck Norris'}}` will become `OBJ_NESTED=Chuck Norris`. Quite handy for filtering the journal. 116 | * `defaultFields`: Fields attached to every entry. They may be overridden by `fields`. 117 | 118 | 119 | ## Acknowledgement 120 | 121 | Sepcial thanks to: 122 | * [ianare](https://github.com/ianare) for improving compatibility with older systemd versions. 123 | * [jez9999](https://github.com/jez9999) for making this module immune to future changes of syslog levels. 124 | * [Z3TA](https://github.com/Z3TA) is responsible for `CODE_FILE`, `CODE_FUNC` and `CODE_LINE` being settable by the `fields` parameter. 125 | * [bryanburgers](https://github.com/bryanburgers) introduced the idea of default fields. 126 | * [spion](https://github.com/spion) for introducing compatibility with NodeJS 12 while preserving compatibility down to Node 0.10. 127 | * [GaikwadPratik](https://github.com/GaikwadPratik) for porting this module from NAN to Node-API. 128 | 129 | I owe you a drink! 130 | 131 | 132 | ## Why? 133 | 134 | This module has been written after some unsuccessful attempts to get the module [journald](https://www.npmjs.com/package/journald) version 0.0.5 working under NodeJS 4.x / 5.x. Due to massive API changes of the v8 engine this module is fully broken from the point of view of recent NodeJS releases. So I rewrote it - this time with a little help of *Native Abstractions for Node.js* (nan). The nice guys from nan promised to ensure compatibility even on future API changes of v8. ~~We will see ;)~~ 135 | 136 | Update: They've kept the promise - but we've changed to the on-board solution for native modules: *Node-API*. We hope to have even less problems with keeping this module compatible to NodeJS. 137 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var assert = require( 'assert' ); 4 | var mockery = require( 'mockery' ); 5 | 6 | 7 | describe( "node-systemd-journald", function() { 8 | 9 | var journal_send; 10 | var log; 11 | 12 | before( function( done ) { 13 | 14 | // Load mocks 15 | mockery.enable( { 16 | useCleanCache: true, 17 | warnOnReplace: false, 18 | warnOnUnregistered: false 19 | } ); 20 | journal_send = require( './mocks/journal_send.js' ); 21 | mockery.registerMock( './build/Release/journal_send.node', journal_send ); 22 | 23 | // Require library under test 24 | log = require( '../index.js' ); 25 | 26 | done(); 27 | 28 | } ); 29 | 30 | after( function( done ) { 31 | 32 | // Remove all mocks 33 | mockery.disable(); 34 | 35 | done(); 36 | 37 | } ); 38 | 39 | it( "should throw an error if no message has been defined", function( done ) { 40 | 41 | try { 42 | log.debug(); 43 | } catch( e ) { 44 | done(); 45 | } 46 | 47 | } ); 48 | 49 | it( "should log an emerg", function( done ) { 50 | 51 | log.emerg( 'Test' ); 52 | 53 | try { 54 | assert.strictEqual( journal_send.getField( 'PRIORITY' ), '0' ); 55 | assert.strictEqual( journal_send.getField( 'MESSAGE' ), 'Test' ); 56 | done(); 57 | } catch( e ) { 58 | done( e ); 59 | } 60 | 61 | } ); 62 | 63 | it( "should log an alert", function( done ) { 64 | 65 | log.alert( 'Test' ); 66 | 67 | try { 68 | assert.strictEqual( journal_send.getField( 'PRIORITY' ), '1' ); 69 | assert.strictEqual( journal_send.getField( 'MESSAGE' ), 'Test' ); 70 | done(); 71 | } catch( e ) { 72 | done( e ); 73 | } 74 | 75 | } ); 76 | 77 | it( "should log a crit", function( done ) { 78 | 79 | log.crit( 'Test' ); 80 | 81 | try { 82 | assert.strictEqual( journal_send.getField( 'PRIORITY' ), '2' ); 83 | assert.strictEqual( journal_send.getField( 'MESSAGE' ), 'Test' ); 84 | done(); 85 | } catch( e ) { 86 | done( e ); 87 | } 88 | 89 | } ); 90 | 91 | it( "should log an err", function( done ) { 92 | 93 | log.err( 'Test' ); 94 | 95 | try { 96 | assert.strictEqual( journal_send.getField( 'PRIORITY' ), '3' ); 97 | assert.strictEqual( journal_send.getField( 'MESSAGE' ), 'Test' ); 98 | done(); 99 | } catch( e ) { 100 | done( e ); 101 | } 102 | 103 | } ); 104 | 105 | it( "should log a warning", function( done ) { 106 | 107 | log.warning( 'Test' ); 108 | 109 | try { 110 | assert.strictEqual( journal_send.getField( 'PRIORITY' ), '4' ); 111 | assert.strictEqual( journal_send.getField( 'MESSAGE' ), 'Test' ); 112 | done(); 113 | } catch( e ) { 114 | done( e ); 115 | } 116 | 117 | } ); 118 | 119 | it( "should log a notice", function( done ) { 120 | 121 | log.notice( 'Test' ); 122 | 123 | try { 124 | assert.strictEqual( journal_send.getField( 'PRIORITY' ), '5' ); 125 | assert.strictEqual( journal_send.getField( 'MESSAGE' ), 'Test' ); 126 | done(); 127 | } catch( e ) { 128 | done( e ); 129 | } 130 | 131 | } ); 132 | 133 | it( "should log a info", function( done ) { 134 | 135 | log.info( 'Test' ); 136 | 137 | try { 138 | assert.strictEqual( journal_send.getField( 'PRIORITY' ), '6' ); 139 | assert.strictEqual( journal_send.getField( 'MESSAGE' ), 'Test' ); 140 | done(); 141 | } catch( e ) { 142 | done( e ); 143 | } 144 | 145 | } ); 146 | 147 | it( "should log a debug", function( done ) { 148 | 149 | log.debug( 'Test' ); 150 | 151 | try { 152 | assert.strictEqual( journal_send.getField( 'PRIORITY' ), '7' ); 153 | assert.strictEqual( journal_send.getField( 'MESSAGE' ), 'Test' ); 154 | done(); 155 | } catch( e ) { 156 | done( e ); 157 | } 158 | 159 | } ); 160 | 161 | it( "should append specified fields", function( done ) { 162 | 163 | log.debug( 'Test', { 164 | number: 3, 165 | boolean: true, 166 | string: 'Chuck Norris', 167 | OBJ: { 168 | nUmBer: 4 169 | }, 170 | ARR: [ 5 ] 171 | } ); 172 | 173 | try { 174 | assert.strictEqual( journal_send.getField( 'PRIORITY' ), '7' ); 175 | assert.strictEqual( journal_send.getField( 'MESSAGE' ), 'Test' ); 176 | assert.strictEqual( journal_send.getField( 'NUMBER' ), '3' ); 177 | assert.strictEqual( journal_send.getField( 'BOOLEAN' ), 'true' ); 178 | assert.strictEqual( journal_send.getField( 'STRING' ), 'Chuck Norris' ); 179 | assert.strictEqual( journal_send.getField( 'OBJ_NUMBER' ), '4' ); 180 | assert.strictEqual( journal_send.getField( 'ARR_0' ), '5' ); 181 | done(); 182 | } catch( e ) { 183 | done( e ); 184 | } 185 | 186 | } ); 187 | 188 | it( "should convert Error instances", function( done ) { 189 | 190 | log.debug( new Error( 'Test' ) ); 191 | 192 | try { 193 | assert.strictEqual( journal_send.getField( 'PRIORITY' ), '7' ); 194 | assert.strictEqual( journal_send.getField( 'MESSAGE' ), 'Test' ); 195 | assert.strictEqual( journal_send.getField( 'CODE_LINE' ), '190' ); 196 | assert.strictEqual( journal_send.getField( 'CODE_FUNC' ), 'Context.' ); 197 | assert.strictEqual( journal_send.getField( 'CODE_FILE' ).substr( -13 ), 'test/index.js' ); 198 | assert.notStrictEqual( journal_send.getField( 'STACK_TRACE' ), undefined ); 199 | done(); 200 | } catch( e ) { 201 | done( e ); 202 | } 203 | 204 | } ); 205 | 206 | it( "should set the syslog identifier", function( done ) { 207 | 208 | var localLog = new log( { syslog_identifier: 'test-identifier' } ); 209 | localLog.debug( 'Test' ); 210 | 211 | try { 212 | assert.strictEqual( journal_send.getField( 'SYSLOG_IDENTIFIER' ), 'test-identifier' ); 213 | done(); 214 | } catch( e ) { 215 | done( e ); 216 | } 217 | 218 | } ); 219 | 220 | it( "should prefer the identifier set in the options to the global identifier", function( done ) { 221 | 222 | var localLog = new log( { syslog_identifier: 'test-identifier' } ); 223 | localLog.debug( 'Test', { 224 | syslog_identifier: 'local-identifier' 225 | } ); 226 | 227 | try { 228 | assert.strictEqual( journal_send.getField( 'SYSLOG_IDENTIFIER' ), 'local-identifier' ); 229 | done(); 230 | } catch( e ) { 231 | done( e ); 232 | } 233 | 234 | } ); 235 | 236 | it( "should not touch default fields", function( done ) { 237 | 238 | var defaultFields = { syslog_identifier: 'test-identifier' }; 239 | var localLog = new log( defaultFields ); 240 | localLog.debug( new Error('test error') ); 241 | 242 | try { 243 | assert.deepStrictEqual( Object.keys( defaultFields ), [ 'syslog_identifier' ] ); 244 | done(); 245 | } catch( e ) { 246 | done( e ); 247 | } 248 | 249 | } ); 250 | 251 | it( "should convert buffers into strings", function( done ) { 252 | 253 | log.debug( 'test', { 254 | test: Buffer.from([0x00, 0x01, 0x02, 0xff]) 255 | } ); 256 | 257 | try { 258 | assert.strictEqual( journal_send.getField( 'MESSAGE' ), 'test' ); 259 | assert.strictEqual( journal_send.getField( 'TEST' ), '000102ff' ); 260 | done(); 261 | } catch( e ) { 262 | done( e ); 263 | } 264 | 265 | } ); 266 | 267 | it( "should convert null into string 'null'", function( done ) { 268 | 269 | log.debug( 'test', { 270 | test: null 271 | } ); 272 | 273 | try { 274 | assert.strictEqual( journal_send.getField( 'MESSAGE' ), 'test' ); 275 | assert.strictEqual( journal_send.getField( 'TEST' ), 'null' ); 276 | done(); 277 | } catch( e ) { 278 | done( e ); 279 | } 280 | 281 | } ); 282 | 283 | } ); 284 | 285 | 286 | describe("real module", function() { 287 | it("should not crash when logging", function() { 288 | var log = require( '../index.js' ); 289 | log.debug("debug message", {test: true}); 290 | }) 291 | }) 292 | --------------------------------------------------------------------------------