-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
86 lines (80 loc) · 3.03 KB
/
index.js
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
const _ = require('lodash')
const util = require('util')
const { Client } = require('@elastic/elasticsearch')
// Elastic APM Logger
module.exports = {
startLogging: async function startLogging ({ esAuthObject, serviceName, apmObject }) {
// The `esAuthObject` is what the Client requires. Documentation here - https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-connecting.html#authentication
const client = new Client(esAuthObject)
// Create a datastream to send logs back for unique app, skip if datastream already exists
const loggingDataStreamName = `logs-${serviceName}`
try {
await client.indices.createDataStream({ name: loggingDataStreamName })
console.log('Elastic datastream already exists, skipping datastream creation..., continuing to logging.')
} catch (error) {
}
// Intercept stdout and send to Elastic APM
interceptStdout((stdout) => {
const isJsonAndEcsFormatted = isJsonString(stdout) && isECSFormat(JSON.parse(stdout))
// If its a regular log, then also include that as a message and send it back with the "trace.id" and "transaction.id"
const documentToSendBack =
isJsonAndEcsFormatted
? JSON.parse(stdout)
: ({
'@timestamp': new Date(),
service: { name: serviceName },
event: { dataset: `${serviceName}.log` },
message: `${stdout}`,
trace: { id: apmObject.currentTraceIds['trace.id'] },
transaction: { id: apmObject.currentTraceIds['transaction.id'] }
})
// Send the log line data
client.index({
index: loggingDataStreamName,
document: documentToSendBack
})
})
}
}
// Source - https://gist.github.com/benbuckman/2758563
// intercept stdout, passes thru callback
// also pass console.error thru stdout so it goes to callback too
// (stdout.write and stderr.write are both refs to the same stream.write function)
// returns an unhook() function, call when done intercepting
function interceptStdout (callback) {
const oldStdoutWrite = process.stdout.write
const oldConsoleError = console.error
process.stdout.write = (function (write) {
return function (string, encoding, fd) {
const args = _.toArray(arguments)
write.apply(process.stdout, args)
// only intercept the string
callback.call(callback, string)
}
}(process.stdout.write))
console.error = (function (log) {
return function () {
const args = _.toArray(arguments)
args.unshift('[ERROR]')
console.log.apply(console.log, args)
// string here encapsulates all the args
callback.call(callback, util.format(args))
}
}(console.error))
// puts back to original
return function unhook () {
process.stdout.write = oldStdoutWrite
console.error = oldConsoleError
}
}
function isJsonString (theString) {
try {
JSON.parse(theString)
} catch (e) {
return false
}
return true
}
function isECSFormat (jsonObject) {
return _.has(jsonObject, 'ecs.version')
}