@nicomatic/logger 0.0.0-stage → 0.1.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 -2
- package/dist/index.cjs +67 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +49 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -4
- package/schemas/examples/invalid/bad-timestamp.json +9 -0
- package/schemas/examples/invalid/forbidden-header.json +17 -0
- package/schemas/examples/invalid/missing-required-fields.json +6 -0
- package/schemas/examples/invalid/missing-schema-version.json +8 -0
- package/schemas/examples/invalid/unknown-level.json +9 -0
- package/schemas/examples/valid/diagnostic-body-redacted.json +33 -0
- package/schemas/examples/valid/error-with-stack.json +27 -0
- package/schemas/examples/valid/login-redacted.json +22 -0
- package/schemas/examples/valid/message-only.json +9 -0
- package/schemas/examples/valid/request-completed.json +36 -0
- package/schemas/log-event.schema.json +157 -0
package/README.md
CHANGED
|
@@ -1,3 +1,56 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@nicomatic/logger`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Package npm de logging JSON unifié pour les services Nicomatic (JS/TS).
|
|
4
|
+
|
|
5
|
+
Prérequis consommateur : **Node.js ≥ 20**.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @nicomatic/logger
|
|
11
|
+
# ou : npm install @nicomatic/logger
|
|
12
|
+
# ou : yarn add @nicomatic/logger
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Package **public** sur [npmjs](https://www.npmjs.com/) (scope `@nicomatic`).
|
|
16
|
+
|
|
17
|
+
## Publication (maintainers)
|
|
18
|
+
|
|
19
|
+
Prérequis : compte npm membre de l’org `@nicomatic`, puis `npm login`.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
just check
|
|
23
|
+
npm publish
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Développement
|
|
27
|
+
|
|
28
|
+
Prérequis : [Nix](https://nixos.org/) (flakes). Optionnel : [direnv](https://direnv.net/) + [nix-direnv](https://github.com/nix-community/nix-direnv) pour entrer automatiquement dans le shell.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
direnv allow # une fois, si direnv est installé
|
|
32
|
+
# sinon : nix develop
|
|
33
|
+
just setup
|
|
34
|
+
just check # test + typecheck + build
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## API minimale
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { createLogger } from "@nicomatic/logger";
|
|
41
|
+
|
|
42
|
+
const log = createLogger({
|
|
43
|
+
service: "app-web",
|
|
44
|
+
env: "dev",
|
|
45
|
+
version: "0.1.0",
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
log.info({ message: "hello", traceId: "abc" });
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Spec (M1)
|
|
52
|
+
|
|
53
|
+
- Schéma JSON : [`schemas/log-event.schema.json`](schemas/log-event.schema.json)
|
|
54
|
+
- Exemples : [`schemas/examples/`](schemas/examples/)
|
|
55
|
+
- ADR format : [`docs/adr/0001-format-de-log-unifie.md`](docs/adr/0001-format-de-log-unifie.md)
|
|
56
|
+
- ADR RGPD / sécurité (NMTC-106) : [`docs/adr/0002-rgpd-securite-capture-logs.md`](docs/adr/0002-rgpd-securite-capture-logs.md)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
createLogger: () => createLogger
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
var SCHEMA_VERSION = "1.0";
|
|
27
|
+
function normalizeFields(input) {
|
|
28
|
+
if (typeof input === "string") {
|
|
29
|
+
return { message: input };
|
|
30
|
+
}
|
|
31
|
+
return input;
|
|
32
|
+
}
|
|
33
|
+
function createLogger(options, bindings = {}) {
|
|
34
|
+
const logAt = (level) => (input) => {
|
|
35
|
+
const fields = normalizeFields(input);
|
|
36
|
+
const { message, level: _ignoredLevel, ...rest } = fields;
|
|
37
|
+
const event = {
|
|
38
|
+
schemaVersion: SCHEMA_VERSION,
|
|
39
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
40
|
+
level,
|
|
41
|
+
service: options.service,
|
|
42
|
+
env: options.env,
|
|
43
|
+
version: options.version,
|
|
44
|
+
message,
|
|
45
|
+
...bindings,
|
|
46
|
+
...rest
|
|
47
|
+
};
|
|
48
|
+
process.stdout.write(`${JSON.stringify(event)}
|
|
49
|
+
`);
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
trace: logAt("trace"),
|
|
53
|
+
debug: logAt("debug"),
|
|
54
|
+
info: logAt("info"),
|
|
55
|
+
warn: logAt("warn"),
|
|
56
|
+
error: logAt("error"),
|
|
57
|
+
fatal: logAt("fatal"),
|
|
58
|
+
child(childBindings) {
|
|
59
|
+
return createLogger(options, { ...bindings, ...childBindings });
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
64
|
+
0 && (module.exports = {
|
|
65
|
+
createLogger
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type {\n CreateLoggerOptions,\n LogFields,\n LogLevel,\n Logger,\n} from \"./types.js\";\n\nexport type {\n CreateLoggerOptions,\n LogError,\n LogFields,\n LogLevel,\n LogRequest,\n LogResponse,\n Logger,\n} from \"./types.js\";\n\nconst SCHEMA_VERSION = \"1.0\";\n\nfunction normalizeFields(input: LogFields | string): LogFields {\n if (typeof input === \"string\") {\n return { message: input };\n }\n return input;\n}\n\nexport function createLogger(\n options: CreateLoggerOptions,\n bindings: Record<string, unknown> = {},\n): Logger {\n const logAt =\n (level: LogLevel) =>\n (input: LogFields | string): void => {\n const fields = normalizeFields(input);\n const { message, level: _ignoredLevel, ...rest } = fields;\n\n const event = {\n schemaVersion: SCHEMA_VERSION,\n timestamp: new Date().toISOString(),\n level,\n service: options.service,\n env: options.env,\n version: options.version,\n message,\n ...bindings,\n ...rest,\n };\n\n process.stdout.write(`${JSON.stringify(event)}\\n`);\n };\n\n return {\n trace: logAt(\"trace\"),\n debug: logAt(\"debug\"),\n info: logAt(\"info\"),\n warn: logAt(\"warn\"),\n error: logAt(\"error\"),\n fatal: logAt(\"fatal\"),\n child(childBindings: Record<string, unknown>): Logger {\n return createLogger(options, { ...bindings, ...childBindings });\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA,IAAM,iBAAiB;AAEvB,SAAS,gBAAgB,OAAsC;AAC7D,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,EAAE,SAAS,MAAM;AAAA,EAC1B;AACA,SAAO;AACT;AAEO,SAAS,aACd,SACA,WAAoC,CAAC,GAC7B;AACR,QAAM,QACJ,CAAC,UACD,CAAC,UAAoC;AACnC,UAAM,SAAS,gBAAgB,KAAK;AACpC,UAAM,EAAE,SAAS,OAAO,eAAe,GAAG,KAAK,IAAI;AAEnD,UAAM,QAAQ;AAAA,MACZ,eAAe;AAAA,MACf,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC;AAAA,MACA,SAAS,QAAQ;AAAA,MACjB,KAAK,QAAQ;AAAA,MACb,SAAS,QAAQ;AAAA,MACjB;AAAA,MACA,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAEA,YAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA,CAAI;AAAA,EACnD;AAEF,SAAO;AAAA,IACL,OAAO,MAAM,OAAO;AAAA,IACpB,OAAO,MAAM,OAAO;AAAA,IACpB,MAAM,MAAM,MAAM;AAAA,IAClB,MAAM,MAAM,MAAM;AAAA,IAClB,OAAO,MAAM,OAAO;AAAA,IACpB,OAAO,MAAM,OAAO;AAAA,IACpB,MAAM,eAAgD;AACpD,aAAO,aAAa,SAAS,EAAE,GAAG,UAAU,GAAG,cAAc,CAAC;AAAA,IAChE;AAAA,EACF;AACF;","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal";
|
|
2
|
+
type CreateLoggerOptions = {
|
|
3
|
+
service: string;
|
|
4
|
+
env: string;
|
|
5
|
+
version: string;
|
|
6
|
+
};
|
|
7
|
+
type LogRequest = {
|
|
8
|
+
method?: string;
|
|
9
|
+
url?: string;
|
|
10
|
+
status?: number;
|
|
11
|
+
durationMs?: number;
|
|
12
|
+
userId?: string;
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
body?: unknown;
|
|
15
|
+
bodyTruncated?: boolean;
|
|
16
|
+
};
|
|
17
|
+
type LogResponse = {
|
|
18
|
+
body?: unknown;
|
|
19
|
+
};
|
|
20
|
+
type LogError = {
|
|
21
|
+
type?: string;
|
|
22
|
+
message?: string;
|
|
23
|
+
stack?: string;
|
|
24
|
+
code?: string | number;
|
|
25
|
+
cause?: unknown;
|
|
26
|
+
};
|
|
27
|
+
type LogFields = {
|
|
28
|
+
message: string;
|
|
29
|
+
level?: LogLevel;
|
|
30
|
+
traceId?: string;
|
|
31
|
+
correlationId?: string;
|
|
32
|
+
request?: LogRequest;
|
|
33
|
+
response?: LogResponse;
|
|
34
|
+
error?: LogError | null;
|
|
35
|
+
[key: string]: unknown;
|
|
36
|
+
};
|
|
37
|
+
type Logger = {
|
|
38
|
+
trace: (fields: LogFields | string) => void;
|
|
39
|
+
debug: (fields: LogFields | string) => void;
|
|
40
|
+
info: (fields: LogFields | string) => void;
|
|
41
|
+
warn: (fields: LogFields | string) => void;
|
|
42
|
+
error: (fields: LogFields | string) => void;
|
|
43
|
+
fatal: (fields: LogFields | string) => void;
|
|
44
|
+
child: (bindings: Record<string, unknown>) => Logger;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
declare function createLogger(options: CreateLoggerOptions, bindings?: Record<string, unknown>): Logger;
|
|
48
|
+
|
|
49
|
+
export { type CreateLoggerOptions, type LogError, type LogFields, type LogLevel, type LogRequest, type LogResponse, type Logger, createLogger };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal";
|
|
2
|
+
type CreateLoggerOptions = {
|
|
3
|
+
service: string;
|
|
4
|
+
env: string;
|
|
5
|
+
version: string;
|
|
6
|
+
};
|
|
7
|
+
type LogRequest = {
|
|
8
|
+
method?: string;
|
|
9
|
+
url?: string;
|
|
10
|
+
status?: number;
|
|
11
|
+
durationMs?: number;
|
|
12
|
+
userId?: string;
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
body?: unknown;
|
|
15
|
+
bodyTruncated?: boolean;
|
|
16
|
+
};
|
|
17
|
+
type LogResponse = {
|
|
18
|
+
body?: unknown;
|
|
19
|
+
};
|
|
20
|
+
type LogError = {
|
|
21
|
+
type?: string;
|
|
22
|
+
message?: string;
|
|
23
|
+
stack?: string;
|
|
24
|
+
code?: string | number;
|
|
25
|
+
cause?: unknown;
|
|
26
|
+
};
|
|
27
|
+
type LogFields = {
|
|
28
|
+
message: string;
|
|
29
|
+
level?: LogLevel;
|
|
30
|
+
traceId?: string;
|
|
31
|
+
correlationId?: string;
|
|
32
|
+
request?: LogRequest;
|
|
33
|
+
response?: LogResponse;
|
|
34
|
+
error?: LogError | null;
|
|
35
|
+
[key: string]: unknown;
|
|
36
|
+
};
|
|
37
|
+
type Logger = {
|
|
38
|
+
trace: (fields: LogFields | string) => void;
|
|
39
|
+
debug: (fields: LogFields | string) => void;
|
|
40
|
+
info: (fields: LogFields | string) => void;
|
|
41
|
+
warn: (fields: LogFields | string) => void;
|
|
42
|
+
error: (fields: LogFields | string) => void;
|
|
43
|
+
fatal: (fields: LogFields | string) => void;
|
|
44
|
+
child: (bindings: Record<string, unknown>) => Logger;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
declare function createLogger(options: CreateLoggerOptions, bindings?: Record<string, unknown>): Logger;
|
|
48
|
+
|
|
49
|
+
export { type CreateLoggerOptions, type LogError, type LogFields, type LogLevel, type LogRequest, type LogResponse, type Logger, createLogger };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var SCHEMA_VERSION = "1.0";
|
|
3
|
+
function normalizeFields(input) {
|
|
4
|
+
if (typeof input === "string") {
|
|
5
|
+
return { message: input };
|
|
6
|
+
}
|
|
7
|
+
return input;
|
|
8
|
+
}
|
|
9
|
+
function createLogger(options, bindings = {}) {
|
|
10
|
+
const logAt = (level) => (input) => {
|
|
11
|
+
const fields = normalizeFields(input);
|
|
12
|
+
const { message, level: _ignoredLevel, ...rest } = fields;
|
|
13
|
+
const event = {
|
|
14
|
+
schemaVersion: SCHEMA_VERSION,
|
|
15
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16
|
+
level,
|
|
17
|
+
service: options.service,
|
|
18
|
+
env: options.env,
|
|
19
|
+
version: options.version,
|
|
20
|
+
message,
|
|
21
|
+
...bindings,
|
|
22
|
+
...rest
|
|
23
|
+
};
|
|
24
|
+
process.stdout.write(`${JSON.stringify(event)}
|
|
25
|
+
`);
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
trace: logAt("trace"),
|
|
29
|
+
debug: logAt("debug"),
|
|
30
|
+
info: logAt("info"),
|
|
31
|
+
warn: logAt("warn"),
|
|
32
|
+
error: logAt("error"),
|
|
33
|
+
fatal: logAt("fatal"),
|
|
34
|
+
child(childBindings) {
|
|
35
|
+
return createLogger(options, { ...bindings, ...childBindings });
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
createLogger
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type {\n CreateLoggerOptions,\n LogFields,\n LogLevel,\n Logger,\n} from \"./types.js\";\n\nexport type {\n CreateLoggerOptions,\n LogError,\n LogFields,\n LogLevel,\n LogRequest,\n LogResponse,\n Logger,\n} from \"./types.js\";\n\nconst SCHEMA_VERSION = \"1.0\";\n\nfunction normalizeFields(input: LogFields | string): LogFields {\n if (typeof input === \"string\") {\n return { message: input };\n }\n return input;\n}\n\nexport function createLogger(\n options: CreateLoggerOptions,\n bindings: Record<string, unknown> = {},\n): Logger {\n const logAt =\n (level: LogLevel) =>\n (input: LogFields | string): void => {\n const fields = normalizeFields(input);\n const { message, level: _ignoredLevel, ...rest } = fields;\n\n const event = {\n schemaVersion: SCHEMA_VERSION,\n timestamp: new Date().toISOString(),\n level,\n service: options.service,\n env: options.env,\n version: options.version,\n message,\n ...bindings,\n ...rest,\n };\n\n process.stdout.write(`${JSON.stringify(event)}\\n`);\n };\n\n return {\n trace: logAt(\"trace\"),\n debug: logAt(\"debug\"),\n info: logAt(\"info\"),\n warn: logAt(\"warn\"),\n error: logAt(\"error\"),\n fatal: logAt(\"fatal\"),\n child(childBindings: Record<string, unknown>): Logger {\n return createLogger(options, { ...bindings, ...childBindings });\n },\n };\n}\n"],"mappings":";AAiBA,IAAM,iBAAiB;AAEvB,SAAS,gBAAgB,OAAsC;AAC7D,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,EAAE,SAAS,MAAM;AAAA,EAC1B;AACA,SAAO;AACT;AAEO,SAAS,aACd,SACA,WAAoC,CAAC,GAC7B;AACR,QAAM,QACJ,CAAC,UACD,CAAC,UAAoC;AACnC,UAAM,SAAS,gBAAgB,KAAK;AACpC,UAAM,EAAE,SAAS,OAAO,eAAe,GAAG,KAAK,IAAI;AAEnD,UAAM,QAAQ;AAAA,MACZ,eAAe;AAAA,MACf,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC;AAAA,MACA,SAAS,QAAQ;AAAA,MACjB,KAAK,QAAQ;AAAA,MACb,SAAS,QAAQ;AAAA,MACjB;AAAA,MACA,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAEA,YAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA,CAAI;AAAA,EACnD;AAEF,SAAO;AAAA,IACL,OAAO,MAAM,OAAO;AAAA,IACpB,OAAO,MAAM,OAAO;AAAA,IACpB,MAAM,MAAM,MAAM;AAAA,IAClB,MAAM,MAAM,MAAM;AAAA,IAClB,OAAO,MAAM,OAAO;AAAA,IACpB,OAAO,MAAM,OAAO;AAAA,IACpB,MAAM,eAAgD;AACpD,aAAO,aAAa,SAAS,EAAE,GAAG,UAAU,GAAG,cAAc,CAAC;AAAA,IAChE;AAAA,EACF;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nicomatic/logger",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Logger JSON unifié pour les services Nicomatic (JS/TS)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"schemas"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=20"
|
|
28
|
+
},
|
|
29
|
+
"license": "UNLICENSED",
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public",
|
|
32
|
+
"registry": "https://registry.npmjs.org/"
|
|
33
|
+
},
|
|
34
|
+
"pnpm": {
|
|
35
|
+
"onlyBuiltDependencies": ["esbuild"]
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^22.13.10",
|
|
39
|
+
"ajv": "^8.17.1",
|
|
40
|
+
"ajv-formats": "^3.0.1",
|
|
41
|
+
"tsup": "^8.4.0",
|
|
42
|
+
"typescript": "^5.8.2",
|
|
43
|
+
"vitest": "^3.0.8"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0",
|
|
3
|
+
"timestamp": "2026-10-30T22:15:03.512Z",
|
|
4
|
+
"level": "info",
|
|
5
|
+
"service": "app-web",
|
|
6
|
+
"env": "prod",
|
|
7
|
+
"version": "2.4.1",
|
|
8
|
+
"message": "request completed",
|
|
9
|
+
"request": {
|
|
10
|
+
"method": "POST",
|
|
11
|
+
"url": "/api/orders",
|
|
12
|
+
"status": 201,
|
|
13
|
+
"headers": {
|
|
14
|
+
"authorization": "Bearer secret-token"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0",
|
|
3
|
+
"timestamp": "2026-11-07T18:05:00.000Z",
|
|
4
|
+
"level": "error",
|
|
5
|
+
"service": "app-web",
|
|
6
|
+
"env": "prod",
|
|
7
|
+
"version": "2.4.1",
|
|
8
|
+
"message": "request failed",
|
|
9
|
+
"traceId": "6d014f5799d56fc8c5e0141f2a2a6958",
|
|
10
|
+
"request": {
|
|
11
|
+
"method": "POST",
|
|
12
|
+
"url": "/api/profile",
|
|
13
|
+
"status": 500,
|
|
14
|
+
"durationMs": 120,
|
|
15
|
+
"userId": "u_5678",
|
|
16
|
+
"headers": {
|
|
17
|
+
"content-type": "application/json",
|
|
18
|
+
"user-agent": "Mozilla/5.0"
|
|
19
|
+
},
|
|
20
|
+
"body": {
|
|
21
|
+
"displayName": "Ada",
|
|
22
|
+
"email": "[REDACTED]",
|
|
23
|
+
"password": "[REDACTED]",
|
|
24
|
+
"token": "[REDACTED]"
|
|
25
|
+
},
|
|
26
|
+
"bodyTruncated": false
|
|
27
|
+
},
|
|
28
|
+
"error": {
|
|
29
|
+
"type": "InternalServerError",
|
|
30
|
+
"message": "unexpected failure",
|
|
31
|
+
"code": 500
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0",
|
|
3
|
+
"timestamp": "2026-10-30T22:16:11.004Z",
|
|
4
|
+
"level": "error",
|
|
5
|
+
"service": "app-web",
|
|
6
|
+
"env": "prod",
|
|
7
|
+
"version": "2.4.1",
|
|
8
|
+
"message": "unhandled exception",
|
|
9
|
+
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
|
|
10
|
+
"correlationId": "c0a8012e-7f3d-4a8b-9b1e-2f6d5c3e9a10",
|
|
11
|
+
"request": {
|
|
12
|
+
"method": "GET",
|
|
13
|
+
"url": "/api/orders/O-5521",
|
|
14
|
+
"status": 500,
|
|
15
|
+
"durationMs": 18
|
|
16
|
+
},
|
|
17
|
+
"error": {
|
|
18
|
+
"type": "Error",
|
|
19
|
+
"message": "database connection refused",
|
|
20
|
+
"stack": "Error: database connection refused\n at Query.run (db.js:10:5)",
|
|
21
|
+
"code": "ECONNREFUSED",
|
|
22
|
+
"cause": {
|
|
23
|
+
"type": "Error",
|
|
24
|
+
"message": "connect ECONNREFUSED 127.0.0.1:5432"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0",
|
|
3
|
+
"timestamp": "2026-11-07T18:00:00.000Z",
|
|
4
|
+
"level": "info",
|
|
5
|
+
"service": "auth-api",
|
|
6
|
+
"env": "prod",
|
|
7
|
+
"version": "1.2.0",
|
|
8
|
+
"message": "login attempt completed",
|
|
9
|
+
"traceId": "5cf03e4688c45eb7b4df030e1f1f5847",
|
|
10
|
+
"correlationId": "login-req-9f2a",
|
|
11
|
+
"request": {
|
|
12
|
+
"method": "POST",
|
|
13
|
+
"url": "/auth/login",
|
|
14
|
+
"status": 401,
|
|
15
|
+
"durationMs": 18,
|
|
16
|
+
"headers": {
|
|
17
|
+
"content-type": "application/json",
|
|
18
|
+
"user-agent": "Mozilla/5.0"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"error": null
|
|
22
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0",
|
|
3
|
+
"timestamp": "2026-10-30T22:15:03.512Z",
|
|
4
|
+
"level": "info",
|
|
5
|
+
"service": "app-web",
|
|
6
|
+
"env": "prod",
|
|
7
|
+
"version": "2.4.1",
|
|
8
|
+
"message": "request completed",
|
|
9
|
+
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
|
|
10
|
+
"correlationId": "c0a8012e-7f3d-4a8b-9b1e-2f6d5c3e9a10",
|
|
11
|
+
"request": {
|
|
12
|
+
"method": "POST",
|
|
13
|
+
"url": "/api/orders",
|
|
14
|
+
"status": 201,
|
|
15
|
+
"durationMs": 42,
|
|
16
|
+
"userId": "u_1234",
|
|
17
|
+
"headers": {
|
|
18
|
+
"user-agent": "Mozilla/5.0",
|
|
19
|
+
"content-type": "application/json"
|
|
20
|
+
},
|
|
21
|
+
"body": {
|
|
22
|
+
"productId": "P-88",
|
|
23
|
+
"quantity": 3,
|
|
24
|
+
"customer": {
|
|
25
|
+
"email": "[REDACTED]"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"bodyTruncated": false
|
|
29
|
+
},
|
|
30
|
+
"response": {
|
|
31
|
+
"body": {
|
|
32
|
+
"orderId": "O-5521"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"error": null
|
|
36
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://nicomatic.local/schemas/log-event.schema.json",
|
|
4
|
+
"title": "Nicomatic unified log event",
|
|
5
|
+
"description": "Format JSON unifié des logs Nicomatic (schemaVersion 1.0). Voir docs/adr/0001-format-de-log-unifie.md.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": true,
|
|
8
|
+
"required": [
|
|
9
|
+
"schemaVersion",
|
|
10
|
+
"timestamp",
|
|
11
|
+
"level",
|
|
12
|
+
"service",
|
|
13
|
+
"env",
|
|
14
|
+
"version",
|
|
15
|
+
"message"
|
|
16
|
+
],
|
|
17
|
+
"properties": {
|
|
18
|
+
"schemaVersion": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"const": "1.0",
|
|
21
|
+
"description": "Version du schéma de log (majeur.mineur)."
|
|
22
|
+
},
|
|
23
|
+
"timestamp": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"format": "date-time",
|
|
26
|
+
"description": "Horodatage ISO 8601 en UTC (ex. 2026-10-30T22:15:03.512Z)."
|
|
27
|
+
},
|
|
28
|
+
"level": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"enum": ["trace", "debug", "info", "warn", "error", "fatal"]
|
|
31
|
+
},
|
|
32
|
+
"service": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"minLength": 1,
|
|
35
|
+
"description": "Identifiant du service émetteur (label Loki)."
|
|
36
|
+
},
|
|
37
|
+
"env": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"minLength": 1,
|
|
40
|
+
"description": "Environnement (ex. dev, staging, prod) — label Loki."
|
|
41
|
+
},
|
|
42
|
+
"version": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"minLength": 1,
|
|
45
|
+
"description": "Version déployée du service."
|
|
46
|
+
},
|
|
47
|
+
"message": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"description": "Message humain court décrivant l'événement."
|
|
50
|
+
},
|
|
51
|
+
"traceId": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"minLength": 1,
|
|
54
|
+
"description": "Identifiant de trace (W3C trace-id ou équivalent)."
|
|
55
|
+
},
|
|
56
|
+
"correlationId": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"minLength": 1,
|
|
59
|
+
"description": "Identifiant de corrélation métier / requête."
|
|
60
|
+
},
|
|
61
|
+
"request": {
|
|
62
|
+
"$ref": "#/$defs/request"
|
|
63
|
+
},
|
|
64
|
+
"response": {
|
|
65
|
+
"$ref": "#/$defs/response"
|
|
66
|
+
},
|
|
67
|
+
"error": {
|
|
68
|
+
"oneOf": [
|
|
69
|
+
{ "type": "null" },
|
|
70
|
+
{ "$ref": "#/$defs/error" }
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"$defs": {
|
|
75
|
+
"request": {
|
|
76
|
+
"type": "object",
|
|
77
|
+
"additionalProperties": false,
|
|
78
|
+
"properties": {
|
|
79
|
+
"method": {
|
|
80
|
+
"type": "string",
|
|
81
|
+
"minLength": 1
|
|
82
|
+
},
|
|
83
|
+
"url": {
|
|
84
|
+
"type": "string",
|
|
85
|
+
"minLength": 1
|
|
86
|
+
},
|
|
87
|
+
"status": {
|
|
88
|
+
"type": "integer",
|
|
89
|
+
"minimum": 100,
|
|
90
|
+
"maximum": 599
|
|
91
|
+
},
|
|
92
|
+
"durationMs": {
|
|
93
|
+
"type": "number",
|
|
94
|
+
"minimum": 0
|
|
95
|
+
},
|
|
96
|
+
"userId": {
|
|
97
|
+
"type": "string"
|
|
98
|
+
},
|
|
99
|
+
"headers": {
|
|
100
|
+
"type": "object",
|
|
101
|
+
"description": "Headers en liste blanche uniquement (jamais Authorization, Cookie, Set-Cookie).",
|
|
102
|
+
"additionalProperties": {
|
|
103
|
+
"type": "string"
|
|
104
|
+
},
|
|
105
|
+
"propertyNames": {
|
|
106
|
+
"enum": [
|
|
107
|
+
"accept",
|
|
108
|
+
"accept-language",
|
|
109
|
+
"content-type",
|
|
110
|
+
"content-length",
|
|
111
|
+
"user-agent",
|
|
112
|
+
"x-request-id",
|
|
113
|
+
"x-forwarded-for",
|
|
114
|
+
"x-forwarded-proto",
|
|
115
|
+
"x-correlation-id",
|
|
116
|
+
"traceparent",
|
|
117
|
+
"tracestate"
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"body": true,
|
|
122
|
+
"bodyTruncated": {
|
|
123
|
+
"type": "boolean"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"response": {
|
|
128
|
+
"type": "object",
|
|
129
|
+
"additionalProperties": false,
|
|
130
|
+
"properties": {
|
|
131
|
+
"body": true
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"error": {
|
|
135
|
+
"type": "object",
|
|
136
|
+
"additionalProperties": true,
|
|
137
|
+
"properties": {
|
|
138
|
+
"type": {
|
|
139
|
+
"type": "string"
|
|
140
|
+
},
|
|
141
|
+
"message": {
|
|
142
|
+
"type": "string"
|
|
143
|
+
},
|
|
144
|
+
"stack": {
|
|
145
|
+
"type": "string"
|
|
146
|
+
},
|
|
147
|
+
"code": {
|
|
148
|
+
"oneOf": [
|
|
149
|
+
{ "type": "string" },
|
|
150
|
+
{ "type": "number" }
|
|
151
|
+
]
|
|
152
|
+
},
|
|
153
|
+
"cause": true
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|