azify-logger 1.0.16 → 1.0.18
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 +5 -6
- package/index.js +17 -4
- package/init.js +74 -0
- package/middleware-express.js +2 -2
- package/package.json +13 -9
- package/register.js +456 -0
- package/server.js +147 -77
- package/streams/bunyan.js +2 -2
- package/streams/pino.js +17 -5
package/README.md
CHANGED
|
@@ -86,9 +86,7 @@ const app = express()
|
|
|
86
86
|
|----------|-----------------------------------|-----------|
|
|
87
87
|
| `APP_NAME` | - | Nome da aplicação |
|
|
88
88
|
| `AZIFY_LOGGER_URL` | `http://localhost:3001/log` | URL do logger |
|
|
89
|
-
| `
|
|
90
|
-
| `NODE_ENV` | `development` | Ambiente |
|
|
91
|
-
| `AZIFY_LOGGER_AUTOREG_DISABLE` | `""` | Se `"1"`, desativa auto-registro do OTEL |
|
|
89
|
+
| `NODE_ENV` | `development` | Ambiente |
|
|
92
90
|
|
|
93
91
|
### 🌐 URLs por Ambiente
|
|
94
92
|
|
|
@@ -102,14 +100,14 @@ NODE_ENV=development
|
|
|
102
100
|
**Staging:**
|
|
103
101
|
```env
|
|
104
102
|
APP_NAME=minha-app
|
|
105
|
-
AZIFY_LOGGER_URL=
|
|
103
|
+
AZIFY_LOGGER_URL=https://logsdashboard.azify.dev/send
|
|
106
104
|
NODE_ENV=staging
|
|
107
105
|
```
|
|
108
106
|
|
|
109
107
|
**Production:**
|
|
110
108
|
```env
|
|
111
109
|
APP_NAME=minha-app
|
|
112
|
-
AZIFY_LOGGER_URL=
|
|
110
|
+
AZIFY_LOGGER_URL=https://logsdashboard.azify.prd/send (a conigurar)
|
|
113
111
|
NODE_ENV=production
|
|
114
112
|
```
|
|
115
113
|
|
|
@@ -167,6 +165,8 @@ if (createAzifyBunyanStream) {
|
|
|
167
165
|
stream: createAzifyBunyanStream({
|
|
168
166
|
loggerUrl: process.env.AZIFY_LOGGER_URL || 'http://localhost:3001/log',
|
|
169
167
|
serviceName: process.env.APP_NAME || 'app'
|
|
168
|
+
loggerUrl: process.env.AZIFY_LOGGER_URL,
|
|
169
|
+
serviceName: process.env.APP_NAME
|
|
170
170
|
})
|
|
171
171
|
})
|
|
172
172
|
}
|
|
@@ -220,7 +220,6 @@ logger.error('Erro', new Error('Falha'), { context: 'payment' })
|
|
|
220
220
|
|
|
221
221
|
Se você precisa subir a infraestrutura do azify-logger:
|
|
222
222
|
|
|
223
|
-
### 1. Iniciar serviços
|
|
224
223
|
|
|
225
224
|
```bash
|
|
226
225
|
./start-docker.sh
|
package/index.js
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
const axios = require('axios')
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
|
|
3
|
+
let context, propagation, trace, W3CTraceContextPropagator
|
|
4
|
+
try {
|
|
5
|
+
const otelApi = require('@opentelemetry/api')
|
|
6
|
+
const otelCore = require('@opentelemetry/core')
|
|
7
|
+
context = otelApi.context
|
|
8
|
+
propagation = otelApi.propagation
|
|
9
|
+
trace = otelApi.trace
|
|
10
|
+
W3CTraceContextPropagator = otelCore.W3CTraceContextPropagator
|
|
11
|
+
} catch (_) {
|
|
12
|
+
context = { active: () => ({}) }
|
|
13
|
+
propagation = { setGlobalPropagator: () => {} }
|
|
14
|
+
trace = { getSpan: () => null }
|
|
15
|
+
W3CTraceContextPropagator = class {}
|
|
16
|
+
}
|
|
4
17
|
|
|
5
18
|
if (process.env.AZIFY_LOGGER_AUTOREG_DISABLE !== '1') {
|
|
6
19
|
try { require('./register-otel') } catch (_) {}
|
|
@@ -41,7 +54,7 @@ class AzifyLogger {
|
|
|
41
54
|
*/
|
|
42
55
|
async log(level, message, meta = {}) {
|
|
43
56
|
const span = trace.getSpan(context.active())
|
|
44
|
-
const spanContext = span
|
|
57
|
+
const spanContext = span && span.spanContext()
|
|
45
58
|
|
|
46
59
|
const logData = {
|
|
47
60
|
level,
|
|
@@ -50,7 +63,7 @@ class AzifyLogger {
|
|
|
50
63
|
...meta,
|
|
51
64
|
service: {
|
|
52
65
|
name: this.options.serviceName,
|
|
53
|
-
version: meta.service
|
|
66
|
+
version: (meta.service && meta.service.version) || '1.0.0'
|
|
54
67
|
},
|
|
55
68
|
environment: this.options.environment,
|
|
56
69
|
timestamp: new Date().toISOString(),
|
package/init.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
if (process.env.AZIFY_LOGGER_DISABLE === '1') {
|
|
2
|
+
module.exports = {}
|
|
3
|
+
} else {
|
|
4
|
+
const Module = require('module')
|
|
5
|
+
const originalRequire = Module.prototype.require
|
|
6
|
+
|
|
7
|
+
Module.prototype.require = function(id) {
|
|
8
|
+
const result = originalRequire.call(this, id)
|
|
9
|
+
|
|
10
|
+
if (id === '@nestjs/common') {
|
|
11
|
+
if (result && result.Logger) {
|
|
12
|
+
const originalLoggerConstructor = result.Logger
|
|
13
|
+
|
|
14
|
+
function PatchedLogger(context) {
|
|
15
|
+
const instance = new originalLoggerConstructor(context)
|
|
16
|
+
|
|
17
|
+
instance.log = function(message, context) {
|
|
18
|
+
const { getRequestContext } = require('./store')
|
|
19
|
+
const ctx = getRequestContext()
|
|
20
|
+
if (ctx && ctx.traceId) {
|
|
21
|
+
return originalLoggerConstructor.prototype.log.call(this, message, context)
|
|
22
|
+
}
|
|
23
|
+
return originalLoggerConstructor.prototype.log.call(this, message, context)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
instance.error = function(message, trace, context) {
|
|
27
|
+
const { getRequestContext } = require('./store')
|
|
28
|
+
const ctx = getRequestContext()
|
|
29
|
+
if (ctx && ctx.traceId) {
|
|
30
|
+
return originalLoggerConstructor.prototype.error.call(this, message, trace, context)
|
|
31
|
+
}
|
|
32
|
+
return originalLoggerConstructor.prototype.error.call(this, message, trace, context)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
instance.warn = function(message, context) {
|
|
36
|
+
const { getRequestContext } = require('./store')
|
|
37
|
+
const ctx = getRequestContext()
|
|
38
|
+
if (ctx && ctx.traceId) {
|
|
39
|
+
return originalLoggerConstructor.prototype.warn.call(this, message, context)
|
|
40
|
+
}
|
|
41
|
+
return originalLoggerConstructor.prototype.warn.call(this, message, context)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
instance.debug = function(message, context) {
|
|
45
|
+
const { getRequestContext } = require('./store')
|
|
46
|
+
const ctx = getRequestContext()
|
|
47
|
+
if (ctx && ctx.traceId) {
|
|
48
|
+
return originalLoggerConstructor.prototype.debug.call(this, message, context)
|
|
49
|
+
}
|
|
50
|
+
return originalLoggerConstructor.prototype.debug.call(this, message, context)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
instance.verbose = function(message, context) {
|
|
54
|
+
const { getRequestContext } = require('./store')
|
|
55
|
+
const ctx = getRequestContext()
|
|
56
|
+
if (ctx && ctx.traceId) {
|
|
57
|
+
return originalLoggerConstructor.prototype.verbose.call(this, message, context)
|
|
58
|
+
}
|
|
59
|
+
return originalLoggerConstructor.prototype.verbose.call(this, message, context)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return instance
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
Object.setPrototypeOf(PatchedLogger, originalLoggerConstructor)
|
|
66
|
+
Object.assign(PatchedLogger, originalLoggerConstructor)
|
|
67
|
+
|
|
68
|
+
result.Logger = PatchedLogger
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return result
|
|
73
|
+
}
|
|
74
|
+
}
|
package/middleware-express.js
CHANGED
|
@@ -186,8 +186,8 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
186
186
|
path: req.url,
|
|
187
187
|
headers: sanitizeHeaders(req.headers || {}),
|
|
188
188
|
query: req.query || {},
|
|
189
|
-
userAgent: req.headers
|
|
190
|
-
ip: req.connection
|
|
189
|
+
userAgent: (req.headers && req.headers['user-agent']) || 'unknown',
|
|
190
|
+
ip: (req.connection && req.connection.remoteAddress) || (req.socket && req.socket.remoteAddress) || req.ip || 'unknown',
|
|
191
191
|
traceId: requestTraceId,
|
|
192
192
|
spanId: requestSpanId,
|
|
193
193
|
parentSpanId: requestParentSpanId
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "azify-logger",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.18",
|
|
4
4
|
"description": "Azify Logger Client - Centralized logging for OpenSearch",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -27,13 +27,6 @@
|
|
|
27
27
|
"author": "Azify",
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@opentelemetry/api": "^1.7.0",
|
|
31
|
-
"@opentelemetry/auto-instrumentations-node": "^0.40.0",
|
|
32
|
-
"@opentelemetry/core": "^1.28.0",
|
|
33
|
-
"@opentelemetry/exporter-trace-otlp-http": "^0.45.0",
|
|
34
|
-
"@opentelemetry/resources": "^1.28.0",
|
|
35
|
-
"@opentelemetry/sdk-node": "^0.45.0",
|
|
36
|
-
"@opentelemetry/semantic-conventions": "^1.28.0",
|
|
37
30
|
"axios": "^1.6.0",
|
|
38
31
|
"cors": "^2.8.5",
|
|
39
32
|
"express": "^4.18.2",
|
|
@@ -43,12 +36,23 @@
|
|
|
43
36
|
"require-in-the-middle": "^7.4.0",
|
|
44
37
|
"uuid": "^9.0.1"
|
|
45
38
|
},
|
|
39
|
+
"optionalDependencies": {
|
|
40
|
+
"@opentelemetry/api": "^1.7.0",
|
|
41
|
+
"@opentelemetry/auto-instrumentations-node": "^0.40.0",
|
|
42
|
+
"@opentelemetry/core": "^1.28.0",
|
|
43
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.45.0",
|
|
44
|
+
"@opentelemetry/resources": "^1.28.0",
|
|
45
|
+
"@opentelemetry/sdk-node": "^0.45.0",
|
|
46
|
+
"@opentelemetry/semantic-conventions": "^1.28.0"
|
|
47
|
+
},
|
|
46
48
|
"engines": {
|
|
47
|
-
"node": ">=
|
|
49
|
+
"node": ">=12.0.0"
|
|
48
50
|
},
|
|
49
51
|
"files": [
|
|
50
52
|
"index.js",
|
|
51
53
|
"index.d.ts",
|
|
54
|
+
"init.js",
|
|
55
|
+
"register.js",
|
|
52
56
|
"store.js",
|
|
53
57
|
"register-otel.js",
|
|
54
58
|
"register-restify.js",
|
package/register.js
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
if (process.env.AZIFY_LOGGER_DISABLE === '1') {
|
|
2
|
+
module.exports = {}
|
|
3
|
+
} else {
|
|
4
|
+
try {
|
|
5
|
+
const bunyan = require('bunyan')
|
|
6
|
+
const createBunyanStream = require('./streams/bunyan')
|
|
7
|
+
const { getRequestContext } = require('./store')
|
|
8
|
+
|
|
9
|
+
const originalCreate = bunyan.createLogger
|
|
10
|
+
bunyan.createLogger = function patchedCreateLogger(options) {
|
|
11
|
+
const logger = originalCreate.call(bunyan, options)
|
|
12
|
+
try {
|
|
13
|
+
const level = process.env.AZIFY_LOG_LEVEL || (options && options.level) || 'info'
|
|
14
|
+
const loggerUrl = process.env.AZIFY_LOGGER_URL || 'http://localhost:3001'
|
|
15
|
+
const serviceName = process.env.APP_NAME || (options && options.name) || 'app'
|
|
16
|
+
const environment = process.env.NODE_ENV || 'development'
|
|
17
|
+
|
|
18
|
+
logger.addStream({
|
|
19
|
+
level,
|
|
20
|
+
type: 'raw',
|
|
21
|
+
stream: createBunyanStream({ loggerUrl, serviceName, environment })
|
|
22
|
+
})
|
|
23
|
+
} catch (_) {}
|
|
24
|
+
return logger
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const Module = require('module')
|
|
29
|
+
const originalRequire = Module.prototype.require
|
|
30
|
+
const { getRequestContext } = require('./store')
|
|
31
|
+
|
|
32
|
+
Module.prototype.require = function(id) {
|
|
33
|
+
const result = originalRequire.call(this, id)
|
|
34
|
+
if (id === 'pino' || id.endsWith('/pino')) {
|
|
35
|
+
if (result && typeof result === 'function') {
|
|
36
|
+
const originalPino = result
|
|
37
|
+
|
|
38
|
+
const patchedPino = function(options, stream) {
|
|
39
|
+
const logger = originalPino(options, stream)
|
|
40
|
+
|
|
41
|
+
const originalInfo = logger.info
|
|
42
|
+
const originalError = logger.error
|
|
43
|
+
const originalWarn = logger.warn
|
|
44
|
+
const originalDebug = logger.debug
|
|
45
|
+
const originalFatal = logger.fatal
|
|
46
|
+
const originalTrace = logger.trace
|
|
47
|
+
|
|
48
|
+
logger.info = function(obj, msg, ...args) {
|
|
49
|
+
const ctx = getRequestContext()
|
|
50
|
+
if (ctx && ctx.traceId) {
|
|
51
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
52
|
+
obj.traceId = ctx.traceId
|
|
53
|
+
obj.spanId = ctx.spanId
|
|
54
|
+
obj.parentSpanId = ctx.parentSpanId
|
|
55
|
+
obj.requestId = ctx.requestId
|
|
56
|
+
} else {
|
|
57
|
+
obj = { traceId: ctx.traceId, spanId: ctx.spanId, parentSpanId: ctx.parentSpanId, requestId: ctx.requestId, msg: obj }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return originalInfo.call(this, obj, msg, ...args)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
logger.error = function(obj, msg, ...args) {
|
|
64
|
+
const ctx = getRequestContext()
|
|
65
|
+
if (ctx && ctx.traceId) {
|
|
66
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
67
|
+
obj.traceId = ctx.traceId
|
|
68
|
+
obj.spanId = ctx.spanId
|
|
69
|
+
obj.parentSpanId = ctx.parentSpanId
|
|
70
|
+
obj.requestId = ctx.requestId
|
|
71
|
+
} else {
|
|
72
|
+
obj = { traceId: ctx.traceId, spanId: ctx.spanId, parentSpanId: ctx.parentSpanId, requestId: ctx.requestId, msg: obj }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return originalError.call(this, obj, msg, ...args)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
logger.warn = function(obj, msg, ...args) {
|
|
79
|
+
const ctx = getRequestContext()
|
|
80
|
+
if (ctx && ctx.traceId) {
|
|
81
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
82
|
+
obj.traceId = ctx.traceId
|
|
83
|
+
obj.spanId = ctx.spanId
|
|
84
|
+
obj.parentSpanId = ctx.parentSpanId
|
|
85
|
+
obj.requestId = ctx.requestId
|
|
86
|
+
} else {
|
|
87
|
+
obj = { traceId: ctx.traceId, spanId: ctx.spanId, parentSpanId: ctx.parentSpanId, requestId: ctx.requestId, msg: obj }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return originalWarn.call(this, obj, msg, ...args)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
logger.debug = function(obj, msg, ...args) {
|
|
94
|
+
const ctx = getRequestContext()
|
|
95
|
+
if (ctx && ctx.traceId) {
|
|
96
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
97
|
+
obj.traceId = ctx.traceId
|
|
98
|
+
obj.spanId = ctx.spanId
|
|
99
|
+
obj.parentSpanId = ctx.parentSpanId
|
|
100
|
+
obj.requestId = ctx.requestId
|
|
101
|
+
} else {
|
|
102
|
+
obj = { traceId: ctx.traceId, spanId: ctx.spanId, parentSpanId: ctx.parentSpanId, requestId: ctx.requestId, msg: obj }
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return originalDebug.call(this, obj, msg, ...args)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
logger.fatal = function(obj, msg, ...args) {
|
|
109
|
+
const ctx = getRequestContext()
|
|
110
|
+
if (ctx && ctx.traceId) {
|
|
111
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
112
|
+
obj.traceId = ctx.traceId
|
|
113
|
+
obj.spanId = ctx.spanId
|
|
114
|
+
obj.parentSpanId = ctx.parentSpanId
|
|
115
|
+
obj.requestId = ctx.requestId
|
|
116
|
+
} else {
|
|
117
|
+
obj = { traceId: ctx.traceId, spanId: ctx.spanId, parentSpanId: ctx.parentSpanId, requestId: ctx.requestId, msg: obj }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return originalFatal.call(this, obj, msg, ...args)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
logger.trace = function(obj, msg, ...args) {
|
|
124
|
+
const ctx = getRequestContext()
|
|
125
|
+
if (ctx && ctx.traceId) {
|
|
126
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
127
|
+
obj.traceId = ctx.traceId
|
|
128
|
+
obj.spanId = ctx.spanId
|
|
129
|
+
obj.parentSpanId = ctx.parentSpanId
|
|
130
|
+
obj.requestId = ctx.requestId
|
|
131
|
+
} else {
|
|
132
|
+
obj = { traceId: ctx.traceId, spanId: ctx.spanId, parentSpanId: ctx.parentSpanId, requestId: ctx.requestId, msg: obj }
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return originalTrace.call(this, obj, msg, ...args)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return logger
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
Object.setPrototypeOf(patchedPino, originalPino)
|
|
142
|
+
Object.assign(patchedPino, originalPino)
|
|
143
|
+
|
|
144
|
+
return patchedPino
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return result
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
} catch (_) {}
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
const { Logger } = require('@nestjs/common')
|
|
155
|
+
if (Logger) {
|
|
156
|
+
const originalLog = Logger.prototype.log
|
|
157
|
+
const originalError = Logger.prototype.error
|
|
158
|
+
const originalWarn = Logger.prototype.warn
|
|
159
|
+
const originalDebug = Logger.prototype.debug
|
|
160
|
+
const originalVerbose = Logger.prototype.verbose
|
|
161
|
+
|
|
162
|
+
Logger.prototype.log = function(message, context) {
|
|
163
|
+
const { getRequestContext } = require('./store')
|
|
164
|
+
const ctx = getRequestContext()
|
|
165
|
+
if (ctx && ctx.traceId) {
|
|
166
|
+
return originalLog.call(this, message, context)
|
|
167
|
+
}
|
|
168
|
+
return originalLog.call(this, message, context)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
Logger.prototype.error = function(message, trace, context) {
|
|
172
|
+
const { getRequestContext } = require('./store')
|
|
173
|
+
const ctx = getRequestContext()
|
|
174
|
+
if (ctx && ctx.traceId) {
|
|
175
|
+
return originalError.call(this, message, trace, context)
|
|
176
|
+
}
|
|
177
|
+
return originalError.call(this, message, trace, context)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
Logger.prototype.warn = function(message, context) {
|
|
181
|
+
const { getRequestContext } = require('./store')
|
|
182
|
+
const ctx = getRequestContext()
|
|
183
|
+
if (ctx && ctx.traceId) {
|
|
184
|
+
return originalWarn.call(this, message, context)
|
|
185
|
+
}
|
|
186
|
+
return originalWarn.call(this, message, context)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
Logger.prototype.debug = function(message, context) {
|
|
190
|
+
const { getRequestContext } = require('./store')
|
|
191
|
+
const ctx = getRequestContext()
|
|
192
|
+
if (ctx && ctx.traceId) {
|
|
193
|
+
return originalDebug.call(this, message, context)
|
|
194
|
+
}
|
|
195
|
+
return originalDebug.call(this, message, context)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
Logger.prototype.verbose = function(message, context) {
|
|
199
|
+
const { getRequestContext } = require('./store')
|
|
200
|
+
const ctx = getRequestContext()
|
|
201
|
+
if (ctx && ctx.traceId) {
|
|
202
|
+
return originalVerbose.call(this, message, context)
|
|
203
|
+
}
|
|
204
|
+
return originalVerbose.call(this, message, context)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
}
|
|
208
|
+
} catch (_) {}
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
const originalConsoleLog = console.log
|
|
212
|
+
const originalConsoleError = console.error
|
|
213
|
+
const originalConsoleWarn = console.warn
|
|
214
|
+
|
|
215
|
+
console.log = function(...args) {
|
|
216
|
+
return originalConsoleLog.apply(this, args)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
console.error = function(...args) {
|
|
220
|
+
return originalConsoleError.apply(this, args)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
console.warn = function(...args) {
|
|
224
|
+
return originalConsoleWarn.apply(this, args)
|
|
225
|
+
}
|
|
226
|
+
} catch (_) {}
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
const Module = require('module')
|
|
230
|
+
const originalRequire = Module.prototype.require
|
|
231
|
+
|
|
232
|
+
Module.prototype.require = function(id) {
|
|
233
|
+
const result = originalRequire.call(this, id)
|
|
234
|
+
|
|
235
|
+
if (id === 'nestjs-pino' || id.endsWith('/nestjs-pino') || id.includes('nestjs-pino')) {
|
|
236
|
+
if (result && result.Logger) {
|
|
237
|
+
const originalLoggerConstructor = result.Logger
|
|
238
|
+
|
|
239
|
+
function PatchedNestJSPinoLogger(context) {
|
|
240
|
+
const instance = new originalLoggerConstructor(context)
|
|
241
|
+
|
|
242
|
+
instance.error = function(message, trace, context) {
|
|
243
|
+
const { getRequestContext } = require('./store')
|
|
244
|
+
const ctx = getRequestContext()
|
|
245
|
+
if (ctx && ctx.traceId) {
|
|
246
|
+
return originalLoggerConstructor.prototype.error.call(this, message, trace, context)
|
|
247
|
+
}
|
|
248
|
+
return originalLoggerConstructor.prototype.error.call(this, message, trace, context)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
instance.log = function(message, context) {
|
|
252
|
+
const { getRequestContext } = require('./store')
|
|
253
|
+
const ctx = getRequestContext()
|
|
254
|
+
if (ctx && ctx.traceId) {
|
|
255
|
+
return originalLoggerConstructor.prototype.log.call(this, message, context)
|
|
256
|
+
}
|
|
257
|
+
return originalLoggerConstructor.prototype.log.call(this, message, context)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
instance.warn = function(message, context) {
|
|
261
|
+
const { getRequestContext } = require('./store')
|
|
262
|
+
const ctx = getRequestContext()
|
|
263
|
+
if (ctx && ctx.traceId) {
|
|
264
|
+
return originalLoggerConstructor.prototype.warn.call(this, message, context)
|
|
265
|
+
}
|
|
266
|
+
return originalLoggerConstructor.prototype.warn.call(this, message, context)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
instance.debug = function(message, context) {
|
|
270
|
+
const { getRequestContext } = require('./store')
|
|
271
|
+
const ctx = getRequestContext()
|
|
272
|
+
if (ctx && ctx.traceId) {
|
|
273
|
+
return originalLoggerConstructor.prototype.debug.call(this, message, context)
|
|
274
|
+
}
|
|
275
|
+
return originalLoggerConstructor.prototype.debug.call(this, message, context)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
instance.verbose = function(message, context) {
|
|
279
|
+
const { getRequestContext } = require('./store')
|
|
280
|
+
const ctx = getRequestContext()
|
|
281
|
+
if (ctx && ctx.traceId) {
|
|
282
|
+
return originalLoggerConstructor.prototype.verbose.call(this, message, context)
|
|
283
|
+
}
|
|
284
|
+
return originalLoggerConstructor.prototype.verbose.call(this, message, context)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return instance
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
Object.setPrototypeOf(PatchedNestJSPinoLogger, originalLoggerConstructor)
|
|
291
|
+
Object.assign(PatchedNestJSPinoLogger, originalLoggerConstructor)
|
|
292
|
+
|
|
293
|
+
result.Logger = PatchedNestJSPinoLogger
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (result && result.LoggerModule && result.LoggerModule.forRoot) {
|
|
297
|
+
const originalForRoot = result.LoggerModule.forRoot
|
|
298
|
+
|
|
299
|
+
result.LoggerModule.forRoot = function(options) {
|
|
300
|
+
const createPinoStream = require('./streams/pino')
|
|
301
|
+
const stream = createPinoStream()
|
|
302
|
+
|
|
303
|
+
const mergedOptions = {
|
|
304
|
+
...options,
|
|
305
|
+
pinoHttp: {
|
|
306
|
+
...(options && options.pinoHttp),
|
|
307
|
+
stream,
|
|
308
|
+
},
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return originalForRoot.call(this, mergedOptions)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
Object.setPrototypeOf(result.LoggerModule.forRoot, originalForRoot)
|
|
315
|
+
Object.assign(result.LoggerModule.forRoot, originalForRoot)
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return result
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
} catch (_) {}
|
|
323
|
+
|
|
324
|
+
try {
|
|
325
|
+
const undici = require('undici')
|
|
326
|
+
if (undici && undici.request) {
|
|
327
|
+
const originalRequest = undici.request
|
|
328
|
+
undici.request = function(url, options, callback) {
|
|
329
|
+
const { getRequestContext } = require('./store')
|
|
330
|
+
const ctx = getRequestContext()
|
|
331
|
+
|
|
332
|
+
if (ctx && ctx.traceId) {
|
|
333
|
+
const headers = (options && options.headers) || {}
|
|
334
|
+
options = {
|
|
335
|
+
...options,
|
|
336
|
+
headers: {
|
|
337
|
+
...headers,
|
|
338
|
+
'X-Trace-ID': ctx.traceId,
|
|
339
|
+
'X-Span-ID': ctx.spanId || '',
|
|
340
|
+
'X-Parent-Span-ID': ctx.parentSpanId || '',
|
|
341
|
+
'X-Request-ID': ctx.requestId || require('uuid').v4()
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return originalRequest.call(this, url, options, callback)
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
} catch (_) {}
|
|
350
|
+
|
|
351
|
+
try {
|
|
352
|
+
const axios = require('axios')
|
|
353
|
+
if (axios && axios.create) {
|
|
354
|
+
const originalCreate = axios.create
|
|
355
|
+
axios.create = function(config) {
|
|
356
|
+
const instance = originalCreate.call(this, config)
|
|
357
|
+
|
|
358
|
+
const originalRequest = instance.interceptors.request.use
|
|
359
|
+
instance.interceptors.request.use = function(fulfilled, rejected) {
|
|
360
|
+
return originalRequest.call(this, (config) => {
|
|
361
|
+
const { getRequestContext } = require('./store')
|
|
362
|
+
const ctx = getRequestContext()
|
|
363
|
+
|
|
364
|
+
if (ctx && ctx.traceId) {
|
|
365
|
+
config.headers = {
|
|
366
|
+
...config.headers,
|
|
367
|
+
'X-Trace-ID': ctx.traceId,
|
|
368
|
+
'X-Span-ID': ctx.spanId || '',
|
|
369
|
+
'X-Parent-Span-ID': ctx.parentSpanId || '',
|
|
370
|
+
'X-Request-ID': ctx.requestId || require('uuid').v4()
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return fulfilled ? fulfilled(config) : config
|
|
375
|
+
}, rejected)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return instance
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
} catch (_) {}
|
|
382
|
+
|
|
383
|
+
try {
|
|
384
|
+
const Bull = require('bull')
|
|
385
|
+
const { runWithRequestContext } = require('./store')
|
|
386
|
+
|
|
387
|
+
const originalAdd = Bull.prototype.add
|
|
388
|
+
Bull.prototype.add = function(name, data, opts) {
|
|
389
|
+
const ctx = getRequestContext()
|
|
390
|
+
|
|
391
|
+
if (ctx && ctx.traceId) {
|
|
392
|
+
data = {
|
|
393
|
+
...data,
|
|
394
|
+
traceId: ctx.traceId,
|
|
395
|
+
spanId: ctx.spanId,
|
|
396
|
+
parentSpanId: ctx.parentSpanId,
|
|
397
|
+
requestId: ctx.requestId,
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return originalAdd.call(this, name, data, opts)
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const originalProcess = Bull.prototype.process
|
|
405
|
+
Bull.prototype.process = function(name, concurrency, handler) {
|
|
406
|
+
let actualName, actualConcurrency, actualHandler
|
|
407
|
+
|
|
408
|
+
if (typeof name === 'function') {
|
|
409
|
+
actualHandler = name
|
|
410
|
+
actualName = '__default__'
|
|
411
|
+
actualConcurrency = 1
|
|
412
|
+
} else if (typeof concurrency === 'function') {
|
|
413
|
+
actualHandler = concurrency
|
|
414
|
+
actualName = name
|
|
415
|
+
actualConcurrency = 1
|
|
416
|
+
} else {
|
|
417
|
+
actualName = name
|
|
418
|
+
actualConcurrency = concurrency
|
|
419
|
+
actualHandler = handler
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const wrappedHandler = function(job, done) {
|
|
423
|
+
const { traceId, spanId, parentSpanId, requestId, ...jobData } = job.data
|
|
424
|
+
|
|
425
|
+
if (traceId && spanId) {
|
|
426
|
+
const ctx = {
|
|
427
|
+
traceId,
|
|
428
|
+
spanId,
|
|
429
|
+
parentSpanId,
|
|
430
|
+
requestId,
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return runWithRequestContext(ctx, () => {
|
|
434
|
+
return actualHandler.call(this, job, done)
|
|
435
|
+
})
|
|
436
|
+
} else {
|
|
437
|
+
const { startRequestContext } = require('./store')
|
|
438
|
+
const newCtx = startRequestContext({ requestId: require('uuid').v4() })
|
|
439
|
+
|
|
440
|
+
return runWithRequestContext(newCtx, () => {
|
|
441
|
+
return actualHandler.call(this, job, done)
|
|
442
|
+
})
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
if (typeof name === 'function') {
|
|
447
|
+
return originalProcess.call(this, wrappedHandler)
|
|
448
|
+
} else if (typeof concurrency === 'function') {
|
|
449
|
+
return originalProcess.call(this, actualName, wrappedHandler)
|
|
450
|
+
} else {
|
|
451
|
+
return originalProcess.call(this, actualName, actualConcurrency, wrappedHandler)
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
} catch (_) {}
|
|
455
|
+
} catch (_) {}
|
|
456
|
+
}
|
package/server.js
CHANGED
|
@@ -4,14 +4,27 @@ const axios = require('axios')
|
|
|
4
4
|
const express = require('express')
|
|
5
5
|
const cors = require('cors')
|
|
6
6
|
const os = require('os')
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
let trace, context, propagation, W3CTraceContextPropagator
|
|
8
|
+
try {
|
|
9
|
+
const otelApi = require('@opentelemetry/api')
|
|
10
|
+
const otelCore = require('@opentelemetry/core')
|
|
11
|
+
trace = otelApi.trace
|
|
12
|
+
context = otelApi.context
|
|
13
|
+
propagation = otelApi.propagation
|
|
14
|
+
W3CTraceContextPropagator = otelCore.W3CTraceContextPropagator
|
|
15
|
+
} catch (_) {
|
|
16
|
+
trace = { getSpan: () => null }
|
|
17
|
+
context = { active: () => ({}) }
|
|
18
|
+
propagation = { extract: () => ({}), inject: () => {} }
|
|
19
|
+
W3CTraceContextPropagator = class {}
|
|
20
|
+
}
|
|
9
21
|
|
|
10
22
|
const app = express()
|
|
11
23
|
|
|
12
24
|
app.set('trust proxy', 1)
|
|
13
25
|
|
|
14
|
-
app.use(express.json())
|
|
26
|
+
app.use(express.json({ limit: '10mb' }))
|
|
27
|
+
app.use(express.urlencoded({ extended: true, limit: '10mb' }))
|
|
15
28
|
app.use(cors())
|
|
16
29
|
|
|
17
30
|
const authEnabled = process.env.AZURE_AD_AUTH_ENABLED === 'true'
|
|
@@ -33,79 +46,121 @@ const propagator = new W3CTraceContextPropagator()
|
|
|
33
46
|
const traceContextMap = new Map()
|
|
34
47
|
|
|
35
48
|
/**
|
|
36
|
-
*
|
|
49
|
+
* Creates an index template for dynamic log indices
|
|
50
|
+
* This allows OpenSearch to auto-create indices like logs-azipay, logs-assemble, etc.
|
|
37
51
|
* @returns {Promise<void>}
|
|
38
52
|
* @private
|
|
39
53
|
*/
|
|
40
|
-
async function
|
|
41
|
-
const
|
|
54
|
+
async function ensureIndexTemplate() {
|
|
55
|
+
const templateName = 'logs-template'
|
|
42
56
|
const osUrl = process.env.OPENSEARCH_URL || 'http://localhost:9200'
|
|
57
|
+
|
|
43
58
|
try {
|
|
44
|
-
await axios.
|
|
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
|
-
statusCode: { type: 'integer' },
|
|
84
|
-
responseTime: { type: 'float' },
|
|
85
|
-
ip: { type: 'ip' },
|
|
86
|
-
userAgent: { type: 'text' },
|
|
87
|
-
environment: { type: 'keyword' },
|
|
88
|
-
hostname: { type: 'keyword' },
|
|
89
|
-
responseBody: { type: 'text' },
|
|
90
|
-
error: {
|
|
91
|
-
properties: {
|
|
92
|
-
message: { type: 'text' },
|
|
93
|
-
stack: { type: 'text' },
|
|
94
|
-
name: { type: 'keyword' }
|
|
95
|
-
}
|
|
59
|
+
await axios.put(`${osUrl}/_index_template/${templateName}`, {
|
|
60
|
+
index_patterns: ['logs-*'],
|
|
61
|
+
template: {
|
|
62
|
+
settings: {
|
|
63
|
+
number_of_shards: 1,
|
|
64
|
+
number_of_replicas: 0,
|
|
65
|
+
'index.refresh_interval': '5s'
|
|
66
|
+
},
|
|
67
|
+
mappings: {
|
|
68
|
+
properties: {
|
|
69
|
+
timestamp: { type: 'date' },
|
|
70
|
+
level: { type: 'keyword' },
|
|
71
|
+
message: { type: 'text' },
|
|
72
|
+
service: {
|
|
73
|
+
properties: {
|
|
74
|
+
name: { type: 'keyword' },
|
|
75
|
+
version: { type: 'keyword' }
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
appName: { type: 'keyword' },
|
|
79
|
+
traceId: { type: 'keyword' },
|
|
80
|
+
spanId: { type: 'keyword' },
|
|
81
|
+
parentSpanId: { type: 'keyword' },
|
|
82
|
+
userId: { type: 'keyword' },
|
|
83
|
+
requestId: { type: 'keyword' },
|
|
84
|
+
method: { type: 'keyword' },
|
|
85
|
+
url: { type: 'keyword' },
|
|
86
|
+
statusCode: { type: 'integer' },
|
|
87
|
+
responseTime: { type: 'float' },
|
|
88
|
+
ip: { type: 'ip' },
|
|
89
|
+
userAgent: { type: 'text' },
|
|
90
|
+
environment: { type: 'keyword' },
|
|
91
|
+
hostname: { type: 'keyword' },
|
|
92
|
+
responseBody: { type: 'text' },
|
|
93
|
+
error: {
|
|
94
|
+
properties: {
|
|
95
|
+
message: { type: 'text' },
|
|
96
|
+
stack: { type: 'text' },
|
|
97
|
+
name: { type: 'keyword' }
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
100
|
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
priority: 500
|
|
104
|
+
})
|
|
105
|
+
console.log(`✅ Index template ${templateName} criado/atualizado no OpenSearch`)
|
|
106
|
+
console.log(` Índices serão criados automaticamente no formato: logs-{service-name}`)
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error('❌ Erro ao criar index template:', error.message)
|
|
109
|
+
if (error.response) {
|
|
110
|
+
console.error(' Detalhes:', error.response.data)
|
|
104
111
|
}
|
|
105
112
|
}
|
|
106
113
|
}
|
|
107
114
|
|
|
108
|
-
|
|
115
|
+
ensureIndexTemplate()
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Escapes HTML special characters to prevent XSS attacks
|
|
119
|
+
* This prevents script injection when data is rendered in OpenSearch Dashboards
|
|
120
|
+
* @param {string} str - String to escape
|
|
121
|
+
* @returns {string} Escaped string
|
|
122
|
+
*/
|
|
123
|
+
function escapeHtml(str) {
|
|
124
|
+
if (typeof str !== 'string') return str
|
|
125
|
+
const map = {
|
|
126
|
+
'&': '&',
|
|
127
|
+
'<': '<',
|
|
128
|
+
'>': '>',
|
|
129
|
+
'"': '"',
|
|
130
|
+
"'": ''',
|
|
131
|
+
'/': '/'
|
|
132
|
+
}
|
|
133
|
+
return str.replace(/[&<>"'/]/g, (m) => map[m])
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Sanitizes a value recursively to prevent XSS attacks
|
|
138
|
+
* Escapes HTML special characters in strings that could be rendered in Dashboards
|
|
139
|
+
* @param {any} value - Value to sanitize
|
|
140
|
+
* @returns {any} Sanitized value
|
|
141
|
+
*/
|
|
142
|
+
function sanitizeValue(value) {
|
|
143
|
+
if (typeof value === 'string') {
|
|
144
|
+
// Escape HTML special characters to prevent XSS when rendered in Dashboards
|
|
145
|
+
return escapeHtml(value)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (Array.isArray(value)) {
|
|
149
|
+
return value.map(item => sanitizeValue(item))
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (value !== null && typeof value === 'object') {
|
|
153
|
+
const sanitized = {}
|
|
154
|
+
for (const key in value) {
|
|
155
|
+
if (value.hasOwnProperty(key)) {
|
|
156
|
+
sanitized[key] = sanitizeValue(value[key])
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return sanitized
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return value
|
|
163
|
+
}
|
|
109
164
|
|
|
110
165
|
function generateTraceId() {
|
|
111
166
|
return Math.random().toString(36).substring(2, 15) +
|
|
@@ -162,7 +217,18 @@ app.get('/', ensureAuthenticated, (req, res) => {
|
|
|
162
217
|
})
|
|
163
218
|
|
|
164
219
|
app.post('/log', async (req, res) => {
|
|
165
|
-
|
|
220
|
+
let { level, message, meta } = req.body
|
|
221
|
+
|
|
222
|
+
if (typeof message === 'string') {
|
|
223
|
+
message = sanitizeValue(message)
|
|
224
|
+
}
|
|
225
|
+
if (meta) {
|
|
226
|
+
meta = sanitizeValue(meta)
|
|
227
|
+
}
|
|
228
|
+
if (typeof level === 'string') {
|
|
229
|
+
level = sanitizeValue(level)
|
|
230
|
+
}
|
|
231
|
+
|
|
166
232
|
if (!level || !message) {
|
|
167
233
|
return res.status(400).json({ success: false, message: 'Level and message are required.' })
|
|
168
234
|
}
|
|
@@ -183,11 +249,11 @@ app.post('/log', async (req, res) => {
|
|
|
183
249
|
return res.json({ success: true, message: 'Log filtrado (Prisma verboso)' })
|
|
184
250
|
}
|
|
185
251
|
|
|
186
|
-
const requestId = meta
|
|
252
|
+
const requestId = meta && meta.requestId
|
|
187
253
|
|
|
188
254
|
let traceContext = null
|
|
189
255
|
|
|
190
|
-
if (meta
|
|
256
|
+
if (meta && meta.traceId && meta.spanId) {
|
|
191
257
|
traceContext = {
|
|
192
258
|
traceId: meta.traceId,
|
|
193
259
|
spanId: meta.spanId,
|
|
@@ -206,7 +272,8 @@ app.post('/log', async (req, res) => {
|
|
|
206
272
|
}
|
|
207
273
|
})
|
|
208
274
|
|
|
209
|
-
const
|
|
275
|
+
const span = trace.getSpan(extractedCtx)
|
|
276
|
+
const spanContext = (span && span.spanContext && span.spanContext()) || null
|
|
210
277
|
if (spanContext && spanContext.traceId && spanContext.spanId) {
|
|
211
278
|
traceContext = {
|
|
212
279
|
traceId: spanContext.traceId,
|
|
@@ -230,16 +297,16 @@ app.post('/log', async (req, res) => {
|
|
|
230
297
|
}
|
|
231
298
|
|
|
232
299
|
const logEntry = {
|
|
233
|
-
timestamp: meta
|
|
300
|
+
timestamp: (meta && meta.timestamp) || new Date().toISOString(),
|
|
234
301
|
level,
|
|
235
302
|
message,
|
|
236
303
|
service: {
|
|
237
|
-
name: meta
|
|
238
|
-
version: meta
|
|
304
|
+
name: (meta && meta.service && meta.service.name) || 'unknown-service',
|
|
305
|
+
version: (meta && meta.service && meta.service.version) || '1.0.0'
|
|
239
306
|
},
|
|
240
|
-
appName: meta
|
|
241
|
-
environment: meta
|
|
242
|
-
hostname: meta
|
|
307
|
+
appName: (meta && meta.appName) || (meta && meta.service && meta.service.name) || undefined,
|
|
308
|
+
environment: (meta && meta.environment) || process.env.NODE_ENV || 'development',
|
|
309
|
+
hostname: (meta && meta.hostname) || os.hostname(),
|
|
243
310
|
traceId: traceContext.traceId,
|
|
244
311
|
spanId: traceContext.spanId,
|
|
245
312
|
parentSpanId: traceContext.parentSpanId
|
|
@@ -255,12 +322,15 @@ app.post('/log', async (req, res) => {
|
|
|
255
322
|
|
|
256
323
|
try {
|
|
257
324
|
const osUrl = process.env.OPENSEARCH_URL || 'http://localhost:9200'
|
|
258
|
-
|
|
325
|
+
const serviceName = (logEntry.service.name || 'unknown').toLowerCase().replace(/[^a-z0-9-]/g, '-')
|
|
326
|
+
const indexName = `logs-${serviceName}`
|
|
327
|
+
|
|
328
|
+
await axios.post(`${osUrl}/${indexName}/_doc`, logEntry, {
|
|
259
329
|
headers: { 'Content-Type': 'application/json' }
|
|
260
330
|
})
|
|
261
331
|
|
|
262
|
-
console.log(`✅ [${level.toUpperCase()}] ${message} | traceId: ${traceContext.traceId.substring(0, 8)}... | service: ${logEntry.service.name}`)
|
|
263
|
-
res.json({ success: true, message: 'Log enviado com sucesso' })
|
|
332
|
+
console.log(`✅ [${level.toUpperCase()}] ${message} | traceId: ${traceContext.traceId.substring(0, 8)}... | service: ${logEntry.service.name} | index: ${indexName}`)
|
|
333
|
+
res.json({ success: true, message: 'Log enviado com sucesso', index: indexName })
|
|
264
334
|
} catch (error) {
|
|
265
335
|
console.error('❌ Erro ao enviar log para OpenSearch:', error.message)
|
|
266
336
|
if (error.response) {
|
package/streams/bunyan.js
CHANGED
|
@@ -43,7 +43,7 @@ function createBunyanStream(options = {}) {
|
|
|
43
43
|
|
|
44
44
|
const meta = {
|
|
45
45
|
...cleanRecord,
|
|
46
|
-
service: { name: serviceName, version: record.service
|
|
46
|
+
service: { name: serviceName, version: (record.service && record.service.version) || '1.0.0' },
|
|
47
47
|
environment,
|
|
48
48
|
timestamp: new Date().toISOString(),
|
|
49
49
|
hostname: require('os').hostname(),
|
|
@@ -54,7 +54,7 @@ function createBunyanStream(options = {}) {
|
|
|
54
54
|
|
|
55
55
|
const payload = { level, message: record.msg || record.message || 'log', meta }
|
|
56
56
|
|
|
57
|
-
axios.post(`${loggerUrl}`, payload, { headers, timeout:
|
|
57
|
+
axios.post(`${loggerUrl}`, payload, { headers, timeout: 10000 }).catch(() => {})
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
}
|
package/streams/pino.js
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
let context, propagation, trace, W3CTraceContextPropagator
|
|
2
|
+
try {
|
|
3
|
+
const otelApi = require('@opentelemetry/api')
|
|
4
|
+
const otelCore = require('@opentelemetry/core')
|
|
5
|
+
context = otelApi.context
|
|
6
|
+
propagation = otelApi.propagation
|
|
7
|
+
trace = otelApi.trace
|
|
8
|
+
W3CTraceContextPropagator = otelCore.W3CTraceContextPropagator
|
|
9
|
+
} catch (_) {
|
|
10
|
+
context = { active: () => ({}) }
|
|
11
|
+
propagation = { setGlobalPropagator: () => {}, inject: () => {} }
|
|
12
|
+
trace = { getSpan: () => null }
|
|
13
|
+
W3CTraceContextPropagator = class {}
|
|
14
|
+
}
|
|
3
15
|
const axios = require('axios')
|
|
4
16
|
|
|
5
17
|
function createPinoStream(options = {}) {
|
|
@@ -23,7 +35,7 @@ function createPinoStream(options = {}) {
|
|
|
23
35
|
spanId = ctx.spanId
|
|
24
36
|
} else {
|
|
25
37
|
const span = trace.getSpan(context.active())
|
|
26
|
-
const spanContext = span
|
|
38
|
+
const spanContext = span && span.spanContext()
|
|
27
39
|
if (spanContext) {
|
|
28
40
|
traceId = spanContext.traceId
|
|
29
41
|
spanId = spanContext.spanId
|
|
@@ -44,7 +56,7 @@ function createPinoStream(options = {}) {
|
|
|
44
56
|
|
|
45
57
|
const meta = {
|
|
46
58
|
...record,
|
|
47
|
-
service: { name: serviceName, version: record.service
|
|
59
|
+
service: { name: serviceName, version: (record.service && record.service.version) || '1.0.0' },
|
|
48
60
|
environment,
|
|
49
61
|
timestamp: new Date().toISOString(),
|
|
50
62
|
hostname: require('os').hostname(),
|
|
@@ -54,7 +66,7 @@ function createPinoStream(options = {}) {
|
|
|
54
66
|
}
|
|
55
67
|
|
|
56
68
|
const payload = { level, message: record.msg || record.message || 'log', meta }
|
|
57
|
-
axios.post(`${loggerUrl}`, payload, { headers, timeout:
|
|
69
|
+
axios.post(`${loggerUrl}`, payload, { headers, timeout: 10000 }).catch(() => {})
|
|
58
70
|
}
|
|
59
71
|
}
|
|
60
72
|
}
|