swadhinbiswas # Changelog · 1/17/2026
9eabb75
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import pino from "pino";
// Custom OTLP transport for Grafana Cloud
const createOtlpTransport = () => {
const endpoint = process.env.GRAFANA_OTLP_ENDPOINT;
const instanceId = process.env.GRAFANA_INSTANCE_ID;
const apiKey = process.env.GRAFANA_API_KEY;
if (!endpoint || !instanceId || !apiKey) {
return null;
}
const authPair = `${instanceId}:${apiKey}`;
const encoded = Buffer.from(authPair).toString('base64');
return {
send: async (level: string, message: string, extra: Record<string, unknown> = {}) => {
try {
const body = {
resourceLogs: [{
resource: {
attributes: [
{ key: "service.name", value: { stringValue: "opencodehub" } },
{ key: "environment", value: { stringValue: process.env.NODE_ENV || "development" } }
]
},
scopeLogs: [{
logRecords: [{
timeUnixNano: String(Date.now() * 1e6),
severityText: level.toUpperCase(),
body: { stringValue: message },
attributes: Object.entries(extra).map(([key, value]) => ({
key,
value: { stringValue: String(value) }
}))
}]
}]
}]
};
await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Basic ${encoded}`,
},
body: JSON.stringify(body)
});
} catch (error) {
// Silently fail to avoid infinite logging loops
console.error('[OTLP Transport Error]', error);
}
}
};
};
const transports = [];
// Always add standard output (pretty in dev, json in prod)
if (process.env.NODE_ENV === "development") {
transports.push({
target: "pino-pretty",
options: {
colorize: true,
},
});
} else {
transports.push({
target: "pino/file",
options: { destination: 1 }
});
}
// Initialize OTLP transport
const otlpTransport = createOtlpTransport();
// Create base pino logger
const baseLogger = pino({
level: process.env.LOG_LEVEL || "info",
transport: transports.length > 0 ? {
targets: transports
} : undefined,
});
// Wrap logger to also send to OTLP if configured
const createWrappedLogger = () => {
const wrap = (level: string) => (msg: string | object, ...args: unknown[]) => {
// Call original pino method
(baseLogger as unknown as Record<string, Function>)[level](msg, ...args);
// Send to OTLP if configured
if (otlpTransport) {
const message = typeof msg === 'string' ? msg : JSON.stringify(msg);
const extra = typeof msg === 'object' ? msg : (args[0] as Record<string, unknown>) || {};
otlpTransport.send(level, message, extra as Record<string, unknown>);
}
};
return {
trace: wrap('trace'),
debug: wrap('debug'),
info: wrap('info'),
warn: wrap('warn'),
error: wrap('error'),
fatal: wrap('fatal'),
child: baseLogger.child.bind(baseLogger),
level: baseLogger.level,
};
};
export const logger = otlpTransport ? createWrappedLogger() : baseLogger;