@altinn/dialogporten-node-logger 1.89.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 +55 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/package.json +31 -0
- package/src/index.ts +88 -0
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# node-logger
|
|
2
|
+
|
|
3
|
+
Logger for nodejs that uses [pino](https://github.com/pinojs/pino)
|
|
4
|
+
as the logger tool. Allows for both a prettified log and a more
|
|
5
|
+
machine readable log depending on environment.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { logger } from '@digdir/dialogporten-node-logger'
|
|
11
|
+
|
|
12
|
+
logger.info('Hello world')
|
|
13
|
+
logger.info({such: 'context'}, 'Hello world with additional context')
|
|
14
|
+
logger.error(new Error('Some error'), 'Oops')
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
You can also create a "context logger", this will add a context object
|
|
19
|
+
to all log calls to that logger.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { logger, createContextLogger } from '@digdir/dialgporten-node-logger'
|
|
23
|
+
|
|
24
|
+
logger.info('Hello world')
|
|
25
|
+
// logs: { <standard fields>, mgs: 'Hello world' }
|
|
26
|
+
logger.info({such: 'context'}, 'Hello world with additional context')
|
|
27
|
+
// logs: { <standard fields>, such: 'context', mgs: 'Hello world' }
|
|
28
|
+
|
|
29
|
+
const ctxLogger = createContextLogger({ foo: 'bar' })
|
|
30
|
+
|
|
31
|
+
ctxLogger.info('Hello world')
|
|
32
|
+
// logs: { <standard fields>, foo: 'bar', mgs: 'Hello world' }
|
|
33
|
+
ctxLogger.info({such: 'context'}, 'Hello world with additional context')
|
|
34
|
+
// logs: { <standard fields>, foo: 'bar', such: 'context', mgs: 'Hello world' }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
You can also import the `pino` logger instance itself.
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { logger } from '@digdir/dialgporten-node-logger'
|
|
41
|
+
|
|
42
|
+
logger.pinoLogger.info('Hello world')
|
|
43
|
+
// logs: { <standard fields>, mgs: 'Hello world' }
|
|
44
|
+
|
|
45
|
+
### Configuration
|
|
46
|
+
|
|
47
|
+
Log level and format are configured through environment variables:
|
|
48
|
+
|
|
49
|
+
* `LOG_LEVEL` - Determines the log level. Allowed values:
|
|
50
|
+
`trace, debug, info, warn, error, fatal, silent`
|
|
51
|
+
* `TEST_LOGGING` - Verifies the log level set by logging
|
|
52
|
+
a message with every available log level. Allowed values: `true`
|
|
53
|
+
* `LOGGER_FORMAT` - If set to `json`, the logs will be output in
|
|
54
|
+
json format for easier consumption by log services. otherwise,
|
|
55
|
+
the logs are prettified
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
export declare const createContextLogger: (context: Record<string | number | symbol, unknown>) => {
|
|
3
|
+
trace: pino.LogFn;
|
|
4
|
+
debug: pino.LogFn;
|
|
5
|
+
info: pino.LogFn;
|
|
6
|
+
warn: pino.LogFn;
|
|
7
|
+
error: pino.LogFn;
|
|
8
|
+
fatal: pino.LogFn;
|
|
9
|
+
silent: pino.LogFn;
|
|
10
|
+
};
|
|
11
|
+
export declare const logger: {
|
|
12
|
+
trace: pino.LogFn;
|
|
13
|
+
debug: pino.LogFn;
|
|
14
|
+
info: pino.LogFn;
|
|
15
|
+
warn: pino.LogFn;
|
|
16
|
+
error: pino.LogFn;
|
|
17
|
+
fatal: pino.LogFn;
|
|
18
|
+
silent: pino.LogFn;
|
|
19
|
+
pinoLoggerInstance: import("pino").Logger<never>;
|
|
20
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
import z from 'zod';
|
|
3
|
+
const envVariables = z.object({
|
|
4
|
+
LOGGER_FORMAT: z.enum(['json', 'pretty']).default('pretty'),
|
|
5
|
+
LOG_LEVEL: z.nativeEnum(pino.levels.labels).default('info'),
|
|
6
|
+
TEST_LOGGING: z
|
|
7
|
+
.enum(['true', 'false'])
|
|
8
|
+
.transform((val) => val === 'true')
|
|
9
|
+
.default('false'),
|
|
10
|
+
OTEL_EXPORTER_OTLP_ENDPOINT: z.string().optional(),
|
|
11
|
+
});
|
|
12
|
+
const env = envVariables.parse(process.env);
|
|
13
|
+
console.info(`node-logger: Log level set to ${env.LOG_LEVEL}`);
|
|
14
|
+
const openTelemetryTransport = {
|
|
15
|
+
target: 'pino-opentelemetry-transport',
|
|
16
|
+
};
|
|
17
|
+
const pinoPrettyTransport = {
|
|
18
|
+
target: 'pino-pretty',
|
|
19
|
+
options: {
|
|
20
|
+
destination: 1,
|
|
21
|
+
colorize: true,
|
|
22
|
+
levelFirst: true,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
const jsonTransport = {
|
|
26
|
+
target: 'pino/file',
|
|
27
|
+
options: {
|
|
28
|
+
destination: 1,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
const consoleTransport = env.LOGGER_FORMAT === 'json' ? jsonTransport : pinoPrettyTransport;
|
|
32
|
+
// biome-ignore lint/suspicious/noExplicitAny: poor typings from pino
|
|
33
|
+
let transports;
|
|
34
|
+
// Configure transports based on OTEL endpoint availability
|
|
35
|
+
if (env.OTEL_EXPORTER_OTLP_ENDPOINT) {
|
|
36
|
+
console.info('node-logger: Using console and OpenTelemetry transports');
|
|
37
|
+
transports = pino.transport({
|
|
38
|
+
targets: [openTelemetryTransport, consoleTransport],
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
console.info('node-logger: Using console transport only');
|
|
43
|
+
transports = pino.transport(consoleTransport);
|
|
44
|
+
}
|
|
45
|
+
const pinoLogger = pino({ level: env.LOG_LEVEL }, transports);
|
|
46
|
+
export const createContextLogger = (context) => {
|
|
47
|
+
const child = pinoLogger.child(context);
|
|
48
|
+
return {
|
|
49
|
+
trace: child.trace.bind(child),
|
|
50
|
+
debug: child.debug.bind(child),
|
|
51
|
+
info: child.info.bind(child),
|
|
52
|
+
warn: child.warn.bind(child),
|
|
53
|
+
error: child.error.bind(child),
|
|
54
|
+
fatal: child.fatal.bind(child),
|
|
55
|
+
silent: child.silent.bind(child),
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
if (env.TEST_LOGGING) {
|
|
59
|
+
pinoLogger.debug('Debug test');
|
|
60
|
+
pinoLogger.trace('Trace test');
|
|
61
|
+
pinoLogger.info({ some: 'object' }, 'Info test');
|
|
62
|
+
pinoLogger.warn('Consider this a warning');
|
|
63
|
+
pinoLogger.error(new Error('Test error'), 'Error test');
|
|
64
|
+
pinoLogger.fatal(new Error('Test error'), 'Fatal test');
|
|
65
|
+
}
|
|
66
|
+
export const logger = {
|
|
67
|
+
trace: pinoLogger.trace.bind(pinoLogger),
|
|
68
|
+
debug: pinoLogger.debug.bind(pinoLogger),
|
|
69
|
+
info: pinoLogger.info.bind(pinoLogger),
|
|
70
|
+
warn: pinoLogger.warn.bind(pinoLogger),
|
|
71
|
+
error: pinoLogger.error.bind(pinoLogger),
|
|
72
|
+
fatal: pinoLogger.fatal.bind(pinoLogger),
|
|
73
|
+
silent: pinoLogger.silent.bind(pinoLogger),
|
|
74
|
+
pinoLoggerInstance: pinoLogger,
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@altinn/dialogporten-node-logger",
|
|
3
|
+
"version": "1.89.0",
|
|
4
|
+
"description": "A logger for nodejs",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"prepare": "tsc",
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"test": "npm run build && TEST_LOGGING=true node dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"logging"
|
|
13
|
+
],
|
|
14
|
+
"author": "",
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"pino": "9.3.2",
|
|
18
|
+
"pino-opentelemetry-transport": "1.1.0",
|
|
19
|
+
"pino-pretty": "11.2.2"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "22.5.1",
|
|
23
|
+
"typescript": "5.5.4",
|
|
24
|
+
"zod": "3.23.8"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/Altinn/dialogporten-frontend.git"
|
|
29
|
+
},
|
|
30
|
+
"type": "module"
|
|
31
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
import z from 'zod';
|
|
3
|
+
|
|
4
|
+
const envVariables = z.object({
|
|
5
|
+
LOGGER_FORMAT: z.enum(['json', 'pretty']).default('pretty'),
|
|
6
|
+
LOG_LEVEL: z.nativeEnum(pino.levels.labels).default('info'),
|
|
7
|
+
TEST_LOGGING: z
|
|
8
|
+
.enum(['true', 'false'])
|
|
9
|
+
.transform((val) => val === 'true')
|
|
10
|
+
.default('false'),
|
|
11
|
+
OTEL_EXPORTER_OTLP_ENDPOINT: z.string().optional(),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const env = envVariables.parse(process.env);
|
|
15
|
+
|
|
16
|
+
console.info(`node-logger: Log level set to ${env.LOG_LEVEL}`);
|
|
17
|
+
|
|
18
|
+
const openTelemetryTransport = {
|
|
19
|
+
target: 'pino-opentelemetry-transport',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const pinoPrettyTransport = {
|
|
23
|
+
target: 'pino-pretty',
|
|
24
|
+
options: {
|
|
25
|
+
destination: 1,
|
|
26
|
+
colorize: true,
|
|
27
|
+
levelFirst: true,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const jsonTransport = {
|
|
32
|
+
target: 'pino/file',
|
|
33
|
+
options: {
|
|
34
|
+
destination: 1,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const consoleTransport = env.LOGGER_FORMAT === 'json' ? jsonTransport : pinoPrettyTransport;
|
|
39
|
+
|
|
40
|
+
// biome-ignore lint/suspicious/noExplicitAny: poor typings from pino
|
|
41
|
+
let transports: any;
|
|
42
|
+
|
|
43
|
+
// Configure transports based on OTEL endpoint availability
|
|
44
|
+
if (env.OTEL_EXPORTER_OTLP_ENDPOINT) {
|
|
45
|
+
console.info('node-logger: Using console and OpenTelemetry transports');
|
|
46
|
+
transports = pino.transport({
|
|
47
|
+
targets: [openTelemetryTransport, consoleTransport],
|
|
48
|
+
});
|
|
49
|
+
} else {
|
|
50
|
+
console.info('node-logger: Using console transport only');
|
|
51
|
+
transports = pino.transport(consoleTransport);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const pinoLogger = pino({ level: env.LOG_LEVEL }, transports);
|
|
55
|
+
|
|
56
|
+
export const createContextLogger = (context: Record<string | number | symbol, unknown>) => {
|
|
57
|
+
const child = pinoLogger.child(context);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
trace: child.trace.bind(child),
|
|
61
|
+
debug: child.debug.bind(child),
|
|
62
|
+
info: child.info.bind(child),
|
|
63
|
+
warn: child.warn.bind(child),
|
|
64
|
+
error: child.error.bind(child),
|
|
65
|
+
fatal: child.fatal.bind(child),
|
|
66
|
+
silent: child.silent.bind(child),
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
if (env.TEST_LOGGING) {
|
|
71
|
+
pinoLogger.debug('Debug test');
|
|
72
|
+
pinoLogger.trace('Trace test');
|
|
73
|
+
pinoLogger.info({ some: 'object' }, 'Info test');
|
|
74
|
+
pinoLogger.warn('Consider this a warning');
|
|
75
|
+
pinoLogger.error(new Error('Test error'), 'Error test');
|
|
76
|
+
pinoLogger.fatal(new Error('Test error'), 'Fatal test');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const logger = {
|
|
80
|
+
trace: pinoLogger.trace.bind(pinoLogger),
|
|
81
|
+
debug: pinoLogger.debug.bind(pinoLogger),
|
|
82
|
+
info: pinoLogger.info.bind(pinoLogger),
|
|
83
|
+
warn: pinoLogger.warn.bind(pinoLogger),
|
|
84
|
+
error: pinoLogger.error.bind(pinoLogger),
|
|
85
|
+
fatal: pinoLogger.fatal.bind(pinoLogger),
|
|
86
|
+
silent: pinoLogger.silent.bind(pinoLogger),
|
|
87
|
+
pinoLoggerInstance: pinoLogger,
|
|
88
|
+
};
|