@elysiumjs/hermes 0.1.1 → 0.3.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.
- package/CHANGELOG.md +10 -0
- package/README.md +2 -2
- package/dist/index.js +2 -0
- package/index.ts +1 -3
- package/package.json +29 -16
- package/src/decorators/logged.ts +86 -0
- package/src/index.ts +40 -0
- package/src/services/logger.service.ts +55 -33
- package/src/transports/http.transport.ts +79 -0
- package/src/{services/pino.factory.ts → types.ts} +19 -5
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# @elysiumjs/hermes
|
|
2
|
+
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Add HTTP transport for remote log shipping.
|
|
8
|
+
- Add `@Logged` decorator for automatic method-level logging.
|
|
9
|
+
- Implement lazy DI registration and logger factory pattern.
|
|
10
|
+
- Export new types and improve overall logging API.
|
package/README.md
CHANGED
|
@@ -11,9 +11,9 @@ bun add @elysiumjs/hermes
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
|
-
import {
|
|
14
|
+
import { HermesLogger } from '@elysiumjs/hermes';
|
|
15
15
|
|
|
16
|
-
const logger =
|
|
16
|
+
const logger = HermesLogger.make('my-logger');
|
|
17
17
|
|
|
18
18
|
logger.info('Hello world!');
|
|
19
19
|
logger.error('Something went wrong!');
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var V=import.meta.require;import{Service as S}from"@elysiumjs/core";import{Service as G}from"@elysiumjs/core";import E from"pino";var Y={level:"info",format:"json"};class C{pino;config;static make(f){return G.get(C)?.child({name:f})??new C({name:f})}constructor(f={}){this.config={...Y,...f},this.pino=this.createPinoInstance()}createPinoInstance(){let f={level:this.config.level,name:this.config.name};if(this.config.format==="pretty")return E(f,E.transport({target:"pino-pretty"}));return E(f)}trace(f,O){this.pino.trace(O??{},f)}debug(f,O){this.pino.debug(O??{},f)}info(f,O){this.pino.info(O??{},f)}warn(f,O){this.pino.warn(O??{},f)}error(f,O){this.pino.error(O??{},f)}fatal(f,O){this.pino.fatal(O??{},f)}child(f){let O=Object.create(this);return O.pino=this.pino.child(f),O}}class b{options;buffer=[];flushTimer;maxBufferSize;constructor(f){this.options=f;this.options.batchSize??=100,this.options.flushInterval??=5000,this.maxBufferSize=this.options.maxBufferSize??1e4,this.flushTimer=setInterval(()=>this.flush(),this.options.flushInterval)}write(f){if(this.buffer.length>=this.maxBufferSize)this.buffer.shift();if(this.buffer.push(f),this.buffer.length>=this.options.batchSize)this.flush()}async flush(){if(this.buffer.length===0)return;let f=this.buffer.splice(0);try{await fetch(this.options.url,{method:"POST",headers:{"Content-Type":"application/json",...this.options.headers},body:JSON.stringify({logs:f})})}catch{let O=this.maxBufferSize-this.buffer.length;if(O>0)this.buffer.unshift(...f.slice(0,O))}}async close(){if(this.flushTimer)clearInterval(this.flushTimer);await this.flush()}}import{ConsoleLogger as q}from"@elysiumjs/core";function J(f={}){return function(O,D,F){let L=F.value,I=`${O.constructor.name}.${String(D)}`;return F.value=async function(...T){let W=this.logger??N(),U=Date.now();if(f.includeArgs)W.debug(`[${I}] Entry`,{args:T});try{let w=await L.apply(this,T);if(f.includeResult||f.includeTiming){let A=Date.now()-U;W[f.level??"debug"](`[${I}] Exit`,{...f.includeResult&&{result:w},...f.includeTiming&&{duration:`${A}ms`}})}return w}catch(w){let A=Date.now()-U;throw W.error(`[${I}] Error`,{error:w instanceof Error?w.message:w,duration:`${A}ms`}),w}},F}}function N(){try{let{Service:f}=V("@elysiumjs/core");return f.get("logger")??new q}catch{return new q}}var R=null,B=()=>{if(!R){let O=S.get("elysium.app")?.getConfig("elysium:hermes");R=new C(O??{})}return R};S.registerLazy(C.name,B);S.registerLazy("logger",B);export{J as Logged,b as HttpTransport,C as HermesLogger};
|
package/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
2
|
+
"name": "@elysiumjs/hermes",
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"module": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"sideEffects": [
|
|
8
|
+
"./src/index.ts"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"format": "prettier --write \"./src/**/*.ts\"",
|
|
12
|
+
"clean": "rimraf dist",
|
|
13
|
+
"build:js": "bun build ./src/index.ts --outdir ./dist --target bun --packages external --root ./src --minify",
|
|
14
|
+
"build:ts": "tsc",
|
|
15
|
+
"build": "bun run clean && bun run build:js && bun run build:ts",
|
|
16
|
+
"test": "bun test",
|
|
17
|
+
"test:coverage": "bun test --coverage",
|
|
18
|
+
"typecheck": "tsc --noEmit",
|
|
19
|
+
"prepublishOnly": "bun run build"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"pino": "^10.0.0",
|
|
23
|
+
"pino-pretty": "^13.0.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@elysiumjs/core": "0.6.1"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@elysiumjs/core": "^0.6.1"
|
|
30
|
+
}
|
|
18
31
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Copyright (c) 2026-present Workbud Technologies Inc. All rights reserved.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import type { LoggerInterface } from '@elysiumjs/core';
|
|
16
|
+
import type { LogLevel } from '../types';
|
|
17
|
+
|
|
18
|
+
import { ConsoleLogger } from '@elysiumjs/core';
|
|
19
|
+
|
|
20
|
+
export interface LoggedOptions {
|
|
21
|
+
level?: LogLevel;
|
|
22
|
+
includeArgs?: boolean;
|
|
23
|
+
includeResult?: boolean;
|
|
24
|
+
includeTiming?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Decorator that logs method entry/exit with optional timing.
|
|
29
|
+
*
|
|
30
|
+
* Logger is resolved at CALL TIME (not decorator definition time)
|
|
31
|
+
* to avoid capturing a stale logger reference.
|
|
32
|
+
*
|
|
33
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
34
|
+
*/
|
|
35
|
+
export function Logged(options: LoggedOptions = {}): MethodDecorator {
|
|
36
|
+
return function (
|
|
37
|
+
target: object,
|
|
38
|
+
propertyKey: string | symbol,
|
|
39
|
+
descriptor: TypedPropertyDescriptor<any>
|
|
40
|
+
) {
|
|
41
|
+
const original = descriptor.value;
|
|
42
|
+
const methodName = `${target.constructor.name}.${String(propertyKey)}`;
|
|
43
|
+
|
|
44
|
+
descriptor.value = async function (...args: any[]) {
|
|
45
|
+
const logger: LoggerInterface = (this as any).logger ?? getServiceLogger();
|
|
46
|
+
|
|
47
|
+
const startTime = Date.now();
|
|
48
|
+
|
|
49
|
+
if (options.includeArgs) {
|
|
50
|
+
logger.debug(`[${methodName}] Entry`, { args });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const result = await original.apply(this, args);
|
|
55
|
+
|
|
56
|
+
if (options.includeResult || options.includeTiming) {
|
|
57
|
+
const duration = Date.now() - startTime;
|
|
58
|
+
logger[options.level ?? 'debug'](`[${methodName}] Exit`, {
|
|
59
|
+
...(options.includeResult && { result }),
|
|
60
|
+
...(options.includeTiming && { duration: `${duration}ms` })
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return result;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
const duration = Date.now() - startTime;
|
|
67
|
+
logger.error(`[${methodName}] Error`, {
|
|
68
|
+
error: error instanceof Error ? error.message : error,
|
|
69
|
+
duration: `${duration}ms`
|
|
70
|
+
});
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return descriptor;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function getServiceLogger(): LoggerInterface {
|
|
80
|
+
try {
|
|
81
|
+
const { Service } = require('@elysiumjs/core');
|
|
82
|
+
return Service.get('logger') ?? new ConsoleLogger();
|
|
83
|
+
} catch {
|
|
84
|
+
return new ConsoleLogger();
|
|
85
|
+
}
|
|
86
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Copyright (c) 2026-present Workbud Technologies Inc. All rights reserved.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import type { HermesConfig } from './types';
|
|
16
|
+
|
|
17
|
+
import { Application, Service } from '@elysiumjs/core';
|
|
18
|
+
|
|
19
|
+
import { HermesLogger } from './services/logger.service';
|
|
20
|
+
|
|
21
|
+
// Lazy singleton resolver: reads config from Application on first access.
|
|
22
|
+
let hermesInstance: HermesLogger | null = null;
|
|
23
|
+
const hermesResolver = () => {
|
|
24
|
+
if (!hermesInstance) {
|
|
25
|
+
const app = Service.get<Application>('elysium.app');
|
|
26
|
+
const config = app?.getConfig<Partial<HermesConfig>>('elysium:hermes');
|
|
27
|
+
hermesInstance = new HermesLogger(config ?? {});
|
|
28
|
+
}
|
|
29
|
+
return hermesInstance;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
Service.registerLazy(HermesLogger.name, hermesResolver);
|
|
33
|
+
Service.registerLazy('logger', hermesResolver);
|
|
34
|
+
|
|
35
|
+
export { HermesLogger } from './services/logger.service';
|
|
36
|
+
export { HttpTransport } from './transports/http.transport';
|
|
37
|
+
export type { HttpTransportOptions } from './transports/http.transport';
|
|
38
|
+
export { Logged } from './decorators/logged';
|
|
39
|
+
export type { LoggedOptions } from './decorators/logged';
|
|
40
|
+
export type { HermesConfig, LogLevel, LogFormat, TransportConfig } from './types';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c)
|
|
1
|
+
// Copyright (c) 2026-present Workbud Technologies Inc. All rights reserved.
|
|
2
2
|
//
|
|
3
3
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
// you may not use this file except in compliance with the License.
|
|
@@ -12,52 +12,74 @@
|
|
|
12
12
|
// See the License for the specific language governing permissions and
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
|
|
15
|
-
import type {
|
|
15
|
+
import type { LoggerInterface } from '@elysiumjs/core';
|
|
16
|
+
import type { Logger as PinoLogger } from 'pino';
|
|
17
|
+
import type { HermesConfig } from '../types';
|
|
16
18
|
|
|
17
|
-
import { Service
|
|
19
|
+
import { Service } from '@elysiumjs/core';
|
|
18
20
|
import pino from 'pino';
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
export class LoggerService {
|
|
22
|
-
readonly #pino: Logger;
|
|
22
|
+
import { DEFAULT_CONFIG } from '../types';
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Production-ready logger implementation wrapping Pino.
|
|
26
|
+
* Implements `LoggerInterface` from `@elysiumjs/core`.
|
|
27
|
+
*
|
|
28
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
29
|
+
*/
|
|
30
|
+
export class HermesLogger implements LoggerInterface {
|
|
31
|
+
private pino: PinoLogger;
|
|
32
|
+
private config: HermesConfig;
|
|
33
|
+
|
|
34
|
+
public static make(name: string): HermesLogger {
|
|
35
|
+
return Service.get(HermesLogger)?.child({ name }) ?? new HermesLogger({ name });
|
|
26
36
|
}
|
|
27
37
|
|
|
28
|
-
|
|
29
|
-
|
|
38
|
+
constructor(config: Partial<HermesConfig> = {}) {
|
|
39
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
40
|
+
this.pino = this.createPinoInstance();
|
|
30
41
|
}
|
|
31
42
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this
|
|
35
|
-
|
|
36
|
-
|
|
43
|
+
private createPinoInstance(): PinoLogger {
|
|
44
|
+
const options: pino.LoggerOptions = {
|
|
45
|
+
level: this.config.level,
|
|
46
|
+
name: this.config.name
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
if (this.config.format === 'pretty') {
|
|
50
|
+
return pino(options, pino.transport({ target: 'pino-pretty' }));
|
|
37
51
|
}
|
|
52
|
+
|
|
53
|
+
return pino(options);
|
|
38
54
|
}
|
|
39
55
|
|
|
40
|
-
public
|
|
41
|
-
|
|
42
|
-
this.#pino.error(details, message);
|
|
43
|
-
} else {
|
|
44
|
-
this.#pino.error(message);
|
|
45
|
-
}
|
|
56
|
+
public trace(msg: string, ctx?: Record<string, unknown>): void {
|
|
57
|
+
this.pino.trace(ctx ?? {}, msg);
|
|
46
58
|
}
|
|
47
59
|
|
|
48
|
-
public
|
|
49
|
-
|
|
50
|
-
this.#pino.error(details, message);
|
|
51
|
-
} else {
|
|
52
|
-
this.#pino.warn(message);
|
|
53
|
-
}
|
|
60
|
+
public debug(msg: string, ctx?: Record<string, unknown>): void {
|
|
61
|
+
this.pino.debug(ctx ?? {}, msg);
|
|
54
62
|
}
|
|
55
63
|
|
|
56
|
-
public
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
64
|
+
public info(msg: string, ctx?: Record<string, unknown>): void {
|
|
65
|
+
this.pino.info(ctx ?? {}, msg);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public warn(msg: string, ctx?: Record<string, unknown>): void {
|
|
69
|
+
this.pino.warn(ctx ?? {}, msg);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public error(msg: string, ctx?: Record<string, unknown>): void {
|
|
73
|
+
this.pino.error(ctx ?? {}, msg);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public fatal(msg: string, ctx?: Record<string, unknown>): void {
|
|
77
|
+
this.pino.fatal(ctx ?? {}, msg);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public child(ctx: Record<string, unknown>): HermesLogger {
|
|
81
|
+
const child = Object.create(this) as HermesLogger;
|
|
82
|
+
child.pino = this.pino.child(ctx);
|
|
83
|
+
return child;
|
|
62
84
|
}
|
|
63
85
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Copyright (c) 2026-present Workbud Technologies Inc. All rights reserved.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
export interface HttpTransportOptions {
|
|
16
|
+
url: string;
|
|
17
|
+
headers?: Record<string, string>;
|
|
18
|
+
batchSize?: number;
|
|
19
|
+
flushInterval?: number;
|
|
20
|
+
maxBufferSize?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* HTTP transport for batching and sending logs to a remote endpoint.
|
|
25
|
+
*
|
|
26
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
27
|
+
*/
|
|
28
|
+
export class HttpTransport {
|
|
29
|
+
private buffer: string[] = [];
|
|
30
|
+
private flushTimer?: ReturnType<typeof setInterval>;
|
|
31
|
+
private maxBufferSize: number;
|
|
32
|
+
|
|
33
|
+
constructor(private options: HttpTransportOptions) {
|
|
34
|
+
this.options.batchSize ??= 100;
|
|
35
|
+
this.options.flushInterval ??= 5000;
|
|
36
|
+
this.maxBufferSize = this.options.maxBufferSize ?? 10_000;
|
|
37
|
+
|
|
38
|
+
this.flushTimer = setInterval(() => this.flush(), this.options.flushInterval);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public write(formatted: string): void {
|
|
42
|
+
if (this.buffer.length >= this.maxBufferSize) {
|
|
43
|
+
this.buffer.shift();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
this.buffer.push(formatted);
|
|
47
|
+
|
|
48
|
+
if (this.buffer.length >= this.options.batchSize!) {
|
|
49
|
+
this.flush();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public async flush(): Promise<void> {
|
|
54
|
+
if (this.buffer.length === 0) return;
|
|
55
|
+
|
|
56
|
+
const batch = this.buffer.splice(0);
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
await fetch(this.options.url, {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: {
|
|
62
|
+
'Content-Type': 'application/json',
|
|
63
|
+
...this.options.headers
|
|
64
|
+
},
|
|
65
|
+
body: JSON.stringify({ logs: batch })
|
|
66
|
+
});
|
|
67
|
+
} catch {
|
|
68
|
+
const space = this.maxBufferSize - this.buffer.length;
|
|
69
|
+
if (space > 0) {
|
|
70
|
+
this.buffer.unshift(...batch.slice(0, space));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public async close(): Promise<void> {
|
|
76
|
+
if (this.flushTimer) clearInterval(this.flushTimer);
|
|
77
|
+
await this.flush();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c)
|
|
1
|
+
// Copyright (c) 2026-present Workbud Technologies Inc. All rights reserved.
|
|
2
2
|
//
|
|
3
3
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
// you may not use this file except in compliance with the License.
|
|
@@ -12,9 +12,23 @@
|
|
|
12
12
|
// See the License for the specific language governing permissions and
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
import pino from 'pino';
|
|
15
|
+
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
export type LogFormat = 'json' | 'pretty' | 'logfmt';
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
export interface TransportConfig {
|
|
20
|
+
type: 'console' | 'file' | 'http';
|
|
21
|
+
options?: Record<string, unknown>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface HermesConfig {
|
|
25
|
+
name?: string;
|
|
26
|
+
level: LogLevel;
|
|
27
|
+
format: LogFormat;
|
|
28
|
+
transports?: TransportConfig[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const DEFAULT_CONFIG: HermesConfig = {
|
|
32
|
+
level: 'info',
|
|
33
|
+
format: 'json'
|
|
34
|
+
};
|