@pori15/logixlysia 6.0.8 → 6.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,49 +1,79 @@
1
- <div align="center">
2
- <h1><code>🦊</code> Logixlysia</h1>
3
- <strong>Logixlysia is a logging library for ElysiaJS</strong>
4
- <img src="https://github.com/PunGrumpy/logixlysia/blob/main/apps/docs/app/opengraph-image.png?raw=true" alt="Logixlysia" width="100%" height="auto" />
5
- </div>
6
-
7
- ## `📩` Installation
8
-
9
- ```bash
10
- bun add logixlysia
11
- ```
12
-
13
- ## `📝` Usage
14
-
15
- ```ts
16
- import { Elysia } from 'elysia'
17
- import logixlysia from 'logixlysia' // or import { logixlysia } from 'logixlysia'
18
-
19
- const app = new Elysia({
20
- name: "Elysia with Logixlysia"
21
- })
22
- .use(
23
- logixlysia({
24
- config: {
25
- showStartupMessage: true,
26
- startupMessageFormat: 'simple',
27
- timestamp: {
28
- translateTime: 'yyyy-mm-dd HH:MM:ss.SSS'
29
- },
30
- logFilePath: './logs/example.log',
31
- ip: true,
32
- customLogFormat:
33
- '🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip}'
34
- }
35
- }))
36
- .get('/', () => {
37
- return { message: 'Welcome to Basic Elysia with Logixlysia' }
38
- })
39
-
40
- app.listen(3000)
41
- ```
42
-
43
- ## `📚` Documentation
44
-
45
- Check out the [website](https://logixlysia.vercel.app) for more detailed documentation and examples.
46
-
47
- ## `📄` License
48
-
49
- Licensed under the [MIT License](LICENSE).
1
+ <div align="center">
2
+ <h1><code>🦊</code> Logixlysia</h1>
3
+ <strong>Logixlysia is a logging library for ElysiaJS</strong>
4
+ <img src="https://github.com/PunGrumpy/logixlysia/blob/main/apps/docs/app/opengraph-image.png?raw=true" alt="Logixlysia" width="100%" height="auto" />
5
+ </div>
6
+
7
+ ## `📩` Installation
8
+
9
+ ```bash
10
+ bun add logixlysia
11
+ ```
12
+
13
+ ## `📝` Usage
14
+
15
+ ### Basic
16
+
17
+ ```ts
18
+ import { Elysia } from 'elysia'
19
+ import logixlysia from 'logixlysia'
20
+
21
+ const app = new Elysia()
22
+ .use(logixlysia())
23
+ .get('/', () => 'Hello World')
24
+ .listen(3000)
25
+ ```
26
+
27
+ ### With Configuration
28
+
29
+ ```ts
30
+ app.use(logixlysia({
31
+ startup: {
32
+ show: true,
33
+ format: 'simple',
34
+ },
35
+ format: {
36
+ timestamp: 'yyyy-mm-dd HH:MM:ss.SSS',
37
+ showIp: true,
38
+ template: '🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip}',
39
+ },
40
+ file: {
41
+ path: './logs/example.log',
42
+ rotation: {
43
+ maxSize: '10m',
44
+ maxFiles: 7,
45
+ compress: true,
46
+ },
47
+ },
48
+ logLevel: ['ERROR', 'WARNING'],
49
+ }))
50
+ ```
51
+
52
+ ## `⚙️` Options
53
+
54
+ | Option | Type | Default | Description |
55
+ |--------|------|---------|-------------|
56
+ | `startup.show` | `boolean` | `true` | Show startup message |
57
+ | `startup.format` | `"simple" \| "banner"` | `"banner"` | Startup message style |
58
+ | `format.colors` | `boolean` | `true` (TTY) | Enable colored output |
59
+ | `format.timestamp` | `string` | — | Timestamp format pattern (e.g. `'yyyy-mm-dd HH:MM:ss.SSS'`) |
60
+ | `format.template` | `string` | — | Custom log format template |
61
+ | `format.showIp` | `boolean` | `false` | Show IP address in logs |
62
+ | `logLevel` | `LogLevel \| LogLevel[]` | — | Filter logs by level(s) |
63
+ | `file` | `false \| { path, rotation? }` | — | File logging config (`false` to disable) |
64
+ | `file.path` | `string` | — | Log file path (required when file logging enabled) |
65
+ | `file.rotation` | `LogRotationConfig` | — | Log file rotation settings |
66
+ | `transports` | `Transport[] \| { targets, only? }` | — | Custom transports |
67
+ | `pino` | `PinoLoggerOptions` | — | Pino logger options |
68
+ | `error.typeBaseUrl` | `string` | — | Base URL for error types (RFC 9457) |
69
+ | `error.errorMap` | `Record<string, ErrorMapping>` | — | Error code to HTTP status mapping |
70
+ | `error.resolve` | `ErrorResolver` | — | Custom error resolver function |
71
+ | `error.verbose` | `boolean` | `false` | Show full error details in console |
72
+
73
+ ## `📚` Documentation
74
+
75
+ Check out the [website](https://logixlysia.vercel.app) for more detailed documentation and examples.
76
+
77
+ ## `📄` License
78
+
79
+ Licensed under the [MIT License](LICENSE).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pori15/logixlysia",
3
- "version": "6.0.8",
3
+ "version": "6.0.9",
4
4
  "description": "🦊 Logixlysia is a logger for Elysia",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -5,7 +5,7 @@ export const startServer = (
5
5
  server: { port?: number; hostname?: string; protocol?: string | null },
6
6
  options: Options
7
7
  ): void => {
8
- const showStartupMessage = options.config?.showStartupMessage ?? true;
8
+ const showStartupMessage = options.startup?.show ?? true;
9
9
  if (!showStartupMessage) {
10
10
  return;
11
11
  }
@@ -18,7 +18,7 @@ export const startServer = (
18
18
  const url = `${protocol}://${hostname}:${port}`;
19
19
  const message = `🦊 Elysia is running at ${url}`;
20
20
 
21
- const format = options.config?.startupMessageFormat ?? "banner";
21
+ const format = options.startup?.format ?? "banner";
22
22
  if (format === "simple") {
23
23
  console.log(message);
24
24
  return;
package/src/index.ts CHANGED
@@ -52,7 +52,7 @@ export const logixlysia = (options: Options = {}): Logixlysia => {
52
52
  name: "Logixlysia",
53
53
  });
54
54
 
55
- const errorConfig = options.config?.error;
55
+ const errorConfig = options.error;
56
56
 
57
57
  return (
58
58
  app
@@ -131,16 +131,21 @@ export { normalizeToProblem } from "./utils/handle-error";
131
131
  // ==========================================
132
132
 
133
133
  export type {
134
+ ErrorConfig,
134
135
  ErrorMapping,
135
136
  ErrorResolver,
137
+ FileConfig,
138
+ FormatConfig,
136
139
  Logger,
137
140
  LogixlysiaContext,
138
141
  LogixlysiaStore,
139
142
  LogLevel,
140
143
  Options,
141
144
  Pino,
145
+ StartupConfig,
142
146
  StoreData,
143
147
  Transport,
148
+ TransportsConfig,
144
149
  } from "./interfaces";
145
150
 
146
151
  export default logixlysia;
package/src/interfaces.ts CHANGED
@@ -5,15 +5,21 @@ import type {
5
5
  import type { ProblemError } from "./error/errors";
6
6
  import type { Code } from "./error/type";
7
7
 
8
+ /** Pino Logger 实例类型 */
8
9
  export type Pino = PinoLogger<never, boolean>;
9
10
 
11
+ /** 日志级别 */
10
12
  export type LogLevel = "DEBUG" | "INFO" | "WARNING" | "ERROR";
11
13
 
14
+ /** 单次请求携带的计时和路径数据 */
12
15
  export interface StoreData {
16
+ /** 请求开始的纳秒时间戳(hrtime) */
13
17
  beforeTime: bigint;
18
+ /** 缓存的 URL pathname,避免重复解析 */
14
19
  pathname: string;
15
20
  }
16
21
 
22
+ /** Elysia store 中挂载的 logixlysia 状态 */
17
23
  export interface LogixlysiaStore {
18
24
  beforeTime?: bigint;
19
25
  logger: Logger;
@@ -22,7 +28,15 @@ export interface LogixlysiaStore {
22
28
  [key: string]: unknown;
23
29
  }
24
30
 
31
+ /** 自定义日志传输接口(如 Elasticsearch、Slack 等) */
25
32
  export interface Transport {
33
+ /**
34
+ * 接收一条日志并输出到外部系统
35
+ *
36
+ * @param level - 日志级别
37
+ * @param message - 日志消息
38
+ * @param meta - 附加元数据(请求信息、耗时等)
39
+ */
26
40
  log: (
27
41
  level: LogLevel,
28
42
  message: string,
@@ -30,41 +44,39 @@ export interface Transport {
30
44
  ) => void | Promise<void>;
31
45
  }
32
46
 
47
+ /** 日志文件轮转配置 */
33
48
  export interface LogRotationConfig {
49
+ /** 轮转后是否压缩旧文件 */
34
50
  compress?: boolean;
51
+ /** 压缩算法 */
35
52
  compression?: "gzip";
36
- /**
37
- * Rotate at a fixed interval, e.g. '1d', '12h'.
38
- */
53
+ /** 固定间隔轮转,如 `'1d'`、`'12h'` */
39
54
  interval?: string;
40
- /**
41
- * Keep at most N files or keep files for a duration like '7d'.
42
- */
55
+ /** 保留的最大文件数量或时长,如 `10` 或 `'7d'` */
43
56
  maxFiles?: number | string;
44
- /**
45
- * Max log file size before rotation, e.g. '10m', '5k', or a byte count.
46
- */
57
+ /** 单个日志文件最大体积,如 `'10m'`、`'5k'`,或字节数 */
47
58
  maxSize?: string | number;
48
59
  }
49
60
 
50
- export interface LogFilter {
51
- /**
52
- * Array of log levels to allow. If specified, only logs with these levels will be processed.
53
- * If not specified, all log levels will be allowed.
54
- */
55
- level?: LogLevel[];
56
- }
57
-
58
61
  // ==========================================
59
62
  // Error Mapping
60
63
  // ==========================================
61
64
 
65
+ /** 错误码到 HTTP 响应的映射条目 */
62
66
  export interface ErrorMapping {
67
+ /** 错误详情描述 */
63
68
  detail?: string;
69
+ /** HTTP 状态码 */
64
70
  status: number;
71
+ /** 错误标题 */
65
72
  title: string;
66
73
  }
67
74
 
75
+ /**
76
+ * 自定义错误解析回调
77
+ *
78
+ * 返回 `ProblemError` 表示已处理,返回 `void` 交给下一层处理
79
+ */
68
80
  export type ErrorResolver = (
69
81
  error: unknown,
70
82
  context: { code: Code; path: string; request: Request }
@@ -74,112 +86,113 @@ export type ErrorResolver = (
74
86
  // Options
75
87
  // ==========================================
76
88
 
89
+ /** 启动消息配置 */
90
+ export interface StartupConfig {
91
+ /** 启动消息格式,默认 `"banner"` */
92
+ format?: "simple" | "banner";
93
+ /** 是否显示启动消息,默认 `true` */
94
+ show?: boolean;
95
+ }
96
+
97
+ /** 日志格式配置 */
98
+ export interface FormatConfig {
99
+ /** 是否启用彩色输出,默认 `true`(仅 TTY) */
100
+ colors?: boolean;
101
+ /** 是否在日志中显示请求 IP,默认 `false` */
102
+ showIp?: boolean;
103
+ /** 自定义日志模板,如 `'🦊 {now} {level} {method} {pathname} {status}'` */
104
+ template?: string;
105
+ /** 时间戳格式,如 `'yyyy-mm-dd HH:MM:ss.SSS'` */
106
+ timestamp?: string;
107
+ }
108
+
109
+ /** 文件日志配置 */
110
+ export interface FileConfig {
111
+ /** 日志文件路径(必填) */
112
+ path: string;
113
+ /** 日志轮转配置 */
114
+ rotation?: LogRotationConfig;
115
+ }
116
+
117
+ /** 自定义传输配置 */
118
+ export interface TransportsConfig {
119
+ /** 设为 `true` 时只使用 transports,禁用控制台和文件输出 */
120
+ only?: boolean;
121
+ /** 传输目标列表 */
122
+ targets: Transport[];
123
+ }
124
+
125
+ /** 错误处理配置 */
126
+ export interface ErrorConfig {
127
+ /** 错误码映射表(Postgres / MySQL / 自定义错误码) */
128
+ errorMap?: Record<string, ErrorMapping>;
129
+ /** 自定义错误解析回调 */
130
+ resolve?: ErrorResolver;
131
+ /** 自定义错误类型的 Base URL(RFC 9457) */
132
+ typeBaseUrl?: string;
133
+ /** 是否在控制台显示完整错误详情(detail、extensions),默认 `false` */
134
+ verbose?: boolean;
135
+ }
136
+
137
+ /** Logixlysia 插件配置 */
77
138
  export interface Options {
78
- config?: {
79
- showStartupMessage?: boolean;
80
- startupMessageFormat?: "simple" | "banner";
81
- useColors?: boolean;
82
- ip?: boolean;
83
- timestamp?: {
84
- translateTime?: string;
85
- };
86
- customLogFormat?: string;
87
-
88
- // Filtering
89
- logFilter?: LogFilter;
90
-
91
- // Outputs
92
- transports?: Transport[];
93
- useTransportsOnly?: boolean;
94
- disableInternalLogger?: boolean;
95
- disableFileLogging?: boolean;
96
- logFilePath?: string;
97
- logRotation?: LogRotationConfig;
98
-
99
- // Pino
100
- pino?: (PinoLoggerOptions & { prettyPrint?: boolean }) | undefined;
101
-
102
- // Error handling
103
- error?: {
104
- /**
105
- * 自定义错误类型的 Base URL
106
- * @example "https://api.mysite.com/errors"
107
- */
108
- typeBaseUrl?: string;
109
-
110
- /**
111
- * 错误码映射表(Postgres / MySQL / 自定义错误码)
112
- * 键为错误码字符串,值为 ProblemError 字段
113
- *
114
- * @example
115
- * ```ts
116
- * errorMap: {
117
- * '23505': { status: 409, title: 'Resource already exists', detail: 'Unique constraint violation' },
118
- * '23503': { status: 400, title: 'Foreign key constraint failed' },
119
- * 'ER_DUP_ENTRY': { status: 409, title: 'Duplicate entry' },
120
- * }
121
- * ```
122
- */
123
- errorMap?: Record<string, ErrorMapping>;
124
-
125
- /**
126
- * 用户自定义错误解析回调
127
- * 返回 ProblemError 表示已处理,返回 void 表示交给下一层
128
- *
129
- * @example
130
- * ```ts
131
- * resolve(error, { code, path }) {
132
- * if (isStripeError(error)) {
133
- * return createProblem(402, { detail: error.message })
134
- * }
135
- * // return void → 交给下一层
136
- * }
137
- * ```
138
- */
139
- resolve?: ErrorResolver;
140
-
141
- /**
142
- * 是否在控制台显示完整的错误详情(包括 detail 和 extensions)
143
- * @default false
144
- */
145
- verboseErrorLogging?: boolean;
146
- };
147
- };
139
+ /** 错误处理配置 */
140
+ error?: ErrorConfig;
141
+ /** 文件日志配置,设为 `false` 禁用文件日志 */
142
+ file?: false | FileConfig;
143
+ /** 日志格式配置 */
144
+ format?: FormatConfig;
145
+ /** 日志级别过滤,接受单个级别或级别数组 */
146
+ logLevel?: LogLevel | LogLevel[];
147
+ /** Pino Logger 原生配置透传 */
148
+ pino?: PinoLoggerOptions;
149
+ /** 启动消息配置 */
150
+ startup?: StartupConfig;
151
+ /** 自定义传输(数组或带 `only` 选项的对象) */
152
+ transports?: Transport[] | TransportsConfig;
148
153
  }
149
154
 
150
155
  // ==========================================
151
156
  // Logger
152
157
  // ==========================================
153
158
 
159
+ /** Logger 实例,可通过 `store.logger` 访问 */
154
160
  export interface Logger {
161
+ /** 记录 DEBUG 级别日志 */
155
162
  debug: (
156
163
  request: Request,
157
164
  message: string,
158
165
  context?: Record<string, unknown>
159
166
  ) => void;
167
+ /** 记录 ERROR 级别日志 */
160
168
  error: (
161
169
  request: Request,
162
170
  message: string,
163
171
  context?: Record<string, unknown>
164
172
  ) => void;
173
+ /** 处理 HTTP 错误并输出日志 */
165
174
  handleHttpError: (
166
175
  request: Request,
167
176
  error: ProblemError,
168
177
  store: StoreData,
169
178
  options: Options
170
179
  ) => void;
180
+ /** 记录 INFO 级别日志 */
171
181
  info: (
172
182
  request: Request,
173
183
  message: string,
174
184
  context?: Record<string, unknown>
175
185
  ) => void;
186
+ /** 记录指定级别的日志 */
176
187
  log: (
177
188
  level: LogLevel,
178
189
  request: Request,
179
190
  data: Record<string, unknown>,
180
191
  store: StoreData
181
192
  ) => void;
193
+ /** 底层 Pino Logger 实例 */
182
194
  pino: Pino;
195
+ /** 记录 WARNING 级别日志 */
183
196
  warn: (
184
197
  request: Request,
185
198
  message: string,
@@ -187,6 +200,7 @@ export interface Logger {
187
200
  ) => void;
188
201
  }
189
202
 
203
+ /** Logixlysia 请求上下文 */
190
204
  export interface LogixlysiaContext {
191
205
  request: Request;
192
206
  store: LogixlysiaStore;
@@ -4,8 +4,7 @@ import type { LogLevel, Options, Pino, StoreData } from "../interfaces";
4
4
  import { pad2, pad3 } from "../utils/format";
5
5
 
6
6
  const shouldUseColors = (options: Options): boolean => {
7
- const config = options.config;
8
- const enabledByConfig = config?.useColors ?? true;
7
+ const enabledByConfig = options.format?.colors ?? true;
9
8
 
10
9
  // Avoid ANSI sequences in non-interactive output (pipes, CI logs, files).
11
10
  const isTty =
@@ -169,15 +168,15 @@ export const formatLine = ({
169
168
  store: StoreData;
170
169
  options: Options;
171
170
  }): string => {
172
- const config = options.config;
171
+ const fmt = options.format;
173
172
  const useColors = shouldUseColors(options);
174
173
  const format =
175
- config?.customLogFormat ??
174
+ fmt?.template ??
176
175
  "🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip} {context}";
177
176
 
178
177
  const now = new Date();
179
178
  const epoch = String(now.getTime());
180
- const rawTimestamp = formatTimestamp(now, config?.timestamp?.translateTime);
179
+ const rawTimestamp = formatTimestamp(now, fmt?.timestamp);
181
180
  const timestamp = getColoredTimestamp(rawTimestamp, useColors);
182
181
 
183
182
  const message = typeof data.message === "string" ? data.message : "";
@@ -193,7 +192,7 @@ export const formatLine = ({
193
192
  ? 200
194
193
  : getStatusCode(statusValue);
195
194
  const status = String(statusCode);
196
- const ip = config?.ip === true ? getIp(request) : "";
195
+ const ip = fmt?.showIp === true ? getIp(request) : "";
197
196
  const ctxString = getContextString(data.context);
198
197
  const coloredLevel = getColoredLevel(level, useColors);
199
198
  const coloredMethod = getColoredMethod(request.method, useColors);
@@ -1,8 +1,22 @@
1
1
  import type { ProblemError } from "../error/errors";
2
- import type { LogLevel, Options, StoreData } from "../interfaces";
2
+ import type {
3
+ LogLevel,
4
+ Options,
5
+ StoreData,
6
+ Transport,
7
+ TransportsConfig,
8
+ } from "../interfaces";
3
9
  import { logToTransports } from "../output";
4
10
  import { logToFile } from "../output/file";
5
11
 
12
+ const normalizeTransports = (
13
+ transports?: Transport[] | TransportsConfig
14
+ ): { targets: Transport[]; only: boolean } => {
15
+ if (!transports) return { targets: [], only: false };
16
+ if (Array.isArray(transports)) return { targets: transports, only: false };
17
+ return { targets: transports.targets, only: transports.only === true };
18
+ };
19
+
6
20
  /**
7
21
  * 统一输出管道:transports → file → console
8
22
  * handleHttpError 和 log 共用同一管道,不再重复判断配置
@@ -15,27 +29,31 @@ const outputPipeline = (
15
29
  options: Options,
16
30
  consoleMessage?: string
17
31
  ): void => {
18
- const config = options.config;
32
+ const { targets, only: transportsOnly } = normalizeTransports(
33
+ options.transports
34
+ );
19
35
 
20
36
  // 1. Transports
21
- logToTransports({ level, request, data, store, options });
37
+ logToTransports({ level, request, data, store, transports: targets });
22
38
 
23
39
  // 2. File
24
- const useTransportsOnly = config?.useTransportsOnly === true;
25
- const disableFileLogging = config?.disableFileLogging === true;
26
- if (!(useTransportsOnly || disableFileLogging)) {
27
- const filePath = config?.logFilePath;
28
- if (filePath) {
29
- logToFile({ filePath, level, request, data, store, options }).catch(
30
- (e) => {
31
- console.error(e);
32
- }
33
- );
34
- }
40
+ const fileConfig = options.file;
41
+ const hasFile = fileConfig !== false && fileConfig !== undefined;
42
+ if (!transportsOnly && hasFile) {
43
+ logToFile({
44
+ filePath: fileConfig.path,
45
+ level,
46
+ request,
47
+ data,
48
+ store,
49
+ options,
50
+ }).catch((e) => {
51
+ console.error(e);
52
+ });
35
53
  }
36
54
 
37
55
  // 3. Console
38
- if (useTransportsOnly || config?.disableInternalLogger === true) return;
56
+ if (transportsOnly) return;
39
57
 
40
58
  if (consoleMessage) {
41
59
  switch (level) {
@@ -63,7 +81,6 @@ export const handleHttpError = (
63
81
  store: StoreData,
64
82
  options: Options
65
83
  ): void => {
66
- const config = options.config;
67
84
  const level: LogLevel = problem.status >= 500 ? "ERROR" : "WARNING";
68
85
  const rfcData = problem.toJSON();
69
86
  const data = {
@@ -73,17 +90,18 @@ export const handleHttpError = (
73
90
  };
74
91
 
75
92
  // 构建 console 消息
93
+ const { only: transportsOnly } = normalizeTransports(options.transports);
76
94
  let consoleMessage = "";
77
- if (!(config?.useTransportsOnly || config?.disableInternalLogger)) {
95
+ if (!transportsOnly) {
78
96
  let timestamp = "";
79
- if (config?.timestamp) {
97
+ if (options.format?.timestamp) {
80
98
  timestamp = `[${new Date().toISOString()}] `;
81
99
  }
82
100
  const pathname = store.pathname || new URL(request.url).pathname;
83
101
  consoleMessage = `${timestamp}${level} ${request.method} ${pathname} ${problem.status} - ${problem.title}`;
84
102
 
85
103
  // 详细错误日志
86
- if (config?.error?.verboseErrorLogging) {
104
+ if (options.error?.verbose) {
87
105
  const parts = [consoleMessage];
88
106
  if (rfcData.detail) parts.push(` Detail: ${rfcData.detail}`);
89
107
  if (rfcData.instance) parts.push(` Instance: ${rfcData.instance}`);
@@ -1,25 +1,23 @@
1
1
  import pino from "pino";
2
- import type {
3
- LogFilter,
4
- Logger,
5
- LogLevel,
6
- Options,
7
- Pino,
8
- StoreData,
9
- } from "../interfaces";
2
+ import type { Logger, LogLevel, Options, Pino, StoreData } from "../interfaces";
10
3
  import { formatLine } from "./create-logger";
11
4
  import { handleHttpError, outputPipeline } from "./handle-http-error";
12
5
 
13
- export const createLogger = (options: Options = {}): Logger => {
14
- const config = options.config;
15
-
16
- const pinoConfig = config?.pino;
17
- const { prettyPrint, ...pinoOptions } = pinoConfig ?? {};
6
+ const shouldLog = (
7
+ level: LogLevel,
8
+ logLevel?: LogLevel | LogLevel[]
9
+ ): boolean => {
10
+ if (logLevel === undefined) return true;
11
+ const levels = Array.isArray(logLevel) ? logLevel : [logLevel];
12
+ if (levels.length === 0) return true;
13
+ return levels.includes(level);
14
+ };
18
15
 
19
- const shouldPrettyPrint =
20
- prettyPrint === true && pinoOptions.transport === undefined;
16
+ export const createLogger = (options: Options = {}): Logger => {
17
+ const pinoOptions = options.pino ?? {};
18
+ const isPrettyPrint = pinoOptions.transport === undefined;
21
19
 
22
- const pinoLogger: Pino = shouldPrettyPrint
20
+ const pinoLogger: Pino = isPrettyPrint
23
21
  ? pino({
24
22
  ...pinoOptions,
25
23
  level: pinoOptions.level ?? "info",
@@ -29,7 +27,7 @@ export const createLogger = (options: Options = {}): Logger => {
29
27
  target: "pino-pretty",
30
28
  options: {
31
29
  colorize: process.stdout?.isTTY === true,
32
- translateTime: config?.timestamp?.translateTime,
30
+ translateTime: options.format?.timestamp,
33
31
  messageKey: pinoOptions.messageKey,
34
32
  errorKey: pinoOptions.errorKey,
35
33
  },
@@ -42,20 +40,13 @@ export const createLogger = (options: Options = {}): Logger => {
42
40
  errorKey: pinoOptions.errorKey,
43
41
  });
44
42
 
45
- const shouldLog = (level: LogLevel, logFilter?: LogFilter): boolean => {
46
- if (!logFilter?.level || logFilter.level.length === 0) {
47
- return true;
48
- }
49
- return logFilter.level.includes(level);
50
- };
51
-
52
43
  const log = (
53
44
  level: LogLevel,
54
45
  request: Request,
55
46
  data: Record<string, unknown>,
56
47
  store: StoreData
57
48
  ): void => {
58
- if (!shouldLog(level, config?.logFilter)) {
49
+ if (!shouldLog(level, options.logLevel)) {
59
50
  return;
60
51
  }
61
52
 
@@ -27,7 +27,8 @@ export const logToFile = async (input: LogToFileInput): Promise<void> => {
27
27
  await ensureDir(dirname(filePath));
28
28
  await appendFile(filePath, line, { encoding: "utf-8" });
29
29
 
30
- const rotation = options.config?.logRotation;
30
+ const rotation =
31
+ options.file && options.file !== false ? options.file.rotation : undefined;
31
32
  if (!rotation) {
32
33
  return;
33
34
  }
@@ -1,16 +1,15 @@
1
- import type { LogLevel, Options, StoreData } from "../interfaces";
1
+ import type { LogLevel, StoreData, Transport } from "../interfaces";
2
2
 
3
3
  interface LogToTransportsInput {
4
4
  data: Record<string, unknown>;
5
5
  level: LogLevel;
6
- options: Options;
7
6
  request: Request;
8
7
  store: StoreData;
8
+ transports: Transport[];
9
9
  }
10
10
 
11
11
  export const logToTransports = (input: LogToTransportsInput): void => {
12
- const { level, request, data, store, options } = input;
13
- const transports = options.config?.transports ?? [];
12
+ const { level, request, data, store, transports } = input;
14
13
  if (transports.length === 0) {
15
14
  return;
16
15
  }