UNPKG

2.4 kBJavaScriptView Raw
1const Transport = require('winston-transport')
2const Batcher = require('./src/batcher')
3const { MESSAGE } = require('triple-beam')
4
5/**
6 * A Winston transport for Grafana Loki.
7 *
8 * @class LokiTransport
9 * @extends {Transport}
10 */
11class LokiTransport extends Transport {
12 /**
13 * Creates an instance of LokiTransport.
14 * @param {*} options
15 * @memberof LokiTransport
16 */
17 constructor (options) {
18 super(options)
19
20 // Pass all the given options to batcher
21 this.batcher = new Batcher({
22 host: options.host,
23 interval: options.interval,
24 json: options.json,
25 batching: options.batching !== undefined ? options.batching : true,
26 clearOnError: options.clearOnError,
27 replaceOnError: options.replaceOnError,
28 replaceTimestamp: options.replaceTimestamp
29 })
30
31 this.useCustomFormat = options.format !== undefined
32 this.labels = options.labels
33 }
34
35 /**
36 * An overwrite of winston-transport's log(),
37 * which the Winston logging library uses
38 * when pushing logs to a transport.
39 *
40 * @param {*} info
41 * @param {*} callback
42 * @memberof LokiTransport
43 */
44 log (info, callback) {
45 // Immediately tell Winston that this transport has received the log.
46 setImmediate(() => {
47 this.emit('logged', info)
48 })
49
50 // Deconstruct the log
51 const { label, labels, timestamp, level, message, ...rest } = info
52
53 // build custom labels if provided
54 let lokiLabels
55 if (this.labels) {
56 lokiLabels = `{level="${level}"`
57 for (let key in this.labels) {
58 lokiLabels += `,${key}="${this.labels[key]}"`
59 }
60 if (labels) {
61 for (let key in labels) {
62 lokiLabels += `,${key}="${labels[key]}"`
63 }
64 }
65 lokiLabels += '}'
66 } else {
67 lokiLabels = `{job="${label}", level="${level}"}`
68 }
69
70 // follow the format provided
71 const line = this.useCustomFormat ? info[MESSAGE] : `${message} ${
72 rest && Object.keys(rest).length > 0 ? JSON.stringify(rest) : ''
73 }`
74
75 // Construct the log to fit Grafana Loki's accepted format
76 const logEntry = {
77 labels: lokiLabels,
78 entries: [
79 {
80 ts: timestamp || Date.now(),
81 line
82 }
83 ]
84 }
85
86 // Pushes the log to the batcher
87 this.batcher.pushLogEntry(logEntry)
88
89 // Trigger the optional callback
90 callback()
91 }
92}
93
94module.exports = LokiTransport