@webpieces/bunyan 0.3.313 → 0.3.316
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/package.json +3 -2
- package/src/BunyanConsoleFactory.d.ts +1 -5
- package/src/BunyanConsoleFactory.js +2 -6
- package/src/BunyanConsoleFactory.js.map +1 -1
- package/src/BunyanFactoryBase.d.ts +5 -5
- package/src/BunyanFactoryBase.js +5 -6
- package/src/BunyanFactoryBase.js.map +1 -1
- package/src/BunyanFactoryOptions.d.ts +7 -10
- package/src/BunyanFactoryOptions.js +6 -8
- package/src/BunyanFactoryOptions.js.map +1 -1
- package/src/BunyanGcpFactory.d.ts +5 -9
- package/src/BunyanGcpFactory.js +6 -10
- package/src/BunyanGcpFactory.js.map +1 -1
- package/src/BunyanLogger.d.ts +12 -9
- package/src/BunyanLogger.js +38 -18
- package/src/BunyanLogger.js.map +1 -1
- package/src/index.d.ts +8 -8
- package/src/index.js +8 -8
- package/src/index.js.map +1 -1
- package/src/streams.d.ts +9 -4
- package/src/streams.js +12 -6
- package/src/streams.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/bunyan",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.316",
|
|
4
4
|
"description": "Node-only bunyan LoggerFactory backends for webpieces: Console (local pretty) + GCP (@google-cloud/logging-bunyan), auto-enriched with HeaderRegistry context keys",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"access": "public"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@webpieces/core-util": "0.3.
|
|
26
|
+
"@webpieces/core-util": "0.3.316",
|
|
27
|
+
"@webpieces/core-context": "0.3.316",
|
|
27
28
|
"bunyan": "1.8.15",
|
|
28
29
|
"@google-cloud/logging-bunyan": "5.1.0",
|
|
29
30
|
"@types/bunyan": "1.8.11"
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ContextReader } from '@webpieces/core-util';
|
|
2
1
|
import { BunyanFactoryBase } from './BunyanFactoryBase';
|
|
3
2
|
import { BunyanFactoryOptions } from './BunyanFactoryOptions';
|
|
4
3
|
/**
|
|
@@ -6,10 +5,7 @@ import { BunyanFactoryOptions } from './BunyanFactoryOptions';
|
|
|
6
5
|
* text to stdout (`[LEVEL][time][ctx tags]: message`) with the registered context
|
|
7
6
|
* keys as tags — same enrichment as the GCP backend, different rendering. Mirrors
|
|
8
7
|
* the tested trytami local console stream.
|
|
9
|
-
*
|
|
10
|
-
* @param reader the environment's ContextReader (on a node server, a
|
|
11
|
-
* `RequestContextReader` from @webpieces/core-context).
|
|
12
8
|
*/
|
|
13
9
|
export declare class BunyanConsoleFactory extends BunyanFactoryBase {
|
|
14
|
-
constructor(
|
|
10
|
+
constructor(opts: BunyanFactoryOptions);
|
|
15
11
|
}
|
|
@@ -2,20 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BunyanConsoleFactory = void 0;
|
|
4
4
|
const BunyanFactoryBase_1 = require("./BunyanFactoryBase");
|
|
5
|
-
const BunyanFactoryOptions_1 = require("./BunyanFactoryOptions");
|
|
6
5
|
const streams_1 = require("./streams");
|
|
7
6
|
/**
|
|
8
7
|
* BunyanConsoleFactory - the LOCAL developer backend. Human-readable, greppable
|
|
9
8
|
* text to stdout (`[LEVEL][time][ctx tags]: message`) with the registered context
|
|
10
9
|
* keys as tags — same enrichment as the GCP backend, different rendering. Mirrors
|
|
11
10
|
* the tested trytami local console stream.
|
|
12
|
-
*
|
|
13
|
-
* @param reader the environment's ContextReader (on a node server, a
|
|
14
|
-
* `RequestContextReader` from @webpieces/core-context).
|
|
15
11
|
*/
|
|
16
12
|
class BunyanConsoleFactory extends BunyanFactoryBase_1.BunyanFactoryBase {
|
|
17
|
-
constructor(
|
|
18
|
-
super(
|
|
13
|
+
constructor(opts) {
|
|
14
|
+
super(opts.serviceName, [(0, streams_1.createConsoleStream)()]);
|
|
19
15
|
}
|
|
20
16
|
}
|
|
21
17
|
exports.BunyanConsoleFactory = BunyanConsoleFactory;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BunyanConsoleFactory.js","sourceRoot":"","sources":["../../../../../packages/logging/bunyan/src/BunyanConsoleFactory.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"BunyanConsoleFactory.js","sourceRoot":"","sources":["../../../../../packages/logging/bunyan/src/BunyanConsoleFactory.ts"],"names":[],"mappings":";;;AAAA,2DAAwD;AAExD,uCAAgD;AAEhD;;;;;GAKG;AACH,MAAa,oBAAqB,SAAQ,qCAAiB;IACvD,YAAY,IAA0B;QAClC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAA,6BAAmB,GAAE,CAAC,CAAC,CAAC;IACrD,CAAC;CACJ;AAJD,oDAIC","sourcesContent":["import { BunyanFactoryBase } from './BunyanFactoryBase';\nimport { BunyanFactoryOptions } from './BunyanFactoryOptions';\nimport { createConsoleStream } from './streams';\n\n/**\n * BunyanConsoleFactory - the LOCAL developer backend. Human-readable, greppable\n * text to stdout (`[LEVEL][time][ctx tags]: message`) with the registered context\n * keys as tags — same enrichment as the GCP backend, different rendering. Mirrors\n * the tested trytami local console stream.\n */\nexport class BunyanConsoleFactory extends BunyanFactoryBase {\n constructor(opts: BunyanFactoryOptions) {\n super(opts.serviceName, [createConsoleStream()]);\n }\n}\n"]}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import Logger from 'bunyan';
|
|
2
|
-
import type {
|
|
2
|
+
import type { Logger as WpLogger, LoggerFactory } from '@webpieces/core-util';
|
|
3
3
|
/**
|
|
4
4
|
* BunyanFactoryBase - shared plumbing for the bunyan {@link LoggerFactory}
|
|
5
5
|
* backends. Builds ONE underlying bunyan logger with the caller-chosen stream,
|
|
6
6
|
* then hands out a cached {@link BunyanLogger} per name (each a bunyan child
|
|
7
|
-
* carrying `loggerName
|
|
8
|
-
*
|
|
7
|
+
* carrying `loggerName`). Every logger reads the magic context DIRECTLY from
|
|
8
|
+
* RequestContext, so nothing is threaded through here. Subclasses differ only in
|
|
9
|
+
* the stream they pass up (GCP vs local console).
|
|
9
10
|
*/
|
|
10
11
|
export declare abstract class BunyanFactoryBase implements LoggerFactory {
|
|
11
|
-
private readonly reader;
|
|
12
12
|
private readonly base;
|
|
13
13
|
private readonly loggers;
|
|
14
|
-
protected constructor(
|
|
14
|
+
protected constructor(name: string, streams: Logger.Stream[]);
|
|
15
15
|
getLogger(name: string): WpLogger;
|
|
16
16
|
}
|
package/src/BunyanFactoryBase.js
CHANGED
|
@@ -8,21 +8,20 @@ const BunyanLogger_1 = require("./BunyanLogger");
|
|
|
8
8
|
* BunyanFactoryBase - shared plumbing for the bunyan {@link LoggerFactory}
|
|
9
9
|
* backends. Builds ONE underlying bunyan logger with the caller-chosen stream,
|
|
10
10
|
* then hands out a cached {@link BunyanLogger} per name (each a bunyan child
|
|
11
|
-
* carrying `loggerName
|
|
12
|
-
*
|
|
11
|
+
* carrying `loggerName`). Every logger reads the magic context DIRECTLY from
|
|
12
|
+
* RequestContext, so nothing is threaded through here. Subclasses differ only in
|
|
13
|
+
* the stream they pass up (GCP vs local console).
|
|
13
14
|
*/
|
|
14
15
|
class BunyanFactoryBase {
|
|
15
|
-
reader;
|
|
16
16
|
base;
|
|
17
17
|
loggers = new Map();
|
|
18
|
-
constructor(
|
|
19
|
-
this.reader = reader;
|
|
18
|
+
constructor(name, streams) {
|
|
20
19
|
this.base = bunyan_1.default.createLogger({ name, streams });
|
|
21
20
|
}
|
|
22
21
|
getLogger(name) {
|
|
23
22
|
let logger = this.loggers.get(name);
|
|
24
23
|
if (!logger) {
|
|
25
|
-
logger = new BunyanLogger_1.BunyanLogger(this.base.child({ loggerName: name })
|
|
24
|
+
logger = new BunyanLogger_1.BunyanLogger(this.base.child({ loggerName: name }));
|
|
26
25
|
this.loggers.set(name, logger);
|
|
27
26
|
}
|
|
28
27
|
return logger;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BunyanFactoryBase.js","sourceRoot":"","sources":["../../../../../packages/logging/bunyan/src/BunyanFactoryBase.ts"],"names":[],"mappings":";;;;AAAA,4DAA4B;AAE5B,iDAA8C;AAE9C
|
|
1
|
+
{"version":3,"file":"BunyanFactoryBase.js","sourceRoot":"","sources":["../../../../../packages/logging/bunyan/src/BunyanFactoryBase.ts"],"names":[],"mappings":";;;;AAAA,4DAA4B;AAE5B,iDAA8C;AAE9C;;;;;;;GAOG;AACH,MAAsB,iBAAiB;IAClB,IAAI,CAAS;IACb,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAEvD,YAAsB,IAAY,EAAE,OAAwB;QACxD,IAAI,CAAC,IAAI,GAAG,gBAAM,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,SAAS,CAAC,IAAY;QAClB,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,MAAM,GAAG,IAAI,2BAAY,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YACjE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ;AAhBD,8CAgBC","sourcesContent":["import Logger from 'bunyan';\nimport type { Logger as WpLogger, LoggerFactory } from '@webpieces/core-util';\nimport { BunyanLogger } from './BunyanLogger';\n\n/**\n * BunyanFactoryBase - shared plumbing for the bunyan {@link LoggerFactory}\n * backends. Builds ONE underlying bunyan logger with the caller-chosen stream,\n * then hands out a cached {@link BunyanLogger} per name (each a bunyan child\n * carrying `loggerName`). Every logger reads the magic context DIRECTLY from\n * RequestContext, so nothing is threaded through here. Subclasses differ only in\n * the stream they pass up (GCP vs local console).\n */\nexport abstract class BunyanFactoryBase implements LoggerFactory {\n private readonly base: Logger;\n private readonly loggers = new Map<string, WpLogger>();\n\n protected constructor(name: string, streams: Logger.Stream[]) {\n this.base = Logger.createLogger({ name, streams });\n }\n\n getLogger(name: string): WpLogger {\n let logger = this.loggers.get(name);\n if (!logger) {\n logger = new BunyanLogger(this.base.child({ loggerName: name }));\n this.loggers.set(name, logger);\n }\n return logger;\n }\n}\n"]}
|
|
@@ -1,24 +1,21 @@
|
|
|
1
|
-
import type { LogLevel } from '@webpieces/core-util';
|
|
2
1
|
/**
|
|
3
2
|
* BunyanFactoryOptions - tuning for the bunyan LoggerFactory backends.
|
|
4
3
|
*
|
|
5
|
-
* Data-only structure → a class, per CLAUDE.md.
|
|
6
|
-
*
|
|
4
|
+
* Data-only structure → a class, per CLAUDE.md.
|
|
5
|
+
*
|
|
6
|
+
* There is deliberately NO level knob: webpieces does not filter by level — that
|
|
7
|
+
* is bunyan's job (bunyan filters at its own default). You must name the service.
|
|
7
8
|
*/
|
|
8
9
|
export declare class BunyanFactoryOptions {
|
|
9
|
-
/** Minimum webpieces level to emit. Defaults to 'info'. */
|
|
10
|
-
readonly level: LogLevel;
|
|
11
10
|
/**
|
|
12
11
|
* The bunyan logger `name` (surfaces as `name` in Cloud Logging's JSON
|
|
13
|
-
* payload).
|
|
12
|
+
* payload). REQUIRED — every service names itself.
|
|
14
13
|
*/
|
|
15
14
|
readonly serviceName: string;
|
|
16
15
|
constructor(
|
|
17
|
-
/** Minimum webpieces level to emit. Defaults to 'info'. */
|
|
18
|
-
level?: LogLevel,
|
|
19
16
|
/**
|
|
20
17
|
* The bunyan logger `name` (surfaces as `name` in Cloud Logging's JSON
|
|
21
|
-
* payload).
|
|
18
|
+
* payload). REQUIRED — every service names itself.
|
|
22
19
|
*/
|
|
23
|
-
serviceName
|
|
20
|
+
serviceName: string);
|
|
24
21
|
}
|
|
@@ -4,21 +4,19 @@ exports.BunyanFactoryOptions = void 0;
|
|
|
4
4
|
/**
|
|
5
5
|
* BunyanFactoryOptions - tuning for the bunyan LoggerFactory backends.
|
|
6
6
|
*
|
|
7
|
-
* Data-only structure → a class, per CLAUDE.md.
|
|
8
|
-
*
|
|
7
|
+
* Data-only structure → a class, per CLAUDE.md.
|
|
8
|
+
*
|
|
9
|
+
* There is deliberately NO level knob: webpieces does not filter by level — that
|
|
10
|
+
* is bunyan's job (bunyan filters at its own default). You must name the service.
|
|
9
11
|
*/
|
|
10
12
|
class BunyanFactoryOptions {
|
|
11
|
-
level;
|
|
12
13
|
serviceName;
|
|
13
14
|
constructor(
|
|
14
|
-
/** Minimum webpieces level to emit. Defaults to 'info'. */
|
|
15
|
-
level = 'info',
|
|
16
15
|
/**
|
|
17
16
|
* The bunyan logger `name` (surfaces as `name` in Cloud Logging's JSON
|
|
18
|
-
* payload).
|
|
17
|
+
* payload). REQUIRED — every service names itself.
|
|
19
18
|
*/
|
|
20
|
-
serviceName
|
|
21
|
-
this.level = level;
|
|
19
|
+
serviceName) {
|
|
22
20
|
this.serviceName = serviceName;
|
|
23
21
|
}
|
|
24
22
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BunyanFactoryOptions.js","sourceRoot":"","sources":["../../../../../packages/logging/bunyan/src/BunyanFactoryOptions.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"BunyanFactoryOptions.js","sourceRoot":"","sources":["../../../../../packages/logging/bunyan/src/BunyanFactoryOptions.ts"],"names":[],"mappings":";;;AAAA;;;;;;;GAOG;AACH,MAAa,oBAAoB;IAMT;IALpB;IACI;;;OAGG;IACa,WAAmB;QAAnB,gBAAW,GAAX,WAAW,CAAQ;IACpC,CAAC;CACP;AARD,oDAQC","sourcesContent":["/**\n * BunyanFactoryOptions - tuning for the bunyan LoggerFactory backends.\n *\n * Data-only structure → a class, per CLAUDE.md.\n *\n * There is deliberately NO level knob: webpieces does not filter by level — that\n * is bunyan's job (bunyan filters at its own default). You must name the service.\n */\nexport class BunyanFactoryOptions {\n constructor(\n /**\n * The bunyan logger `name` (surfaces as `name` in Cloud Logging's JSON\n * payload). REQUIRED — every service names itself.\n */\n public readonly serviceName: string,\n ) {}\n}\n"]}
|
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
import type { ContextReader } from '@webpieces/core-util';
|
|
2
1
|
import { BunyanFactoryBase } from './BunyanFactoryBase';
|
|
3
2
|
import { BunyanFactoryOptions } from './BunyanFactoryOptions';
|
|
4
3
|
/**
|
|
5
4
|
* BunyanGcpFactory - the GCP backend. Streams to Cloud Logging via
|
|
6
5
|
* @google-cloud/logging-bunyan (which owns the numeric-level→severity mapping,
|
|
7
|
-
* msg→message, trace/httpRequest fields).
|
|
8
|
-
* structured payload fields
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* @param reader the environment's ContextReader — on a node server pass
|
|
12
|
-
* `new RequestContextReader()` from @webpieces/core-context. Keeping it a
|
|
13
|
-
* constructor arg is why this package depends only on @webpieces/core-util.
|
|
6
|
+
* msg→message, trace/httpRequest fields). The logged context keys ride along as
|
|
7
|
+
* structured payload fields, read straight from RequestContext on each line. This
|
|
8
|
+
* matches the tested-in-GCP trytami service exactly. Requires GCP Application
|
|
9
|
+
* Default Credentials on the instance.
|
|
14
10
|
*/
|
|
15
11
|
export declare class BunyanGcpFactory extends BunyanFactoryBase {
|
|
16
|
-
constructor(
|
|
12
|
+
constructor(opts: BunyanFactoryOptions);
|
|
17
13
|
}
|
package/src/BunyanGcpFactory.js
CHANGED
|
@@ -2,22 +2,18 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BunyanGcpFactory = void 0;
|
|
4
4
|
const BunyanFactoryBase_1 = require("./BunyanFactoryBase");
|
|
5
|
-
const BunyanFactoryOptions_1 = require("./BunyanFactoryOptions");
|
|
6
5
|
const streams_1 = require("./streams");
|
|
7
6
|
/**
|
|
8
7
|
* BunyanGcpFactory - the GCP backend. Streams to Cloud Logging via
|
|
9
8
|
* @google-cloud/logging-bunyan (which owns the numeric-level→severity mapping,
|
|
10
|
-
* msg→message, trace/httpRequest fields).
|
|
11
|
-
* structured payload fields
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* @param reader the environment's ContextReader — on a node server pass
|
|
15
|
-
* `new RequestContextReader()` from @webpieces/core-context. Keeping it a
|
|
16
|
-
* constructor arg is why this package depends only on @webpieces/core-util.
|
|
9
|
+
* msg→message, trace/httpRequest fields). The logged context keys ride along as
|
|
10
|
+
* structured payload fields, read straight from RequestContext on each line. This
|
|
11
|
+
* matches the tested-in-GCP trytami service exactly. Requires GCP Application
|
|
12
|
+
* Default Credentials on the instance.
|
|
17
13
|
*/
|
|
18
14
|
class BunyanGcpFactory extends BunyanFactoryBase_1.BunyanFactoryBase {
|
|
19
|
-
constructor(
|
|
20
|
-
super(
|
|
15
|
+
constructor(opts) {
|
|
16
|
+
super(opts.serviceName, [(0, streams_1.createGoogleCloudStream)()]);
|
|
21
17
|
}
|
|
22
18
|
}
|
|
23
19
|
exports.BunyanGcpFactory = BunyanGcpFactory;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BunyanGcpFactory.js","sourceRoot":"","sources":["../../../../../packages/logging/bunyan/src/BunyanGcpFactory.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"BunyanGcpFactory.js","sourceRoot":"","sources":["../../../../../packages/logging/bunyan/src/BunyanGcpFactory.ts"],"names":[],"mappings":";;;AAAA,2DAAwD;AAExD,uCAAoD;AAEpD;;;;;;;GAOG;AACH,MAAa,gBAAiB,SAAQ,qCAAiB;IACnD,YAAY,IAA0B;QAClC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAA,iCAAuB,GAAE,CAAC,CAAC,CAAC;IACzD,CAAC;CACJ;AAJD,4CAIC","sourcesContent":["import { BunyanFactoryBase } from './BunyanFactoryBase';\nimport { BunyanFactoryOptions } from './BunyanFactoryOptions';\nimport { createGoogleCloudStream } from './streams';\n\n/**\n * BunyanGcpFactory - the GCP backend. Streams to Cloud Logging via\n * @google-cloud/logging-bunyan (which owns the numeric-level→severity mapping,\n * msg→message, trace/httpRequest fields). The logged context keys ride along as\n * structured payload fields, read straight from RequestContext on each line. This\n * matches the tested-in-GCP trytami service exactly. Requires GCP Application\n * Default Credentials on the instance.\n */\nexport class BunyanGcpFactory extends BunyanFactoryBase {\n constructor(opts: BunyanFactoryOptions) {\n super(opts.serviceName, [createGoogleCloudStream()]);\n }\n}\n"]}
|
package/src/BunyanLogger.d.ts
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import type Logger from 'bunyan';
|
|
2
|
-
import type {
|
|
2
|
+
import type { Logger as WpLogger } from '@webpieces/core-util';
|
|
3
3
|
/**
|
|
4
4
|
* BunyanLogger - a webpieces {@link WpLogger} backed by a bunyan logger (one per
|
|
5
|
-
* name, created as a bunyan child carrying `loggerName`). On every call it
|
|
6
|
-
* the logged HeaderRegistry
|
|
7
|
-
* values masked) into the bunyan fields object, and normalizes an optional
|
|
8
|
-
* into `err: { name, message, stack }` — matching the tested trytami AppLogger.
|
|
5
|
+
* name, created as a bunyan child carrying `loggerName`). On every call it reads
|
|
6
|
+
* the logged HeaderRegistry keys DIRECTLY from the active {@link RequestContext}
|
|
7
|
+
* (secured values masked) into the bunyan fields object, and normalizes an optional
|
|
8
|
+
* Error into `err: { name, message, stack }` — matching the tested trytami AppLogger.
|
|
9
9
|
* The GCP stream then serializes those fields into the structured log payload.
|
|
10
|
+
*
|
|
11
|
+
* This context-reading is INLINED here (and duplicated in the winston logger) on
|
|
12
|
+
* purpose: it must run ONLY when a bunyan/winston backend is installed, never for
|
|
13
|
+
* the plain ConsoleLogger — so it does not belong on RequestContext.
|
|
10
14
|
*/
|
|
11
15
|
export declare class BunyanLogger implements WpLogger {
|
|
12
16
|
private readonly bunyan;
|
|
13
|
-
private
|
|
14
|
-
|
|
15
|
-
private loggedKeys?;
|
|
16
|
-
constructor(bunyan: Logger, reader: ContextReader);
|
|
17
|
+
private reportedMissingContext;
|
|
18
|
+
constructor(bunyan: Logger);
|
|
17
19
|
trace(message: string, err?: Error): void;
|
|
18
20
|
debug(message: string, err?: Error): void;
|
|
19
21
|
info(message: string, err?: Error): void;
|
|
20
22
|
warn(message: string, err?: Error): void;
|
|
21
23
|
error(message: string, err?: Error): void;
|
|
22
24
|
private buildFields;
|
|
25
|
+
private reportMissingContextOnce;
|
|
23
26
|
}
|
package/src/BunyanLogger.js
CHANGED
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BunyanLogger = void 0;
|
|
4
4
|
const core_util_1 = require("@webpieces/core-util");
|
|
5
|
+
const core_context_1 = require("@webpieces/core-context");
|
|
5
6
|
const LoggedError_1 = require("./LoggedError");
|
|
7
|
+
// A log line with no active RequestContext = a missing request-wrapping server
|
|
8
|
+
// filter. We report that once (below), never on every line.
|
|
9
|
+
const MISSING_CONTEXT_MESSAGE = 'Log emitted OUTSIDE RequestContext.run(...) — every request must be wrapped in ' +
|
|
10
|
+
'RequestContext.run() by a server filter. That filter appears to be missing: correlation ' +
|
|
11
|
+
'fields (requestId, tenant, ...) will be absent from logs until it is added. Reported once.';
|
|
6
12
|
// Above this serialized size the error is truncated, so one giant stack can't
|
|
7
13
|
// blow up a log line (ported from the tested trytami AppLogger).
|
|
8
14
|
const MAX_ERR_SERIALIZED = 100_000;
|
|
@@ -21,20 +27,23 @@ function normalizeError(err) {
|
|
|
21
27
|
}
|
|
22
28
|
/**
|
|
23
29
|
* BunyanLogger - a webpieces {@link WpLogger} backed by a bunyan logger (one per
|
|
24
|
-
* name, created as a bunyan child carrying `loggerName`). On every call it
|
|
25
|
-
* the logged HeaderRegistry
|
|
26
|
-
* values masked) into the bunyan fields object, and normalizes an optional
|
|
27
|
-
* into `err: { name, message, stack }` — matching the tested trytami AppLogger.
|
|
30
|
+
* name, created as a bunyan child carrying `loggerName`). On every call it reads
|
|
31
|
+
* the logged HeaderRegistry keys DIRECTLY from the active {@link RequestContext}
|
|
32
|
+
* (secured values masked) into the bunyan fields object, and normalizes an optional
|
|
33
|
+
* Error into `err: { name, message, stack }` — matching the tested trytami AppLogger.
|
|
28
34
|
* The GCP stream then serializes those fields into the structured log payload.
|
|
35
|
+
*
|
|
36
|
+
* This context-reading is INLINED here (and duplicated in the winston logger) on
|
|
37
|
+
* purpose: it must run ONLY when a bunyan/winston backend is installed, never for
|
|
38
|
+
* the plain ConsoleLogger — so it does not belong on RequestContext.
|
|
29
39
|
*/
|
|
30
40
|
class BunyanLogger {
|
|
31
41
|
bunyan;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
constructor(bunyan
|
|
42
|
+
// One-shot latch (see MISSING_CONTEXT_MESSAGE) — flips true after the first
|
|
43
|
+
// out-of-context line so we report the missing filter exactly once, not per line.
|
|
44
|
+
reportedMissingContext = false;
|
|
45
|
+
constructor(bunyan) {
|
|
36
46
|
this.bunyan = bunyan;
|
|
37
|
-
this.reader = reader;
|
|
38
47
|
}
|
|
39
48
|
trace(message, err) {
|
|
40
49
|
this.bunyan.trace(this.buildFields(err), message);
|
|
@@ -51,22 +60,33 @@ class BunyanLogger {
|
|
|
51
60
|
error(message, err) {
|
|
52
61
|
this.bunyan.error(this.buildFields(err), message);
|
|
53
62
|
}
|
|
54
|
-
// Registry keys are read LAZILY (first log) — a LoggerFactory is built before
|
|
55
|
-
// setupRuntime calls HeaderRegistry.configure.
|
|
56
63
|
buildFields(err) {
|
|
57
|
-
if (!this.loggedKeys) {
|
|
58
|
-
this.loggedKeys = core_util_1.HeaderRegistry.get().getLoggedKeys();
|
|
59
|
-
}
|
|
60
64
|
const fields = {};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
fields
|
|
64
|
-
}
|
|
65
|
+
if (!core_context_1.RequestContext.isActive()) {
|
|
66
|
+
this.reportMissingContextOnce();
|
|
67
|
+
return fields;
|
|
68
|
+
}
|
|
69
|
+
// getLoggedKeys() already returns only isLogged keys (precomputed at configure()).
|
|
70
|
+
for (const key of core_util_1.HeaderRegistry.get().getLoggedKeys()) {
|
|
71
|
+
const value = core_context_1.RequestContext.getHeader(key);
|
|
72
|
+
if (value) {
|
|
73
|
+
fields[key.name] = key.maskIfSecured(value);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
65
76
|
if (err) {
|
|
66
77
|
fields['err'] = normalizeError(err);
|
|
67
78
|
}
|
|
68
79
|
return fields;
|
|
69
80
|
}
|
|
81
|
+
// Report the missing request-wrapping filter once. Uses the RAW bunyan logger
|
|
82
|
+
// (not buildFields()), so there is no re-entrancy — just a single extra line.
|
|
83
|
+
reportMissingContextOnce() {
|
|
84
|
+
if (this.reportedMissingContext) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this.reportedMissingContext = true;
|
|
88
|
+
this.bunyan.error(MISSING_CONTEXT_MESSAGE);
|
|
89
|
+
}
|
|
70
90
|
}
|
|
71
91
|
exports.BunyanLogger = BunyanLogger;
|
|
72
92
|
//# sourceMappingURL=BunyanLogger.js.map
|
package/src/BunyanLogger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BunyanLogger.js","sourceRoot":"","sources":["../../../../../packages/logging/bunyan/src/BunyanLogger.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"BunyanLogger.js","sourceRoot":"","sources":["../../../../../packages/logging/bunyan/src/BunyanLogger.ts"],"names":[],"mappings":"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","sourcesContent":["import type Logger from 'bunyan';\nimport type { Logger as WpLogger } from '@webpieces/core-util';\nimport { HeaderRegistry } from '@webpieces/core-util';\nimport { RequestContext } from '@webpieces/core-context';\nimport { LoggedError } from './LoggedError';\n\n// A log line with no active RequestContext = a missing request-wrapping server\n// filter. We report that once (below), never on every line.\nconst MISSING_CONTEXT_MESSAGE =\n 'Log emitted OUTSIDE RequestContext.run(...) — every request must be wrapped in ' +\n 'RequestContext.run() by a server filter. That filter appears to be missing: correlation ' +\n 'fields (requestId, tenant, ...) will be absent from logs until it is added. Reported once.';\n\n// Above this serialized size the error is truncated, so one giant stack can't\n// blow up a log line (ported from the tested trytami AppLogger).\nconst MAX_ERR_SERIALIZED = 100_000;\n\nfunction truncateStack(stack: string | undefined, maxLines = 5): string {\n if (!stack) {\n return '';\n }\n return stack.split('\\n').slice(0, maxLines).join('\\n');\n}\n\nfunction normalizeError(err: Error): LoggedError {\n const full = new LoggedError(err.name, err.message, err.stack);\n if (JSON.stringify({ err: full }).length <= MAX_ERR_SERIALIZED) {\n return full;\n }\n return new LoggedError(\n `error too long: ${err.name}`,\n err.message.substring(0, 100),\n truncateStack(err.stack, 5),\n );\n}\n\n/**\n * BunyanLogger - a webpieces {@link WpLogger} backed by a bunyan logger (one per\n * name, created as a bunyan child carrying `loggerName`). On every call it reads\n * the logged HeaderRegistry keys DIRECTLY from the active {@link RequestContext}\n * (secured values masked) into the bunyan fields object, and normalizes an optional\n * Error into `err: { name, message, stack }` — matching the tested trytami AppLogger.\n * The GCP stream then serializes those fields into the structured log payload.\n *\n * This context-reading is INLINED here (and duplicated in the winston logger) on\n * purpose: it must run ONLY when a bunyan/winston backend is installed, never for\n * the plain ConsoleLogger — so it does not belong on RequestContext.\n */\nexport class BunyanLogger implements WpLogger {\n // One-shot latch (see MISSING_CONTEXT_MESSAGE) — flips true after the first\n // out-of-context line so we report the missing filter exactly once, not per line.\n private reportedMissingContext = false;\n\n constructor(private readonly bunyan: Logger) {}\n\n trace(message: string, err?: Error): void {\n this.bunyan.trace(this.buildFields(err), message);\n }\n\n debug(message: string, err?: Error): void {\n this.bunyan.debug(this.buildFields(err), message);\n }\n\n info(message: string, err?: Error): void {\n this.bunyan.info(this.buildFields(err), message);\n }\n\n warn(message: string, err?: Error): void {\n this.bunyan.warn(this.buildFields(err), message);\n }\n\n error(message: string, err?: Error): void {\n this.bunyan.error(this.buildFields(err), message);\n }\n\n private buildFields(err?: Error): Record<string, string | LoggedError> {\n const fields: Record<string, string | LoggedError> = {};\n if (!RequestContext.isActive()) {\n this.reportMissingContextOnce();\n return fields;\n }\n\n // getLoggedKeys() already returns only isLogged keys (precomputed at configure()).\n for (const key of HeaderRegistry.get().getLoggedKeys()) {\n const value = RequestContext.getHeader<string>(key);\n if (value) {\n fields[key.name] = key.maskIfSecured(value);\n }\n }\n if (err) {\n fields['err'] = normalizeError(err);\n }\n return fields;\n }\n\n // Report the missing request-wrapping filter once. Uses the RAW bunyan logger\n // (not buildFields()), so there is no re-entrancy — just a single extra line.\n private reportMissingContextOnce(): void {\n if (this.reportedMissingContext) {\n return;\n }\n this.reportedMissingContext = true;\n this.bunyan.error(MISSING_CONTEXT_MESSAGE);\n }\n}\n"]}
|
package/src/index.d.ts
CHANGED
|
@@ -5,19 +5,19 @@
|
|
|
5
5
|
* startup via `LogManager.setFactory(...)`:
|
|
6
6
|
*
|
|
7
7
|
* ```ts
|
|
8
|
-
* import { BunyanGcpFactory, BunyanConsoleFactory } from '@webpieces/bunyan';
|
|
9
|
-
* import { RequestContextReader } from '@webpieces/core-context';
|
|
8
|
+
* import { BunyanGcpFactory, BunyanConsoleFactory, BunyanFactoryOptions } from '@webpieces/bunyan';
|
|
10
9
|
*
|
|
11
|
-
* const
|
|
10
|
+
* const opts = new BunyanFactoryOptions('my-service'); // serviceName is required
|
|
12
11
|
* const loggerFactory = process.env.K_SERVICE
|
|
13
|
-
* ? new BunyanGcpFactory(
|
|
14
|
-
* : new BunyanConsoleFactory(
|
|
12
|
+
* ? new BunyanGcpFactory(opts) // Cloud Logging via @google-cloud/logging-bunyan
|
|
13
|
+
* : new BunyanConsoleFactory(opts); // local → pretty console
|
|
15
14
|
* // hand to setupRuntime(new RuntimeSetupOptions(loggerFactory, ...))
|
|
16
15
|
* ```
|
|
17
16
|
*
|
|
18
|
-
* Both backends auto-enrich every line with the logged context keys
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* Both backends auto-enrich every line with the logged context keys, read
|
|
18
|
+
* DIRECTLY from the active RequestContext (@webpieces/core-context) on each line —
|
|
19
|
+
* no ContextReader is threaded in. There is no level knob: bunyan filters at its
|
|
20
|
+
* own default.
|
|
21
21
|
*
|
|
22
22
|
* @packageDocumentation
|
|
23
23
|
*/
|
package/src/index.js
CHANGED
|
@@ -8,19 +8,19 @@ exports.logLevelToBunyanLevel = exports.LEVEL_TO_BUNYAN = exports.createConsoleS
|
|
|
8
8
|
* startup via `LogManager.setFactory(...)`:
|
|
9
9
|
*
|
|
10
10
|
* ```ts
|
|
11
|
-
* import { BunyanGcpFactory, BunyanConsoleFactory } from '@webpieces/bunyan';
|
|
12
|
-
* import { RequestContextReader } from '@webpieces/core-context';
|
|
11
|
+
* import { BunyanGcpFactory, BunyanConsoleFactory, BunyanFactoryOptions } from '@webpieces/bunyan';
|
|
13
12
|
*
|
|
14
|
-
* const
|
|
13
|
+
* const opts = new BunyanFactoryOptions('my-service'); // serviceName is required
|
|
15
14
|
* const loggerFactory = process.env.K_SERVICE
|
|
16
|
-
* ? new BunyanGcpFactory(
|
|
17
|
-
* : new BunyanConsoleFactory(
|
|
15
|
+
* ? new BunyanGcpFactory(opts) // Cloud Logging via @google-cloud/logging-bunyan
|
|
16
|
+
* : new BunyanConsoleFactory(opts); // local → pretty console
|
|
18
17
|
* // hand to setupRuntime(new RuntimeSetupOptions(loggerFactory, ...))
|
|
19
18
|
* ```
|
|
20
19
|
*
|
|
21
|
-
* Both backends auto-enrich every line with the logged context keys
|
|
22
|
-
*
|
|
23
|
-
*
|
|
20
|
+
* Both backends auto-enrich every line with the logged context keys, read
|
|
21
|
+
* DIRECTLY from the active RequestContext (@webpieces/core-context) on each line —
|
|
22
|
+
* no ContextReader is threaded in. There is no level knob: bunyan filters at its
|
|
23
|
+
* own default.
|
|
24
24
|
*
|
|
25
25
|
* @packageDocumentation
|
|
26
26
|
*/
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/logging/bunyan/src/index.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AACzB,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAC7B,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAC7B,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AACrB,qCAAyE;AAAhE,kHAAA,uBAAuB,OAAA;AAAE,8GAAA,mBAAmB,OAAA;AACrD,mCAAkE;AAAzD,yGAAA,eAAe,OAAA;AAAE,+GAAA,qBAAqB,OAAA","sourcesContent":["/**\n * @webpieces/bunyan\n *\n * Node-only bunyan {@link LoggerFactory} backends for webpieces. Install one at\n * startup via `LogManager.setFactory(...)`:\n *\n * ```ts\n * import { BunyanGcpFactory, BunyanConsoleFactory } from '@webpieces/bunyan';\n
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/logging/bunyan/src/index.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AACzB,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAC7B,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAC7B,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AACrB,qCAAyE;AAAhE,kHAAA,uBAAuB,OAAA;AAAE,8GAAA,mBAAmB,OAAA;AACrD,mCAAkE;AAAzD,yGAAA,eAAe,OAAA;AAAE,+GAAA,qBAAqB,OAAA","sourcesContent":["/**\n * @webpieces/bunyan\n *\n * Node-only bunyan {@link LoggerFactory} backends for webpieces. Install one at\n * startup via `LogManager.setFactory(...)`:\n *\n * ```ts\n * import { BunyanGcpFactory, BunyanConsoleFactory, BunyanFactoryOptions } from '@webpieces/bunyan';\n *\n * const opts = new BunyanFactoryOptions('my-service'); // serviceName is required\n * const loggerFactory = process.env.K_SERVICE\n * ? new BunyanGcpFactory(opts) // Cloud Logging via @google-cloud/logging-bunyan\n * : new BunyanConsoleFactory(opts); // local → pretty console\n * // hand to setupRuntime(new RuntimeSetupOptions(loggerFactory, ...))\n * ```\n *\n * Both backends auto-enrich every line with the logged context keys, read\n * DIRECTLY from the active RequestContext (@webpieces/core-context) on each line —\n * no ContextReader is threaded in. There is no level knob: bunyan filters at its\n * own default.\n *\n * @packageDocumentation\n */\nexport { BunyanGcpFactory } from './BunyanGcpFactory';\nexport { BunyanConsoleFactory } from './BunyanConsoleFactory';\nexport { BunyanFactoryOptions } from './BunyanFactoryOptions';\nexport { BunyanLogger } from './BunyanLogger';\nexport { createGoogleCloudStream, createConsoleStream } from './streams';\nexport { LEVEL_TO_BUNYAN, logLevelToBunyanLevel } from './levels';\n"]}
|
package/src/streams.d.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import Logger from 'bunyan';
|
|
2
|
-
import type { LogLevel } from '@webpieces/core-util';
|
|
3
2
|
/**
|
|
4
3
|
* The GCP stream: delegates ALL structured-JSON formatting (numeric level → GCP
|
|
5
4
|
* severity, msg→message, trace/httpRequest fields, stripping name/hostname/pid)
|
|
6
5
|
* to @google-cloud/logging-bunyan, exactly as the tested trytami service does.
|
|
7
6
|
* Sends to the Cloud Logging API (needs ADC on the instance).
|
|
7
|
+
*
|
|
8
|
+
* We do NOT filter by level — that is bunyan's job. The stream is created at
|
|
9
|
+
* bunyan's default level ('info'); there is no webpieces level knob.
|
|
8
10
|
*/
|
|
9
|
-
export declare function createGoogleCloudStream(
|
|
10
|
-
/**
|
|
11
|
-
|
|
11
|
+
export declare function createGoogleCloudStream(): Logger.Stream;
|
|
12
|
+
/**
|
|
13
|
+
* The local dev stream: human-readable text to stdout via {@link writeConsole}.
|
|
14
|
+
* No level is set — bunyan filters at its own default ('info').
|
|
15
|
+
*/
|
|
16
|
+
export declare function createConsoleStream(): Logger.Stream;
|
package/src/streams.js
CHANGED
|
@@ -6,7 +6,6 @@ const tslib_1 = require("tslib");
|
|
|
6
6
|
const stream_1 = require("stream");
|
|
7
7
|
const bunyan_1 = tslib_1.__importDefault(require("bunyan"));
|
|
8
8
|
const logging_bunyan_1 = require("@google-cloud/logging-bunyan");
|
|
9
|
-
const levels_1 = require("./levels");
|
|
10
9
|
// bunyan record fields that are structural / rendered specially, so they are not
|
|
11
10
|
// shown as context tags in the local console line.
|
|
12
11
|
const BUNYAN_STD_FIELDS = new Set([
|
|
@@ -68,13 +67,21 @@ function writeConsole(line) {
|
|
|
68
67
|
* severity, msg→message, trace/httpRequest fields, stripping name/hostname/pid)
|
|
69
68
|
* to @google-cloud/logging-bunyan, exactly as the tested trytami service does.
|
|
70
69
|
* Sends to the Cloud Logging API (needs ADC on the instance).
|
|
70
|
+
*
|
|
71
|
+
* We do NOT filter by level — that is bunyan's job. The stream is created at
|
|
72
|
+
* bunyan's default level ('info'); there is no webpieces level knob.
|
|
71
73
|
*/
|
|
72
|
-
function
|
|
74
|
+
// webpieces-disable no-function-outside-class -- bunyan Stream factory; whole file is bunyan stream/render factories
|
|
75
|
+
function createGoogleCloudStream() {
|
|
73
76
|
const loggingBunyan = new logging_bunyan_1.LoggingBunyan();
|
|
74
|
-
return loggingBunyan.stream(
|
|
77
|
+
return loggingBunyan.stream('info');
|
|
75
78
|
}
|
|
76
|
-
/**
|
|
77
|
-
|
|
79
|
+
/**
|
|
80
|
+
* The local dev stream: human-readable text to stdout via {@link writeConsole}.
|
|
81
|
+
* No level is set — bunyan filters at its own default ('info').
|
|
82
|
+
*/
|
|
83
|
+
// webpieces-disable no-function-outside-class -- bunyan Stream factory; whole file is bunyan stream/render factories
|
|
84
|
+
function createConsoleStream() {
|
|
78
85
|
const writable = new stream_1.Writable({
|
|
79
86
|
write(chunk, _encoding, callback) {
|
|
80
87
|
writeConsole(chunk.toString());
|
|
@@ -83,7 +90,6 @@ function createConsoleStream(level) {
|
|
|
83
90
|
});
|
|
84
91
|
return {
|
|
85
92
|
name: 'console',
|
|
86
|
-
level: (0, levels_1.logLevelToBunyanLevel)(level),
|
|
87
93
|
stream: writable,
|
|
88
94
|
};
|
|
89
95
|
}
|
package/src/streams.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streams.js","sourceRoot":"","sources":["../../../../../packages/logging/bunyan/src/streams.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"streams.js","sourceRoot":"","sources":["../../../../../packages/logging/bunyan/src/streams.ts"],"names":[],"mappings":"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","sourcesContent":["import { Writable } from 'stream';\nimport Logger from 'bunyan';\nimport { LoggingBunyan } from '@google-cloud/logging-bunyan';\nimport { LoggedError } from './LoggedError';\n\n// A parsed bunyan JSON record: standard fields plus arbitrary injected context\n// tags. Values are whatever JSON holds.\ntype JsonValue = string | number | boolean | object | null;\ntype BunyanRecord = Record<string, JsonValue>;\n\n// bunyan record fields that are structural / rendered specially, so they are not\n// shown as context tags in the local console line.\nconst BUNYAN_STD_FIELDS = new Set<string>([\n 'v',\n 'level',\n 'name',\n 'hostname',\n 'pid',\n 'time',\n 'msg',\n 'src',\n 'err',\n 'loggerName',\n]);\n\nfunction formatTime(iso: JsonValue): string {\n if (typeof iso !== 'string') {\n return '';\n }\n // ISO 8601 \"2026-07-08T12:34:56.789Z\" → \"12:34:56.789\"\n const timePart = iso.split('T')[1];\n return timePart ? timePart.replace('Z', '') : iso;\n}\n\n/**\n * Render one bunyan JSON line as a human-readable, greppable console line:\n * `[LEVEL][time][ctx tags]: message` plus multi-line error details. Ported from\n * the tested trytami writeConsole, generalized: every non-structural field\n * (i.e. the injected context keys) becomes a `key:value` tag.\n */\nfunction writeConsole(line: string): void {\n const obj: BunyanRecord = JSON.parse(line);\n const levelName = (Logger.nameFromLevel[obj['level'] as number] ?? 'info').toUpperCase().padEnd(5);\n const time = formatTime(obj['time']);\n\n const tags: string[] = [];\n if (obj['loggerName']) {\n tags.push(`logger:${String(obj['loggerName'])}`);\n }\n for (const key of Object.keys(obj)) {\n if (BUNYAN_STD_FIELDS.has(key)) {\n continue;\n }\n tags.push(`${key}:${String(obj[key])}`);\n }\n const tagStr = tags.length > 0 ? tags.join(', ') : 'no-context';\n\n let message = `[${levelName}][${time}][${tagStr}]: ${String(obj['msg'] ?? '')}`;\n\n const err = obj['err'] as LoggedError | undefined;\n if (err) {\n message += `\\nError Details:`;\n message += `\\n Message: ${err.message}`;\n message += `\\n Name: ${err.name}`;\n if (err.stack) {\n message += `\\n Stack Trace:\\n${err.stack}`;\n }\n }\n\n // This IS a logging backend (the console sink); direct stdout is intentional.\n console.log(message);\n}\n\n/**\n * The GCP stream: delegates ALL structured-JSON formatting (numeric level → GCP\n * severity, msg→message, trace/httpRequest fields, stripping name/hostname/pid)\n * to @google-cloud/logging-bunyan, exactly as the tested trytami service does.\n * Sends to the Cloud Logging API (needs ADC on the instance).\n *\n * We do NOT filter by level — that is bunyan's job. The stream is created at\n * bunyan's default level ('info'); there is no webpieces level knob.\n */\n// webpieces-disable no-function-outside-class -- bunyan Stream factory; whole file is bunyan stream/render factories\nexport function createGoogleCloudStream(): Logger.Stream {\n const loggingBunyan = new LoggingBunyan();\n return loggingBunyan.stream('info');\n}\n\n/**\n * The local dev stream: human-readable text to stdout via {@link writeConsole}.\n * No level is set — bunyan filters at its own default ('info').\n */\n// webpieces-disable no-function-outside-class -- bunyan Stream factory; whole file is bunyan stream/render factories\nexport function createConsoleStream(): Logger.Stream {\n const writable = new Writable({\n write(chunk: Buffer | string, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void {\n writeConsole(chunk.toString());\n callback();\n },\n });\n return {\n name: 'console',\n stream: writable,\n };\n}\n"]}
|