@imqueue/async-logger 3.1.0 → 3.2.1

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.
@@ -0,0 +1,58 @@
1
+ # Contributing to @imqueue
2
+
3
+ Thanks for your interest in improving @imqueue! Contributions of all kinds are
4
+ welcome — bug fixes, features, tests, and documentation.
5
+
6
+ ## Contribution terms — please read first
7
+
8
+ @imqueue is **dual-licensed**: it is free to everyone under **GPL-3.0**, and it is
9
+ also offered under **commercial licenses** for closed-source use. To make that
10
+ sustainable, contributions are accepted under the
11
+ **[@imqueue Contribution Terms](./CONTRIBUTION-TERMS.md)**.
12
+
13
+ **By opening a pull request — or otherwise contributing — you agree to those
14
+ terms.** In short:
15
+
16
+ - You **keep the copyright** in your contribution.
17
+ - Your contribution stays available to everyone under **GPL-3.0**.
18
+ - You grant the project owner the right to **also license your contribution
19
+ commercially**, royalty-free — you will not receive a fee for it.
20
+
21
+ **If you do not agree, please do not contribute.** Read the full text in
22
+ [CONTRIBUTION-TERMS.md](./CONTRIBUTION-TERMS.md).
23
+
24
+ ## How to contribute
25
+
26
+ 1. **Open an issue first** for anything non-trivial, so we can agree on the
27
+ approach before you invest time.
28
+ 2. **Fork** the repository and create a topic branch from `master`
29
+ (e.g. `fix/redis-reconnect` or `feat/lock-timeout`).
30
+ 3. **Make your change**, following the existing code style. Keep pull requests
31
+ focused — one logical change per PR.
32
+ 4. **Add or update tests** so the change is covered, and make sure the full suite
33
+ passes locally:
34
+ ```bash
35
+ npm ci
36
+ npm test
37
+ ```
38
+ 5. **Write clear commit messages** and a descriptive PR title and summary.
39
+ 6. **Open the pull request** against `master` and fill in the PR template,
40
+ including the contribution-terms checkbox.
41
+
42
+ ## Guidelines
43
+
44
+ - Match the existing TypeScript style and formatting already used in the file you
45
+ are editing.
46
+ - Keep public API changes documented (doc-blocks / README as appropriate).
47
+ - Be respectful and constructive in reviews and discussions.
48
+
49
+ ## Reporting security issues
50
+
51
+ Please **do not** open a public issue for security vulnerabilities. Report them
52
+ privately to the maintainers (see the repository's security policy or contact
53
+ address) so they can be addressed responsibly.
54
+
55
+ ---
56
+
57
+ Questions about the terms or a larger/corporate contribution? Reach out before you
58
+ start and we'll help.
@@ -0,0 +1,79 @@
1
+ # @imqueue Contribution Terms (v1.0)
2
+
3
+ These terms apply to every contribution to any repository of the **@imqueue**
4
+ project — the packages published under the `@imqueue` npm scope and any repository
5
+ in the imqueue GitHub organisation.
6
+
7
+ **By submitting a contribution — opening a pull request, pushing a commit, sending
8
+ a patch, or otherwise offering work for inclusion — you accept these terms in
9
+ full. If you do not agree with them, do not contribute.**
10
+
11
+ In these terms, **"Owner"** means Mykhailo Stadnyk, together with his successors,
12
+ assigns and any entity he controls (including VaryLogic s.r.o.), and
13
+ **"Contribution"** means any work of authorship — code, documentation or other
14
+ material — you submit to an @imqueue repository.
15
+
16
+ ## 1. What you grant
17
+
18
+ You grant the Owner a **perpetual, worldwide, irrevocable, royalty-free,
19
+ non-exclusive, transferable and sublicensable** license to use, reproduce,
20
+ modify, adapt, publish, distribute and otherwise exploit your Contribution and
21
+ derivative works of it, **and to license and sub-license it under any terms the
22
+ Owner chooses — including commercial and proprietary (closed-source) licenses,
23
+ without any obligation to release source code.**
24
+
25
+ In plain terms: the Owner may include your Contribution in @imqueue and **sell
26
+ commercial licenses that cover it**, alongside the open-source edition.
27
+
28
+ ## 2. No royalties, fees or compensation
29
+
30
+ The rights above are granted **free of charge**. You **waive** any right to
31
+ royalties, license fees, revenue share or any other compensation arising from the
32
+ Owner's use or licensing of your Contribution, including its commercial licensing,
33
+ and you agree not to seek any such payment now or in the future.
34
+
35
+ ## 3. You keep your copyright
36
+
37
+ You **retain ownership** of the copyright in your Contribution and may use it
38
+ elsewhere for your own purposes. You are granting the Owner the rights in Section
39
+ 1 — you are not required to transfer ownership. Your Contribution also remains
40
+ available to the public under the repository's open-source license (GPL-3.0).
41
+
42
+ ## 4. Patent license
43
+
44
+ You grant the Owner and all downstream recipients a perpetual, worldwide,
45
+ royalty-free, irrevocable (except as stated) patent license to make, use, sell,
46
+ offer to sell, import and transfer your Contribution, limited to the patent claims
47
+ you can license that are necessarily infringed by your Contribution alone or in
48
+ combination with the project. If you start patent litigation alleging the project
49
+ or your Contribution infringes your patents, the patent license you received
50
+ terminates.
51
+
52
+ ## 5. Your promises
53
+
54
+ You confirm that: (a) the Contribution is your own original work, or you have the
55
+ right to submit it and to grant these rights; (b) if your employer has any rights
56
+ in your work, you have their permission to contribute, or they have waived those
57
+ rights; and (c) you have identified any third-party material in your Contribution
58
+ and its license.
59
+
60
+ ## 6. Moral rights
61
+
62
+ To the maximum extent permitted by applicable law, you waive, or agree not to
63
+ exercise, any moral rights in your Contribution in a way that would prevent the
64
+ Owner from exercising the rights in Section 1. (Certain moral rights are
65
+ inalienable under Slovak/EU law; nothing here purports to transfer those.)
66
+
67
+ ## 7. No obligation; "as is"
68
+
69
+ The Owner is under no obligation to use your Contribution. It is provided **"as
70
+ is"**, without warranty of any kind.
71
+
72
+ ## 8. Governing law
73
+
74
+ These terms are governed by the laws of the Slovak Republic, without regard to its
75
+ conflict-of-laws rules.
76
+
77
+ ---
78
+
79
+ **If you do not agree to all of the above, do not contribute to @imqueue.**
package/SECURITY.md ADDED
@@ -0,0 +1,41 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a vulnerability
4
+
5
+ If you believe you have found a security vulnerability in this `@imqueue` project (or
6
+ any `@imqueue/*` package), please report it **privately** — do not open a public
7
+ issue, pull request, or discussion for it.
8
+
9
+ Two private channels:
10
+
11
+ - **GitHub** — use *Security → Report a vulnerability* on this repository to open a
12
+ private advisory (preferred; it keeps the report and the fix coordinated in one
13
+ place).
14
+ - **Email** — <support@imqueue.com> with the details below.
15
+
16
+ Please include:
17
+
18
+ - the affected package or repository and version(s);
19
+ - a description of the issue and its impact;
20
+ - steps to reproduce, or a proof of concept, where possible.
21
+
22
+ ## What to expect
23
+
24
+ - We aim to acknowledge a report within a few business days.
25
+ - We'll confirm the issue, keep you updated on progress, and coordinate a fix and a
26
+ disclosure timeline with you.
27
+ - Once a fix is released we'll credit the reporter in the advisory unless you prefer
28
+ to remain anonymous.
29
+
30
+ ## Supported versions
31
+
32
+ Security fixes land on the latest published release line of each `@imqueue/*`
33
+ package on npm. Please make sure you can reproduce an issue against the current
34
+ release before reporting.
35
+
36
+ ## Scope
37
+
38
+ The `@imqueue` framework is open source under GPL-3.0. This policy covers the code
39
+ in the `@imqueue/*` packages and the project repositories. Vulnerabilities in
40
+ third-party dependencies should be reported to those projects, though we're glad to
41
+ help coordinate an upgrade.
package/index.d.ts CHANGED
@@ -19,7 +19,55 @@
19
19
  * purchase a proprietary commercial license. Please contact us at
20
20
  * <support@imqueue.com> to get commercial licensing options.
21
21
  */
22
+ /**
23
+ * Non-blocking logger for `@imqueue` services: writes to the console without
24
+ * holding up the caller, and ships the same records to file or HTTP transports
25
+ * configured entirely from the environment.
26
+ *
27
+ * The default export is a ready-to-use {@link Logger} already configured from
28
+ * `LOGGER_TRANSPORTS` and `LOGGER_METADATA`, so the common case needs no
29
+ * construction and no wiring:
30
+ *
31
+ * ```typescript
32
+ * import logger from '@imqueue/async-logger';
33
+ *
34
+ * logger.info('service started on port %s', port);
35
+ * ```
36
+ *
37
+ * @remarks
38
+ * Console writes are deferred with `setTimeout`, which is what keeps a burst of
39
+ * logging from blocking the event loop — and the reason for the package name.
40
+ * Two consequences follow: log output can appear after code that ran later, and
41
+ * a process that exits immediately after logging may lose the tail. Call it a
42
+ * tick before exiting if the last lines matter.
43
+ *
44
+ * Transports are declared as JSON in `LOGGER_TRANSPORTS`. The placeholders
45
+ * `%name` and `%version` are substituted from the running service's own
46
+ * `package.json`, so one config can be shared across services:
47
+ *
48
+ * ```bash
49
+ * export LOGGER_TRANSPORTS='[{"type":"http","options":{"ssl":true,"port":443,"host":"http-intake.logs.datadoghq.com","path":"/v1/input/<API_KEY>"},"enabled":true}]'
50
+ * export LOGGER_METADATA='{"ddsource":"%name %version","ddtags":"env: dev"}'
51
+ * ```
52
+ *
53
+ * With no transports configured the logger still works — console only. That is
54
+ * the intended local-development mode, not a misconfiguration.
55
+ *
56
+ * @packageDocumentation
57
+ */
22
58
  import { Logger } from './src/index.js';
23
59
  export * from './src/index.js';
60
+ /**
61
+ * A {@link Logger} configured from the environment, constructed at import time.
62
+ *
63
+ * @remarks
64
+ * Shared by every module that imports it, which is normally what you want — one
65
+ * set of transports per process. Construct {@link Logger} directly instead when
66
+ * you need different metadata or transports for a particular subsystem.
67
+ *
68
+ * Because it is built at import time, `LOGGER_TRANSPORTS` and `LOGGER_METADATA`
69
+ * must already be set when this module is first imported; changing them later has
70
+ * no effect on this instance.
71
+ */
24
72
  declare const _default: Logger;
25
73
  export default _default;
package/index.js CHANGED
@@ -19,7 +19,55 @@
19
19
  * purchase a proprietary commercial license. Please contact us at
20
20
  * <support@imqueue.com> to get commercial licensing options.
21
21
  */
22
+ /**
23
+ * Non-blocking logger for `@imqueue` services: writes to the console without
24
+ * holding up the caller, and ships the same records to file or HTTP transports
25
+ * configured entirely from the environment.
26
+ *
27
+ * The default export is a ready-to-use {@link Logger} already configured from
28
+ * `LOGGER_TRANSPORTS` and `LOGGER_METADATA`, so the common case needs no
29
+ * construction and no wiring:
30
+ *
31
+ * ```typescript
32
+ * import logger from '@imqueue/async-logger';
33
+ *
34
+ * logger.info('service started on port %s', port);
35
+ * ```
36
+ *
37
+ * @remarks
38
+ * Console writes are deferred with `setTimeout`, which is what keeps a burst of
39
+ * logging from blocking the event loop — and the reason for the package name.
40
+ * Two consequences follow: log output can appear after code that ran later, and
41
+ * a process that exits immediately after logging may lose the tail. Call it a
42
+ * tick before exiting if the last lines matter.
43
+ *
44
+ * Transports are declared as JSON in `LOGGER_TRANSPORTS`. The placeholders
45
+ * `%name` and `%version` are substituted from the running service's own
46
+ * `package.json`, so one config can be shared across services:
47
+ *
48
+ * ```bash
49
+ * export LOGGER_TRANSPORTS='[{"type":"http","options":{"ssl":true,"port":443,"host":"http-intake.logs.datadoghq.com","path":"/v1/input/<API_KEY>"},"enabled":true}]'
50
+ * export LOGGER_METADATA='{"ddsource":"%name %version","ddtags":"env: dev"}'
51
+ * ```
52
+ *
53
+ * With no transports configured the logger still works — console only. That is
54
+ * the intended local-development mode, not a misconfiguration.
55
+ *
56
+ * @packageDocumentation
57
+ */
22
58
  import { Logger } from './src/index.js';
23
59
  export * from './src/index.js';
60
+ /**
61
+ * A {@link Logger} configured from the environment, constructed at import time.
62
+ *
63
+ * @remarks
64
+ * Shared by every module that imports it, which is normally what you want — one
65
+ * set of transports per process. Construct {@link Logger} directly instead when
66
+ * you need different metadata or transports for a particular subsystem.
67
+ *
68
+ * Because it is built at import time, `LOGGER_TRANSPORTS` and `LOGGER_METADATA`
69
+ * must already be set when this module is first imported; changing them later has
70
+ * no effect on this instance.
71
+ */
24
72
  export default new Logger();
25
73
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imqueue/async-logger",
3
- "version": "3.1.0",
3
+ "version": "3.2.1",
4
4
  "description": "Configurable async logger over winston for @imqueue services",
5
5
  "keywords": [
6
6
  "logger",
@@ -34,7 +34,7 @@
34
34
  "bugs": {
35
35
  "url": "https://github.com/imqueue/async-logger/issues"
36
36
  },
37
- "homepage": "https://github.com/imqueue/async-logger",
37
+ "homepage": "https://imqueue.org/",
38
38
  "author": "imqueue.com <support@imqueue.com> (https://imqueue.com)",
39
39
  "license": "GPL-3.0-only",
40
40
  "dependencies": {
@@ -0,0 +1,3 @@
1
+ {
2
+ "signedContributors": []
3
+ }
package/src/Logger.d.ts CHANGED
@@ -21,73 +21,138 @@
21
21
  */
22
22
  import { type ILogger, type JsonObject } from './types.js';
23
23
  import { type TransportOptions } from './TransportOptions.js';
24
+ /**
25
+ * Explicit configuration for a {@link Logger}, replacing what it would otherwise
26
+ * read from the environment.
27
+ *
28
+ * @remarks
29
+ * Both fields are read independently: pass only `metadata` and the transports
30
+ * still come from `LOGGER_TRANSPORTS`, and vice versa. Passing an empty
31
+ * `transports` array is not the same as omitting it — an empty array means
32
+ * "console only", while omitting it falls back to the environment.
33
+ */
24
34
  export interface AsyncLoggerOptions {
35
+ /**
36
+ * Transports to log through. Each entry is created and attached at
37
+ * construction time; entries with `enabled: false` are skipped.
38
+ */
25
39
  transports: TransportOptions[];
40
+ /**
41
+ * Fields attached to every record sent to a transport, such as a source or
42
+ * environment tag. Does not affect console output.
43
+ */
26
44
  metadata: JsonObject;
27
45
  }
28
46
  /**
29
- * Class Logger
47
+ * Logger that writes to the console without blocking the caller and forwards the
48
+ * same records to any configured winston transports.
49
+ *
50
+ * @remarks
51
+ * Implements {@link ILogger}, so it drops into anything in `@imqueue` that accepts
52
+ * a logger — `IMQClient`, `IMQService`, `RedisCache` — replacing the default
53
+ * synchronous console.
54
+ *
55
+ * Console output is scheduled with `setTimeout` rather than written inline. That
56
+ * is the point of the package: a service logging heavily does not pay for it on
57
+ * the request path. It also means ordering against synchronous code is not
58
+ * guaranteed, and output queued at the moment of `process.exit()` is lost.
59
+ *
60
+ * Transports are optional. Constructed with none — the default when
61
+ * `LOGGER_TRANSPORTS` is unset — this behaves as an async console logger and
62
+ * never touches winston.
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * import { Logger } from '@imqueue/async-logger';
67
+ *
68
+ * // configured from LOGGER_TRANSPORTS / LOGGER_METADATA
69
+ * const logger = new Logger();
70
+ *
71
+ * // or explicitly, e.g. to tag one subsystem differently
72
+ * const audit = new Logger({
73
+ * transports: [{ type: 'file', options: { filename: 'audit.log' }, enabled: true }],
74
+ * metadata: { subsystem: 'audit' },
75
+ * });
76
+ *
77
+ * audit.info('user %s signed in', userId);
78
+ * ```
30
79
  */
31
80
  export declare class Logger implements ILogger {
32
81
  /**
33
- * Asynchronous console async-logger
34
- *
35
- * @type {ILogger}
82
+ * Console bound through `setTimeout`, so every write is deferred to a later
83
+ * tick instead of blocking the caller.
36
84
  */
37
85
  private static readonly console;
38
86
  /**
39
- * @description
40
- * Configuring options of async-logger
87
+ * Builds the winston options every transport shares: JSON formatting, the
88
+ * given (or environment-derived) default metadata, and `exitOnError: false`
89
+ * so a transport failure never takes the process down.
41
90
  *
42
- * @returns {LoggerOptions}
91
+ * @param metadata - fields to attach to every record; falls back to
92
+ * `LOGGER_METADATA` when omitted
93
+ * @returns winston logger options
43
94
  */
44
95
  private static getLoggerOptions;
45
96
  /**
46
- * Winston based async-logger having different logging transports
47
- *
48
- * @type {WinstonLogger}
97
+ * The winston logger the transports are attached to. Left undefined when no
98
+ * enabled transport was configured, which is how console-only mode is
99
+ * represented — every method checks it before forwarding.
49
100
  */
50
101
  private readonly logger?;
51
102
  /**
52
- * Logger Ctor
53
- *
54
- * @constructor
55
- * @param {AsyncLoggerOptions} options
103
+ * @param options - explicit transports and metadata. Omit either half and it
104
+ * is read from `LOGGER_TRANSPORTS` / `LOGGER_METADATA`; omit
105
+ * the argument entirely and both are.
106
+ * @throws TypeError if the environment config is not valid JSON, or names a
107
+ * transport type other than `file` or `http`
56
108
  */
57
109
  constructor(options?: AsyncLoggerOptions);
58
110
  /**
59
- * Logs given arguments to configured async-logger destinations and to stdout
60
- * with log level = LOG
111
+ * Logs to the console and to every configured transport.
61
112
  *
62
- * @param {...*[]} args
113
+ * @remarks
114
+ * Reaches transports at winston's `info` level — there is no distinct `log`
115
+ * level — so records from here and from {@link Logger.info} are
116
+ * indistinguishable once shipped. They differ only in the console method
117
+ * used. Pick by the destination you care about.
118
+ *
119
+ * @param args - `console.log`-style arguments; the first may be a format
120
+ * string with `%s`/`%d`/`%j` placeholders for the rest
63
121
  */
64
122
  log(...args: any[]): void;
65
123
  /**
66
- * Logs given arguments to configured async-logger destinations and to stdout
67
- * with log level = INFO
124
+ * Logs at INFO level routine progress worth keeping.
68
125
  *
69
- * @param {...*[]} args
126
+ * @param args - `console.info`-style arguments; the first may be a format
127
+ * string with `%s`/`%d`/`%j` placeholders for the rest
70
128
  */
71
129
  info(...args: any[]): void;
72
130
  /**
73
- * Logs given arguments to configured async-logger destinations and to stderr
74
- * with log level = WARN
131
+ * Logs at WARN level something recovered from, but worth seeing.
75
132
  *
76
- * @param {...*[]} args
133
+ * @param args - `console.warn`-style arguments; the first may be a format
134
+ * string with `%s`/`%d`/`%j` placeholders for the rest
77
135
  */
78
136
  warn(...args: any[]): void;
79
137
  /**
80
- * Logs given arguments to configured async-logger destinations and to stderr
81
- * with log level = ERROR
138
+ * Logs at ERROR level.
139
+ *
140
+ * @remarks
141
+ * Pass an `Error` and it is formatted like the console would — including the
142
+ * stack. Passing `error.stack` explicitly is the usual choice when the record
143
+ * has to stay one line for a log shipper.
82
144
  *
83
- * @param {...*[]} args
145
+ * @param args - `console.error`-style arguments; the first may be a format
146
+ * string with `%s`/`%d`/`%j` placeholders for the rest
84
147
  */
85
148
  error(...args: any[]): void;
86
149
  /**
87
- * Configuring transports of async-logger
150
+ * Creates and attaches each enabled transport from the given config.
88
151
  *
89
- * @param {TransportOptions[]} config - configuration for transports from
90
- * environment variables
152
+ * @param config - transport definitions, from {@link AsyncLoggerOptions} or
153
+ * parsed out of `LOGGER_TRANSPORTS`
154
+ * @throws TypeError if `config` is not an array, or an enabled entry names a
155
+ * transport type other than `file` or `http`
91
156
  */
92
157
  private setupLogger;
93
158
  }
package/src/Logger.js CHANGED
@@ -24,13 +24,43 @@ import { createLogger, format, Logger as WinstonLogger, } from 'winston';
24
24
  import { buildMessage, defaultMetadata, getTransport, transportsConfig, } from './helpers/index.js';
25
25
  import {} from './TransportOptions.js';
26
26
  /**
27
- * Class Logger
27
+ * Logger that writes to the console without blocking the caller and forwards the
28
+ * same records to any configured winston transports.
29
+ *
30
+ * @remarks
31
+ * Implements {@link ILogger}, so it drops into anything in `@imqueue` that accepts
32
+ * a logger — `IMQClient`, `IMQService`, `RedisCache` — replacing the default
33
+ * synchronous console.
34
+ *
35
+ * Console output is scheduled with `setTimeout` rather than written inline. That
36
+ * is the point of the package: a service logging heavily does not pay for it on
37
+ * the request path. It also means ordering against synchronous code is not
38
+ * guaranteed, and output queued at the moment of `process.exit()` is lost.
39
+ *
40
+ * Transports are optional. Constructed with none — the default when
41
+ * `LOGGER_TRANSPORTS` is unset — this behaves as an async console logger and
42
+ * never touches winston.
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * import { Logger } from '@imqueue/async-logger';
47
+ *
48
+ * // configured from LOGGER_TRANSPORTS / LOGGER_METADATA
49
+ * const logger = new Logger();
50
+ *
51
+ * // or explicitly, e.g. to tag one subsystem differently
52
+ * const audit = new Logger({
53
+ * transports: [{ type: 'file', options: { filename: 'audit.log' }, enabled: true }],
54
+ * metadata: { subsystem: 'audit' },
55
+ * });
56
+ *
57
+ * audit.info('user %s signed in', userId);
58
+ * ```
28
59
  */
29
60
  export class Logger {
30
61
  /**
31
- * Asynchronous console async-logger
32
- *
33
- * @type {ILogger}
62
+ * Console bound through `setTimeout`, so every write is deferred to a later
63
+ * tick instead of blocking the caller.
34
64
  */
35
65
  static console = {
36
66
  // oxlint-disable-next-line no-console -- forwarding is the API here
@@ -40,10 +70,13 @@ export class Logger {
40
70
  error: (...args) => setTimeout(() => console.error(...args)),
41
71
  };
42
72
  /**
43
- * @description
44
- * Configuring options of async-logger
73
+ * Builds the winston options every transport shares: JSON formatting, the
74
+ * given (or environment-derived) default metadata, and `exitOnError: false`
75
+ * so a transport failure never takes the process down.
45
76
  *
46
- * @returns {LoggerOptions}
77
+ * @param metadata - fields to attach to every record; falls back to
78
+ * `LOGGER_METADATA` when omitted
79
+ * @returns winston logger options
47
80
  */
48
81
  static getLoggerOptions(metadata) {
49
82
  return {
@@ -53,16 +86,17 @@ export class Logger {
53
86
  };
54
87
  }
55
88
  /**
56
- * Winston based async-logger having different logging transports
57
- *
58
- * @type {WinstonLogger}
89
+ * The winston logger the transports are attached to. Left undefined when no
90
+ * enabled transport was configured, which is how console-only mode is
91
+ * represented — every method checks it before forwarding.
59
92
  */
60
93
  logger;
61
94
  /**
62
- * Logger Ctor
63
- *
64
- * @constructor
65
- * @param {AsyncLoggerOptions} options
95
+ * @param options - explicit transports and metadata. Omit either half and it
96
+ * is read from `LOGGER_TRANSPORTS` / `LOGGER_METADATA`; omit
97
+ * the argument entirely and both are.
98
+ * @throws TypeError if the environment config is not valid JSON, or names a
99
+ * transport type other than `file` or `http`
66
100
  */
67
101
  constructor(options) {
68
102
  const opts = Logger.getLoggerOptions((options || {}).metadata);
@@ -73,10 +107,16 @@ export class Logger {
73
107
  }
74
108
  }
75
109
  /**
76
- * Logs given arguments to configured async-logger destinations and to stdout
77
- * with log level = LOG
110
+ * Logs to the console and to every configured transport.
78
111
  *
79
- * @param {...*[]} args
112
+ * @remarks
113
+ * Reaches transports at winston's `info` level — there is no distinct `log`
114
+ * level — so records from here and from {@link Logger.info} are
115
+ * indistinguishable once shipped. They differ only in the console method
116
+ * used. Pick by the destination you care about.
117
+ *
118
+ * @param args - `console.log`-style arguments; the first may be a format
119
+ * string with `%s`/`%d`/`%j` placeholders for the rest
80
120
  */
81
121
  log(...args) {
82
122
  Logger.console.log(...args);
@@ -85,10 +125,10 @@ export class Logger {
85
125
  }
86
126
  }
87
127
  /**
88
- * Logs given arguments to configured async-logger destinations and to stdout
89
- * with log level = INFO
128
+ * Logs at INFO level routine progress worth keeping.
90
129
  *
91
- * @param {...*[]} args
130
+ * @param args - `console.info`-style arguments; the first may be a format
131
+ * string with `%s`/`%d`/`%j` placeholders for the rest
92
132
  */
93
133
  info(...args) {
94
134
  Logger.console.info(...args);
@@ -97,10 +137,10 @@ export class Logger {
97
137
  }
98
138
  }
99
139
  /**
100
- * Logs given arguments to configured async-logger destinations and to stderr
101
- * with log level = WARN
140
+ * Logs at WARN level something recovered from, but worth seeing.
102
141
  *
103
- * @param {...*[]} args
142
+ * @param args - `console.warn`-style arguments; the first may be a format
143
+ * string with `%s`/`%d`/`%j` placeholders for the rest
104
144
  */
105
145
  warn(...args) {
106
146
  Logger.console.warn(...args);
@@ -109,10 +149,15 @@ export class Logger {
109
149
  }
110
150
  }
111
151
  /**
112
- * Logs given arguments to configured async-logger destinations and to stderr
113
- * with log level = ERROR
152
+ * Logs at ERROR level.
153
+ *
154
+ * @remarks
155
+ * Pass an `Error` and it is formatted like the console would — including the
156
+ * stack. Passing `error.stack` explicitly is the usual choice when the record
157
+ * has to stay one line for a log shipper.
114
158
  *
115
- * @param {...*[]} args
159
+ * @param args - `console.error`-style arguments; the first may be a format
160
+ * string with `%s`/`%d`/`%j` placeholders for the rest
116
161
  */
117
162
  error(...args) {
118
163
  Logger.console.error(...args);
@@ -121,10 +166,12 @@ export class Logger {
121
166
  }
122
167
  }
123
168
  /**
124
- * Configuring transports of async-logger
169
+ * Creates and attaches each enabled transport from the given config.
125
170
  *
126
- * @param {TransportOptions[]} config - configuration for transports from
127
- * environment variables
171
+ * @param config - transport definitions, from {@link AsyncLoggerOptions} or
172
+ * parsed out of `LOGGER_TRANSPORTS`
173
+ * @throws TypeError if `config` is not an array, or an enabled entry names a
174
+ * transport type other than `file` or `http`
128
175
  */
129
176
  setupLogger(config) {
130
177
  if (!config || !Array.isArray(config)) {
@@ -135,6 +182,13 @@ export class Logger {
135
182
  continue;
136
183
  }
137
184
  const transport = getTransport(options.type, options.options);
185
+ // getTransport() yields nothing for a type it does not know. Report
186
+ // the offending type here: winston would otherwise reject the null
187
+ // with "Invalid transport, must be an object with a log method",
188
+ // which names neither the type nor the config it came from.
189
+ if (!transport) {
190
+ throw new TypeError(`Logger: unknown transport type "${options.type}", expected "file" or "http"!`);
191
+ }
138
192
  // the constructor always creates the winston logger before
139
193
  // calling setupLogger(), the optional chaining only satisfies
140
194
  // strict property-initialization analysis
@@ -21,10 +21,44 @@
21
21
  */
22
22
  import { type LoggerOptions } from 'winston';
23
23
  /**
24
- * Interface IConfig
24
+ * One transport declaration — the shape of each element in the
25
+ * `LOGGER_TRANSPORTS` JSON array.
26
+ *
27
+ * @example
28
+ * ```json
29
+ * {
30
+ * "type": "http",
31
+ * "options": {
32
+ * "ssl": true,
33
+ * "port": 443,
34
+ * "host": "http-intake.logs.datadoghq.com",
35
+ * "path": "/v1/input/<API_KEY>"
36
+ * },
37
+ * "enabled": true
38
+ * }
39
+ * ```
25
40
  */
26
41
  export interface TransportOptions {
42
+ /**
43
+ * Which transport to create: `'file'` or `'http'`. Any other value is
44
+ * rejected at construction time.
45
+ */
27
46
  type: string;
47
+ /**
48
+ * Options handed to the winston transport constructor — `filename` for
49
+ * `file`, `host`/`port`/`path`/`ssl` for `http`.
50
+ *
51
+ * @remarks
52
+ * Typed as winston's `LoggerOptions` for historical reasons, which is wider
53
+ * than what is actually accepted here. Treat it as `FileTransportOptions` or
54
+ * `HttpTransportOptions` according to `type`; the declared type will not
55
+ * catch a mismatch for you.
56
+ */
28
57
  options: LoggerOptions;
58
+ /**
59
+ * Whether to attach this transport. A `false` entry is skipped entirely, so
60
+ * a transport can be left in the config and switched off per environment
61
+ * rather than deleted.
62
+ */
29
63
  enabled: boolean;
30
64
  }
@@ -22,23 +22,46 @@
22
22
  import { type JsonObject } from '../types.js';
23
23
  import { type TransportOptions } from '../TransportOptions.js';
24
24
  /**
25
- * Retrieve package name and version from package.json of running service
25
+ * Reads the running service's own name and version, used to expand the `%name`
26
+ * and `%version` placeholders in the logger environment variables.
26
27
  *
27
- * @returns {name: string, value: string} - return package name and version
28
+ * @remarks
29
+ * Resolved from `package.json` in the process's CURRENT WORKING DIRECTORY, not
30
+ * from this package's location. A service started from a different directory
31
+ * therefore reports whatever it finds there, and one started somewhere with no
32
+ * `package.json` falls back to `{ name: 'logger', version: '' }` rather than
33
+ * failing.
34
+ *
35
+ * @returns the service name and version, or the fallback pair
28
36
  */
29
37
  export declare function pkg(): {
30
38
  name: string;
31
39
  version: string;
32
40
  };
33
41
  /**
34
- * Used for retrieve transport config from environment variables
42
+ * Parses the transport declarations out of `LOGGER_TRANSPORTS`, expanding
43
+ * `%name` and `%version` first.
44
+ *
45
+ * @remarks
46
+ * An unset variable yields an empty array, which the {@link Logger} treats as
47
+ * console-only rather than as an error — the normal local-development case.
48
+ * Malformed JSON, by contrast, throws: a config typo should fail loudly at
49
+ * start-up rather than silently drop a production log destination.
35
50
  *
36
- * @returns {TransportOptions[]}
51
+ * @returns the declared transports, or an empty array when unset
52
+ * @throws TypeError if the variable is set but not parseable as JSON
37
53
  */
38
54
  export declare function transportsConfig(): TransportOptions[];
39
55
  /**
40
- * Returns default metadata, configured by environment variables
56
+ * Parses the default record metadata out of `LOGGER_METADATA`, expanding `%name`
57
+ * and `%version` first.
58
+ *
59
+ * @remarks
60
+ * These fields are attached to every record sent to a transport — a source tag,
61
+ * an environment name, a hostname — and are what makes records from several
62
+ * services distinguishable at the collector. Console output is unaffected.
41
63
  *
42
- * @returns {JsonObject}
64
+ * @returns the parsed metadata, or an empty object when unset
65
+ * @throws TypeError if the variable is set but not parseable as JSON
43
66
  */
44
67
  export declare function defaultMetadata(): JsonObject;
@@ -26,9 +26,17 @@ import {} from '../TransportOptions.js';
26
26
  const RX_NAME = /%name/g;
27
27
  const RX_VERSION = /%version/g;
28
28
  /**
29
- * Retrieve package name and version from package.json of running service
29
+ * Reads the running service's own name and version, used to expand the `%name`
30
+ * and `%version` placeholders in the logger environment variables.
30
31
  *
31
- * @returns {name: string, value: string} - return package name and version
32
+ * @remarks
33
+ * Resolved from `package.json` in the process's CURRENT WORKING DIRECTORY, not
34
+ * from this package's location. A service started from a different directory
35
+ * therefore reports whatever it finds there, and one started somewhere with no
36
+ * `package.json` falls back to `{ name: 'logger', version: '' }` rather than
37
+ * failing.
38
+ *
39
+ * @returns the service name and version, or the fallback pair
32
40
  */
33
41
  export function pkg() {
34
42
  const pkgPath = resolve(process.cwd(), 'package.json');
@@ -38,9 +46,17 @@ export function pkg() {
38
46
  return { name, version };
39
47
  }
40
48
  /**
41
- * Used for retrieve transport config from environment variables
49
+ * Parses the transport declarations out of `LOGGER_TRANSPORTS`, expanding
50
+ * `%name` and `%version` first.
51
+ *
52
+ * @remarks
53
+ * An unset variable yields an empty array, which the {@link Logger} treats as
54
+ * console-only rather than as an error — the normal local-development case.
55
+ * Malformed JSON, by contrast, throws: a config typo should fail loudly at
56
+ * start-up rather than silently drop a production log destination.
42
57
  *
43
- * @returns {TransportOptions[]}
58
+ * @returns the declared transports, or an empty array when unset
59
+ * @throws TypeError if the variable is set but not parseable as JSON
44
60
  */
45
61
  export function transportsConfig() {
46
62
  const { name, version } = pkg();
@@ -54,9 +70,16 @@ export function transportsConfig() {
54
70
  }
55
71
  }
56
72
  /**
57
- * Returns default metadata, configured by environment variables
73
+ * Parses the default record metadata out of `LOGGER_METADATA`, expanding `%name`
74
+ * and `%version` first.
75
+ *
76
+ * @remarks
77
+ * These fields are attached to every record sent to a transport — a source tag,
78
+ * an environment name, a hostname — and are what makes records from several
79
+ * services distinguishable at the collector. Console output is unaffected.
58
80
  *
59
- * @returns {JsonObject}
81
+ * @returns the parsed metadata, or an empty object when unset
82
+ * @throws TypeError if the variable is set but not parseable as JSON
60
83
  */
61
84
  export function defaultMetadata() {
62
85
  const { name, version } = pkg();
@@ -1,7 +1,13 @@
1
1
  /**
2
- * Format message like console log
2
+ * Renders `console.log`-style arguments into the single string a transport
3
+ * record needs, applying `util.format` so `%s`/`%d`/`%j` placeholders and object
4
+ * inspection behave exactly as they do on the console.
3
5
  *
4
- * @param {...*[]} args
5
- * @returns {string}
6
+ * @remarks
7
+ * MUTATES the array it is given — the first element is shifted off to serve as
8
+ * the format string. Pass a copy if you need the original afterwards.
9
+ *
10
+ * @param args - the logging arguments, first one treated as the format string
11
+ * @returns the formatted message
6
12
  */
7
13
  export declare function buildMessage(args: any[]): string;
@@ -21,10 +21,16 @@
21
21
  */
22
22
  import { format } from 'util';
23
23
  /**
24
- * Format message like console log
24
+ * Renders `console.log`-style arguments into the single string a transport
25
+ * record needs, applying `util.format` so `%s`/`%d`/`%j` placeholders and object
26
+ * inspection behave exactly as they do on the console.
25
27
  *
26
- * @param {...*[]} args
27
- * @returns {string}
28
+ * @remarks
29
+ * MUTATES the array it is given — the first element is shifted off to serve as
30
+ * the format string. Pass a copy if you need the original afterwards.
31
+ *
32
+ * @param args - the logging arguments, first one treated as the format string
33
+ * @returns the formatted message
28
34
  */
29
35
  export function buildMessage(args) {
30
36
  return format(args.shift(), ...args);
@@ -1,11 +1,16 @@
1
1
  import type Transport from 'winston-transport';
2
2
  import type { FileTransportOptions, HttpTransportOptions } from 'winston/lib/winston/transports/index.js';
3
3
  /**
4
- * Used for get configured transport by type
4
+ * Constructs a winston transport of the named type.
5
5
  *
6
- * @param {string} type - transport type
7
- * @param {FileTransportOptions | HttpTransportOptions} options -
8
- * options for configure transport
9
- * @returns {Transport}
6
+ * @remarks
7
+ * Only `'file'` and `'http'` are supported. Anything else returns nothing —
8
+ * despite the declared return type, which is a `Transport` cast rather than a
9
+ * guarantee. {@link Logger} checks for that and reports the offending type; a
10
+ * direct caller must check too.
11
+ *
12
+ * @param type - `'file'` or `'http'`
13
+ * @param options - options for the winston transport constructor
14
+ * @returns the transport, or nothing if the type is not recognised
10
15
  */
11
16
  export declare function getTransport(type: string, options: FileTransportOptions | HttpTransportOptions): Transport;
@@ -21,12 +21,17 @@
21
21
  */
22
22
  import { transports } from 'winston';
23
23
  /**
24
- * Used for get configured transport by type
24
+ * Constructs a winston transport of the named type.
25
25
  *
26
- * @param {string} type - transport type
27
- * @param {FileTransportOptions | HttpTransportOptions} options -
28
- * options for configure transport
29
- * @returns {Transport}
26
+ * @remarks
27
+ * Only `'file'` and `'http'` are supported. Anything else returns nothing —
28
+ * despite the declared return type, which is a `Transport` cast rather than a
29
+ * guarantee. {@link Logger} checks for that and reports the offending type; a
30
+ * direct caller must check too.
31
+ *
32
+ * @param type - `'file'` or `'http'`
33
+ * @param options - options for the winston transport constructor
34
+ * @returns the transport, or nothing if the type is not recognised
30
35
  */
31
36
  export function getTransport(type, options) {
32
37
  let transportInstance = null;
package/src/types.d.ts CHANGED
@@ -26,46 +26,40 @@
26
26
  * assignment-compatible with code written against the core interfaces.
27
27
  */
28
28
  /**
29
- * Represents any JSON-serializable value
29
+ * Any value that survives `JSON.stringify` unchanged.
30
+ *
31
+ * @remarks
32
+ * A structural copy of the type in `@imqueue/core`, declared here so the logger
33
+ * needs no runtime dependency on the queue library. The shapes match exactly, so
34
+ * values remain assignable in both directions.
30
35
  */
31
36
  export type AnyJson = boolean | number | string | null | undefined | JsonArray | JsonObject;
32
37
  /**
33
- * Represents JSON serializable object
38
+ * A JSON object — string keys, {@link AnyJson} values. This is the type of the
39
+ * logger's default metadata.
34
40
  */
35
41
  export interface JsonObject {
36
42
  [key: string]: AnyJson;
37
43
  }
38
- /**
39
- * Represents JSON-serializable array
40
- */
44
+ /** A JSON array — any number of {@link AnyJson} values. */
41
45
  export interface JsonArray extends Array<AnyJson> {
42
46
  }
43
47
  /**
44
- * Logger interface
48
+ * The logger contract shared across `@imqueue` — the four console methods, and
49
+ * nothing else.
50
+ *
51
+ * @remarks
52
+ * Deliberately console-shaped, so `console` itself satisfies it and any
53
+ * `@imqueue` component taking a logger accepts either that or a {@link Logger}
54
+ * with no adapter. Implement it to route the framework's own output elsewhere.
45
55
  */
46
56
  export interface ILogger {
47
- /**
48
- * Log level function
49
- *
50
- * @param {...unknown[]} args
51
- */
57
+ /** Logs at the default level. */
52
58
  log(...args: unknown[]): void;
53
- /**
54
- * Info level function
55
- *
56
- * @param {...unknown[]} args
57
- */
59
+ /** Logs at INFO level. */
58
60
  info(...args: unknown[]): void;
59
- /**
60
- * Warning level function
61
- *
62
- * @param {...unknown[]} args
63
- */
61
+ /** Logs at WARN level. */
64
62
  warn(...args: unknown[]): void;
65
- /**
66
- * Error level function
67
- *
68
- * @param {...unknown[]} args
69
- */
63
+ /** Logs at ERROR level. */
70
64
  error(...args: unknown[]): void;
71
65
  }