azify-logger 1.0.43 → 1.0.44
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 +3 -3
- package/middleware-pino.js +164 -0
- package/package.json +3 -1
- package/pino-config.js +26 -0
- package/register.js +272 -170
- package/server.js +331 -150
- package/streams/pino.js +21 -4
package/README.md
CHANGED
|
@@ -95,16 +95,16 @@ O `azify-logger` inclui um OpenTelemetry Collector configurado para receber trac
|
|
|
95
95
|
Para habilitar o envio de traces, configure a variável de ambiente na sua aplicação:
|
|
96
96
|
|
|
97
97
|
```bash
|
|
98
|
-
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:
|
|
98
|
+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:3001/v1/traces
|
|
99
99
|
```
|
|
100
100
|
|
|
101
101
|
### URLs
|
|
102
102
|
|
|
103
103
|
| Ambiente | URL |
|
|
104
104
|
|----------|-----|
|
|
105
|
-
| **Development** | `http://localhost:
|
|
105
|
+
| **Development (Docker)** | `http://localhost:3001/v1/traces` |
|
|
106
106
|
| **Staging** | `https://logsdashboard.azify.dev/v1/traces` |
|
|
107
|
-
| **Production** | `https://cadence.aztech.host/v1/traces` |
|
|
107
|
+
| **Production** | `https://cadence.aztech.host/v1/traces` |
|
|
108
108
|
|
|
109
109
|
## 🔍 Como Funciona
|
|
110
110
|
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
require('./otel-env')
|
|
2
|
+
const { startRequestContext, runWithRequestContext, getRequestContext } = require('./store')
|
|
3
|
+
const { createHttpLoggerTransport } = require('./streams/httpQueue')
|
|
4
|
+
const { sendSpanToOtel, setEndpointOverride } = require('./trace-export')
|
|
5
|
+
const os = require('os')
|
|
6
|
+
|
|
7
|
+
let trace, otelContext
|
|
8
|
+
try {
|
|
9
|
+
const otelApi = require('@opentelemetry/api')
|
|
10
|
+
trace = otelApi.trace
|
|
11
|
+
otelContext = otelApi.context
|
|
12
|
+
} catch (_) {
|
|
13
|
+
trace = { getSpan: () => null }
|
|
14
|
+
otelContext = { active: () => ({}) }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function fastUUID() {
|
|
18
|
+
const timestamp = Date.now().toString(36)
|
|
19
|
+
const randomPart = Math.random().toString(36).substring(2, 15)
|
|
20
|
+
const randomPart2 = Math.random().toString(36).substring(2, 15)
|
|
21
|
+
return `${timestamp}-${randomPart}-${randomPart2}`.substring(0, 36)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function sanitizeTraceHex(value) {
|
|
25
|
+
if (!value || typeof value !== 'string') return null
|
|
26
|
+
const hex = value.replace(/[^0-9a-fA-F]/g, '').toLowerCase()
|
|
27
|
+
if (!hex) return null
|
|
28
|
+
return hex.padEnd(32, '0').slice(0, 32)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function createPinoHttpLoggingMiddleware(options = {}) {
|
|
32
|
+
const svcName = options.serviceName || process.env.APP_NAME
|
|
33
|
+
if (svcName) {
|
|
34
|
+
process.env.OTEL_SERVICE_NAME = svcName
|
|
35
|
+
process.env.SERVICE_NAME = svcName
|
|
36
|
+
}
|
|
37
|
+
const otelEndpoint = options.otelEndpoint || options.otelExporterEndpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
|
|
38
|
+
if (otelEndpoint) {
|
|
39
|
+
setEndpointOverride(otelEndpoint)
|
|
40
|
+
}
|
|
41
|
+
const config = {
|
|
42
|
+
serviceName: svcName,
|
|
43
|
+
loggerUrl: options.loggerUrl || process.env.AZIFY_LOGGER_URL || 'http://localhost:3001/log',
|
|
44
|
+
environment: options.environment || process.env.NODE_ENV,
|
|
45
|
+
logRequest: options.logRequest !== false && process.env.AZIFY_LOGGER_LOG_REQUEST !== 'false',
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const transport = createHttpLoggerTransport(config.loggerUrl, {})
|
|
49
|
+
const hostname = os.hostname()
|
|
50
|
+
const serviceObj = config.serviceName ? { name: config.serviceName, version: '1.0.0' } : null
|
|
51
|
+
|
|
52
|
+
function getOtelTraceContext() {
|
|
53
|
+
try {
|
|
54
|
+
const activeContext = otelContext.active()
|
|
55
|
+
const span = trace.getSpan(activeContext)
|
|
56
|
+
if (span) {
|
|
57
|
+
const spanContext = span.spanContext()
|
|
58
|
+
if (spanContext && spanContext.traceId && spanContext.spanId) {
|
|
59
|
+
const traceHex = spanContext.traceId.replace(/-/g, '')
|
|
60
|
+
return {
|
|
61
|
+
traceId: traceHex.length === 32 ? `${traceHex.substring(0, 8)}-${traceHex.substring(8, 12)}-${traceHex.substring(12, 16)}-${traceHex.substring(16, 20)}-${traceHex.substring(20, 32)}` : spanContext.traceId,
|
|
62
|
+
spanId: spanContext.spanId,
|
|
63
|
+
parentSpanId: null
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} catch (_) {}
|
|
68
|
+
return null
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function sendLog(level, message, meta = {}) {
|
|
72
|
+
if (!transport || typeof transport.enqueue !== 'function') return
|
|
73
|
+
|
|
74
|
+
transport.enqueue({
|
|
75
|
+
level,
|
|
76
|
+
message,
|
|
77
|
+
meta
|
|
78
|
+
}, { 'content-type': 'application/json' })
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return function azifyPinoLoggingMiddleware(req, res, next) {
|
|
82
|
+
const startTime = Date.now()
|
|
83
|
+
const method = req.method
|
|
84
|
+
const url = req.url
|
|
85
|
+
const path = req.path || url
|
|
86
|
+
|
|
87
|
+
let reqCtx = null
|
|
88
|
+
|
|
89
|
+
function ensureRequestContext() {
|
|
90
|
+
if (reqCtx) return reqCtx
|
|
91
|
+
|
|
92
|
+
const otelCtx = getOtelTraceContext()
|
|
93
|
+
const traceHex = otelCtx ? otelCtx.traceId.replace(/-/g, '').substring(0, 32) : sanitizeTraceHex(req.headers['x-trace-id'])
|
|
94
|
+
|
|
95
|
+
reqCtx = startRequestContext({
|
|
96
|
+
requestId: req.requestId || fastUUID(),
|
|
97
|
+
traceHex: traceHex || undefined,
|
|
98
|
+
parentSpanId: otelCtx?.parentSpanId || req.headers['x-parent-span-id'] || null
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
if (otelCtx) {
|
|
102
|
+
reqCtx.traceId = otelCtx.traceId
|
|
103
|
+
reqCtx.spanId = otelCtx.spanId
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return reqCtx
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const ctx = ensureRequestContext()
|
|
110
|
+
|
|
111
|
+
req.traceId = ctx.traceId
|
|
112
|
+
req.spanId = ctx.spanId
|
|
113
|
+
req.parentSpanId = ctx.parentSpanId
|
|
114
|
+
req.requestId = ctx.requestId
|
|
115
|
+
|
|
116
|
+
const logWithContext = (level, message, meta) => {
|
|
117
|
+
const otelCtx = getOtelTraceContext()
|
|
118
|
+
const ctx = getRequestContext() || ensureRequestContext()
|
|
119
|
+
|
|
120
|
+
meta.traceId = otelCtx?.traceId || meta.traceId || ctx.traceId
|
|
121
|
+
meta.spanId = otelCtx?.spanId || meta.spanId || ctx.spanId
|
|
122
|
+
meta.parentSpanId = otelCtx?.parentSpanId || meta.parentSpanId || ctx.parentSpanId
|
|
123
|
+
sendLog(level, message, meta)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (config.logRequest) {
|
|
127
|
+
logWithContext('info', `[REQUEST] ${method} ${path}`, {
|
|
128
|
+
method,
|
|
129
|
+
url: path,
|
|
130
|
+
hostname,
|
|
131
|
+
service: serviceObj,
|
|
132
|
+
environment: config.environment
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const originalEnd = res.end
|
|
137
|
+
res.end = function(...args) {
|
|
138
|
+
res.end = originalEnd
|
|
139
|
+
|
|
140
|
+
const duration = Date.now() - startTime
|
|
141
|
+
const statusCode = res.statusCode
|
|
142
|
+
|
|
143
|
+
if (config.logRequest) {
|
|
144
|
+
logWithContext('info', `[RESPONSE] ${method} ${path}`, {
|
|
145
|
+
method,
|
|
146
|
+
url: path,
|
|
147
|
+
statusCode,
|
|
148
|
+
duration,
|
|
149
|
+
hostname,
|
|
150
|
+
service: serviceObj,
|
|
151
|
+
environment: config.environment
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return res.end.apply(res, args)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
runWithRequestContext(ctx, () => {
|
|
159
|
+
next()
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = createPinoHttpLoggingMiddleware
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "azify-logger",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.44",
|
|
4
4
|
"description": "Azify Logger Client - Centralized logging for OpenSearch",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -94,9 +94,11 @@
|
|
|
94
94
|
"middleware-restify.js",
|
|
95
95
|
"middleware-express.js",
|
|
96
96
|
"middleware-express.d.ts",
|
|
97
|
+
"middleware-pino.js",
|
|
97
98
|
"middleware-fastify.js",
|
|
98
99
|
"server.js",
|
|
99
100
|
"sampling.js",
|
|
101
|
+
"pino-config.js",
|
|
100
102
|
"queue/",
|
|
101
103
|
"scripts/redis-worker.js",
|
|
102
104
|
"streams/",
|
package/pino-config.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const createPinoStream = require('./streams/pino')
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Helper para configurar Pino com azify-logger de forma simples
|
|
5
|
+
*/
|
|
6
|
+
function createAzifyPinoTransport(options = {}) {
|
|
7
|
+
const loggerUrl = options.loggerUrl || process.env.AZIFY_LOGGER_URL
|
|
8
|
+
const serviceName = options.serviceName || process.env.APP_NAME
|
|
9
|
+
const environment = options.environment || process.env.NODE_ENV
|
|
10
|
+
|
|
11
|
+
if (!loggerUrl) {
|
|
12
|
+
return null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
target: require.resolve('./streams/pino'),
|
|
17
|
+
options: {
|
|
18
|
+
loggerUrl,
|
|
19
|
+
serviceName,
|
|
20
|
+
environment,
|
|
21
|
+
...options
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = { createAzifyPinoTransport }
|