@ditjenpajakri/elasticsearch-logging 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/lib.js +167 -0
- package/package.json +28 -0
package/README.md
ADDED
package/lib.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
const { Client } = require('@elastic/elasticsearch')
|
|
5
|
+
const split = require('split2')
|
|
6
|
+
const pump = require('pump')
|
|
7
|
+
|
|
8
|
+
function setDateTimeString(value) {
|
|
9
|
+
if (typeof value === 'object' && value.hasOwnProperty('time')) {
|
|
10
|
+
if (
|
|
11
|
+
(typeof value.time === 'string' && value.time.length) ||
|
|
12
|
+
(typeof value.time === 'number' && value.time >= 0)
|
|
13
|
+
) {
|
|
14
|
+
return new Date(value.time).toISOString()
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return new Date().toISOString()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function initializeBulkHandler (opts, client, splitter) {
|
|
21
|
+
const esVersion = Number(opts.esVersion || opts['es-version']) || 7
|
|
22
|
+
const index = opts.index || 'pino'
|
|
23
|
+
const buildIndexName = typeof index === 'function' ? index : null
|
|
24
|
+
const type = esVersion >= 7 ? undefined : (opts.type || 'log')
|
|
25
|
+
const opType = esVersion >= 7 ? (opts.opType || opts.op_type) : undefined
|
|
26
|
+
|
|
27
|
+
// Resurrect connection pool on destroy
|
|
28
|
+
splitter.destroy = () => {
|
|
29
|
+
if (typeof client.connectionPool.resurrect === 'function') {
|
|
30
|
+
client.connectionPool.resurrect({ name: 'elasticsearch-js' })
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const bulkInsert = client.helpers.bulk({
|
|
35
|
+
datasource: splitter,
|
|
36
|
+
flushBytes: opts.flushBytes || opts['flush-bytes'] || 1000,
|
|
37
|
+
flushInterval: opts.flushInterval || opts['flush-interval'] || 30000,
|
|
38
|
+
refreshOnCompletion: getIndexName(),
|
|
39
|
+
onDocument (doc) {
|
|
40
|
+
const date = doc.time || doc['@timestamp']
|
|
41
|
+
if (opType === 'create') {
|
|
42
|
+
doc['@timestamp'] = date
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
index: {
|
|
47
|
+
_index: getIndexName(date),
|
|
48
|
+
_type: type,
|
|
49
|
+
op_type: opType
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
onDrop (doc) {
|
|
54
|
+
const error = new Error('Dropped document')
|
|
55
|
+
error.document = doc
|
|
56
|
+
splitter.emit('insertError', error)
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
bulkInsert.then(
|
|
61
|
+
(stats) => splitter.emit('insert', stats),
|
|
62
|
+
(err) => splitter.emit('error', err)
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
function getIndexName (time = new Date().toISOString()) {
|
|
66
|
+
if (buildIndexName) {
|
|
67
|
+
return buildIndexName(time)
|
|
68
|
+
}
|
|
69
|
+
return index.replace('%{DATE}', time.substring(0, 10))
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
function pinoElasticSearch(opts = {}) {
|
|
75
|
+
const splitter = split(function (line) {
|
|
76
|
+
let value
|
|
77
|
+
try {
|
|
78
|
+
value = JSON.parse(line)
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.log(line);
|
|
81
|
+
// this.emit('unknown', line, error)
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (typeof value === 'boolean') {
|
|
86
|
+
this.emit('unknown', line, 'Boolean value ignored')
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
if (value === null) {
|
|
90
|
+
this.emit('unknown', line, 'Null value ignored')
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
if (typeof value !== 'object') {
|
|
94
|
+
value = {
|
|
95
|
+
data: value,
|
|
96
|
+
time: setDateTimeString(value)
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
if (value['@timestamp'] === undefined) {
|
|
100
|
+
value.time = setDateTimeString(value)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return value
|
|
104
|
+
}, { autoDestroy: true })
|
|
105
|
+
|
|
106
|
+
const clientOpts = {
|
|
107
|
+
node: opts.node,
|
|
108
|
+
auth: opts.auth,
|
|
109
|
+
// cloud: opts.cloud,
|
|
110
|
+
ssl: { rejectUnauthorized: opts.rejectUnauthorized, ...opts.tls }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (opts.caFingerprint) {
|
|
114
|
+
clientOpts.caFingerprint = opts.caFingerprint
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (opts.Connection) {
|
|
118
|
+
clientOpts.Connection = opts.Connection
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (opts.ConnectionPool) {
|
|
122
|
+
clientOpts.ConnectionPool = opts.ConnectionPool
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const client = new Client(clientOpts)
|
|
126
|
+
console.log("Logging to elasticsearch...");
|
|
127
|
+
console.log("Any line showing up here means that the line was not logged to elasticsearch.");
|
|
128
|
+
client.on('resurrect', () => {
|
|
129
|
+
initializeBulkHandler(opts, client, splitter)
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
initializeBulkHandler(opts, client, splitter)
|
|
133
|
+
|
|
134
|
+
return splitter
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function start(opts) {
|
|
138
|
+
console.log('opts', opts)
|
|
139
|
+
const stream = pinoElasticSearch(opts)
|
|
140
|
+
|
|
141
|
+
stream.on('unknown', (line, error) => {
|
|
142
|
+
console.error('Elasticsearch client json error in line:\n' + line + '\nError:', error)
|
|
143
|
+
})
|
|
144
|
+
stream.on('error', (error) => {
|
|
145
|
+
console.error('Elasticsearch client error:', error)
|
|
146
|
+
})
|
|
147
|
+
stream.on('insertError', (error) => {
|
|
148
|
+
console.error('Elasticsearch server error:', error)
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
pump(process.stdin, stream)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = pinoElasticSearch
|
|
155
|
+
|
|
156
|
+
if (require.main === module) {
|
|
157
|
+
start({
|
|
158
|
+
node: process.env.LOG_ES_HOST || 'http://localhost:9200',
|
|
159
|
+
auth: {
|
|
160
|
+
username: process.env.LOG_ES_USER || 'elastic',
|
|
161
|
+
password: process.env.LOG_ES_PASS || 'changeme'
|
|
162
|
+
},
|
|
163
|
+
index: process.env.LOG_ES_INDEX || 'pino-%{DATE}',
|
|
164
|
+
flushBytes: process.env.LOG_ES_FLUSH_BYTES ? parseInt(process.env.LOG_ES_FLUSH_BYTES) : undefined,
|
|
165
|
+
rejectUnauthorized: process.env.LOG_ES_REJECT_UNAUTHORIZED === 'true' ? true : false
|
|
166
|
+
})
|
|
167
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ditjenpajakri/elasticsearch-logging",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Elasticsearch ",
|
|
5
|
+
"main": "lib.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"log-to-es": "lib.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"author": "nsrb",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/ditjenpajakri/pino-elasticsearch-logging.git"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@elastic/elasticsearch": "^7.17.12",
|
|
20
|
+
"pump": "^3.0.0",
|
|
21
|
+
"split2": "^4.2.0"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/ditjenpajakri/pino-elasticsearch-logging/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/ditjenpajakri/pino-elasticsearch-logging#readme",
|
|
27
|
+
"devDependencies": {}
|
|
28
|
+
}
|