1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
|
# Cologne
Cologne is a logger multiplexer that uses a JSON log format inspired in gelf.
It can be instantiated with several loggers, or they can be changed after
the fact.
## Usage
Install from npm
```
$ npm install --save cologne
```
Create an instance
```javascript
const { Cologne, Loggers, Formatters } = require('cologne');
const co = new Cologne({
from: 'Special Worker Logger',
loggers: [
new Loggers.Console({
formatter: new Formatters.Token({
formatString: '[{{_timestamp}}]{{_from}}: {{message}}'
})
})
]
});
```
This example would create a cologne instance with a console logger that
uses a Token formatter. (More on loggers and formatters below.);
## Quick API Reference
* **addLogger(logger)**: Adds a logger to the cologne instance.
* **removeLogger(logger)**: Removes a logger from the cologne instance.
* **buildLog(item, level, [meta])**: Generates a cologne log object as if you had
logged an item (it will do this automatically when you log anything.)
level defaults to 6. You can optionally send it an object to extend
the object with.
* **log, info, notice, warn, error**: Generates a log object with the
appropriate severity level and sends it to all loggers.
## Loggers
Cologne loggers are any object that responds to the `#log()` method.
This methoud should be able to receive any number of arguments and
log them independently. Similar to how you can send multiple arguments
to the browser console.
`#log()` will receive any number of `Cologne Log Objects`. For a detailed
reference of this format, see further below.
Cologne includes two loggers out of the box:
* `Loggers.Console` logs to the JS console
* `Loggers.File` appends to a file
### Loggers.Console
This logger communicates with the Javascript console. It uses the log level
to trigger the appropriate method, so `error` logs would go to stderr
as expected when calling `console.error`.
This logger can be sent a `formatter`, which is an object that responds
to the `#format()` method: it should receive a cologne log object and respond
with a string.
```javascript
new Loggers.Console({
formatter : new Formatters.Token({
formatString: '[{{_timestamp}}]{{_from}}: {{message}}'
})
});
```
### Loggers.File
This logger opens a writable stream to a file, to which it will append
everything. Like the Console logger it supports a `formatter` property
that will respond to the `#format()` method.
It MUST include a `file` property on initialization, otherwise it will throw
an exception.
```javascript
new Loggers.File({
file: '/var/log/server_log.log',
formatter : new Formatters.Token({
formatString: '[{{_ansi:_level}}{{_timestamp}}{{_ansi:reset}}]{{_from}}: {{message}}'
})
});
```
### More Loggers?
We're working on a socket logger. It's separate so you don't have to
install the socket dependencies if you don't want to.
You can build your own logger easily for any method of transport you find
necessary (e.g. mail, database, twitter, etc). Any object that responds
to `#log()` is a valid logger:
```javascript
// A valid, very minimalistic logger
const simpleLogger = {
log: function(...logs) {
for (const log of logs) {
this._doSomeMagic(logs);
}
},
_doSomeMagic: function(log) {
console.log(log + "... but magical!");
}
};
logger.addLogger(simpleLogger);
```
## Formatters
Cologne doesn't need formatters to work, and in fact they're optional in
the included loggers. But if you would like to make your logs prettier,
then you can use one of the included formatters or roll your own.
Formatters are objects that respond to the `#format()` method. It will
receive a single cologne log object (see fields it includes below), and
it should return a string.
We include some formatters so you can get running real quicklike:
* `Formatters.Simple` a simple predefined formatter
* `Formatters.Token` a formatter that lets you define format
strings that it will use to build your final log.
### Formatters.Simple
This is the lazy formatter, it just outputs the string in the following
format:
```
'[{{_timestamp}}][{{_levelString}}]{{_from}}: {{message}}'
```
Where `_timestamp` is converted to ISO.
#### Accepted Options
* `colorize` <Boolean>: whether or not to add color. False by default.
By default we don't colorize the output, but if you enable the flag this
formatter will add a bit of color in the level string. Red for error, crit,
alert, and emerg; yellow for warn; blue for info; green for debug; and white
for everything else.
#### Usage
```javascript
new Formatters.Simple({
colorize: true
});
```
### Example Output
```
co.log("hello world");
// -> [2016-01-21T05:50:36.505Z][INFO] Server Logger: hello world
```
### Formatters.Token
The token formatter lets you build strings with simple tokens. When
instantiating, you can specify a `formatString` to interpolate
properties from the logObject. The default version looks for tokens
inside double curly braces like `{{message}}` or `{{_level}}`. If
you don't like it, you can specify your own.
#### Accepted Options
* `formatString` <String>: The string used to replace. Defaults to `"{{message}}"`
* `replaceRule` <String>: The regex rule to use for replacement of tokens in the
formatString. Defaults to `/{{(.*?)}}/g`
* `isoDate` <Boolean> : Whether or not to convert `_timestamp` to ISO
date. Defaults to true. Otherwise it'll use the raw timestamp.
#### Usage
```javascript
new Formatters.Token({
formatString: '[{{_timestamp}}]{{_from}}: {{message}}'
});
```
#### ANSI tokens
If you want to add color to your logs, you can use the special \_ansi
token. It has several options which you can call like `{{_ansi:red}}`
and `{{_ansi:reset}}`. Here's a list of all the ansi stuff you can use:
* `bold`: makes text bold
* `italics`: makes text italics
* `underline`: makes text underlined
* `inverse`: inverts foreground and background
* `strikethrough`: strikethrough text
* `bold_off`, `italics_off`, `underline_off`, `inverse_off`, and
`strikethrough_off`: turn off the specified effect.
* `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`,
and `default`: change the foreground color of your text.
* `black_bg`, `red_bg`, `green_bg`, `yellow_bg`, `blue_bg`, `magenta_bg`,
`cyan_bg`, `white_bg`, and `default_bg`: change the background color of your
text.
* `reset`: makes everything normal again.
* `_level`: this is a special code that will set a color depending on
the level of the log: debug gets green, info and notice blue, warn is
yellow, and anything worse is red.
### More Formatters?
You can create your own formatters by creating an object that responds
to the `#format()` method, knows how to handle cologne log objects and
returns a string.
Here's an example of a logger that surrounds a log with sparkles:
```javascript
const sparkleFormatter = {
format: function(logObject) {
return `✨${logObject.message}✨`;
}
}
logger.addLogger(new Loggers.Console({
formatter: sparkleFormatter
}));
```
## The Cologne Log Format
The cologne log format is a JSON based log format, based on the cobalt
log format, which is in turn based on Graylog's GELF. However, where GELF
treats all internal fields without a prefix, and all user fields with a
prefix, we do it backwards so it's easier to extend the object with
metadata from existing objects.
You could try to build it on your own, but you can use `#buildLog()`
to build it without logging.
### Fields
* **\_timestamp** : A bigint timestamp in nanoseconds
* **\_cologneLog** <String> : This is how we know if the log is already
formatted and ready to go. This field is a string containing the
version of cologne log format it's using. It's `2.0.0` right now.
* **\_from**: The sender of the log (Defaults to Generic Cologne Logger)
* **\_level**: The level of the log (Defaults to 6)
* **\_levelString**: The string corresponding to the log level (e.g. 7 ->
debug, 3 -> error, 0 -> emerg)
### A word on Log Levels
The log levels in cologne correspond to the syslog levels, and the
levelStrings correspond to the priority keywords:
* `0 -> emerg`
* `1 -> alert`
* `2 -> crit`
* `3 -> error`
* `4 -> warning`
* `5 -> notice`
* `6 -> info`
* `7 -> debug`
This is useful when deciding how to log. You could even have a logger
filter out unnecessary levels (eg. If you have a reporting logger that
only reports error or worse.)
## Further Improvements
* Improve the API for buildLog
* More loggers & formatters (will not be distributed in core cologne)
* Improve tests
|