UNPKG

2.65 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 !== false,
26 clearOnError: options.clearOnError,
27 replaceOnError: options.replaceOnError,
28 replaceTimestamp: options.replaceTimestamp,
29 gracefulShutdown: options.gracefulShutdown !== false
30 })
31
32 this.useCustomFormat = options.format !== undefined
33 this.labels = options.labels
34 }
35
36 /**
37 * An overwrite of winston-transport's log(),
38 * which the Winston logging library uses
39 * when pushing logs to a transport.
40 *
41 * @param {*} info
42 * @param {*} callback
43 * @memberof LokiTransport
44 */
45 log (info, callback) {
46 // Immediately tell Winston that this transport has received the log.
47 setImmediate(() => {
48 this.emit('logged', info)
49 })
50
51 // Deconstruct the log
52 const { label, labels, timestamp, level, message, ...rest } = info
53
54 // build custom labels if provided
55 let lokiLabels
56 if (this.labels) {
57 lokiLabels = `{level="${level}"`
58 for (let key in this.labels) {
59 lokiLabels += `,${key}="${this.labels[key]}"`
60 }
61 if (labels) {
62 for (let key in labels) {
63 lokiLabels += `,${key}="${labels[key]}"`
64 }
65 }
66 lokiLabels += '}'
67 } else {
68 lokiLabels = `{job="${label}", level="${level}"}`
69 }
70
71 // follow the format provided
72 const line = this.useCustomFormat ? info[MESSAGE] : `${message} ${
73 rest && Object.keys(rest).length > 0 ? JSON.stringify(rest) : ''
74 }`
75
76 // Construct the log to fit Grafana Loki's accepted format
77 const logEntry = {
78 labels: lokiLabels,
79 entries: [
80 {
81 ts: timestamp || Date.now(),
82 line
83 }
84 ]
85 }
86
87 // Pushes the log to the batcher
88 this.batcher.pushLogEntry(logEntry)
89
90 // Trigger the optional callback
91 callback()
92 }
93
94 /**
95 * Send batch to loki when clean up
96 */
97 close () {
98 this.batcher.sendBatchToLoki()
99 .then(() => {}) // maybe should emit something here
100 .catch(() => {}) // maybe should emit something here
101 }
102}
103
104module.exports = LokiTransport