@anteros/core 0.0.30 → 0.0.31

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.
@@ -22,7 +22,7 @@ export function LogSlowQuery(): any {
22
22
  const duration = performance.now() - start;
23
23
  const slowMs = cfg.server.logging?.slowQueryMs ?? 200;
24
24
  if (duration >= slowMs) {
25
- logger.warn(`Slow ${propertyKey} (${Math.round(duration)}ms)`, {
25
+ logger.file('warn', `Slow ${propertyKey} (${Math.round(duration)}ms)`, {
26
26
  collection: args[0],
27
27
  tenant: this.tenant_id,
28
28
  duration: Math.round(duration),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@anteros/core",
3
3
  "module": "index.ts",
4
- "version": "0.0.30",
4
+ "version": "0.0.31",
5
5
  "type": "module",
6
6
  "description": "Anteros Core",
7
7
  "private": false,
package/server/boot.ts CHANGED
@@ -177,7 +177,8 @@ async function bootApp(options: BootAppOptions = {} as BootAppOptions) {
177
177
  const remote: any = (server as any).requestIP?.(req);
178
178
  const remoteIp = remote?.address ?? null;
179
179
  const remotePort = remote?.port ?? null;
180
- logger.info(`${req.method} ${url.pathname}${url.search} → ${res.status}`, {
180
+ // File-only: same as the API access log, no console noise.
181
+ logger.file(`${req.method} ${url.pathname}${url.search} → ${res.status}`, {
181
182
  logger: 'http.log.access',
182
183
  status: res.status,
183
184
  duration: Math.round((performance.now() - start) * 10) / 10,
package/server/hono.ts CHANGED
@@ -234,7 +234,8 @@ function createApp(): Hono<{ Variables: HonoVariables }> {
234
234
  const remoteIp = conn?.remote?.address ?? null;
235
235
  const remotePort = conn?.remote?.port ?? null;
236
236
 
237
- logger.info(`${c.req.method} ${uri} → ${c.res.status}`, {
237
+ // File-only: the per-request access log would flood the console.
238
+ logger.file(`${c.req.method} ${uri} → ${c.res.status}`, {
238
239
  logger: 'http.log.access',
239
240
  status: c.res.status,
240
241
  duration: Math.round(duration * 10) / 10,
package/server/mcp.ts CHANGED
@@ -124,7 +124,7 @@ function buildServer(tenantId: string, tools: McpTool[], resources: McpResource[
124
124
  description: t.description,
125
125
  inputSchema: joiToJsonSchema(t.inputSchema),
126
126
  }));
127
- logger.info('MCP tools/list', { method: 'tools/list', tenant: tenantId, count: toolsList.length, duration: ms(start) });
127
+ logger.file('MCP tools/list', { method: 'tools/list', tenant: tenantId, count: toolsList.length, duration: ms(start) });
128
128
  return { tools: toolsList };
129
129
  });
130
130
 
@@ -132,14 +132,14 @@ function buildServer(tenantId: string, tools: McpTool[], resources: McpResource[
132
132
  const start = performance.now();
133
133
  const tool = tools.find((t) => t.name === req.params.name);
134
134
  if (!tool) {
135
- logger.warn('MCP tools/call', { method: 'tools/call', tenant: tenantId, tool: req.params.name, error: 'unknown tool', duration: ms(start) });
135
+ logger.file('warn', 'MCP tools/call', { method: 'tools/call', tenant: tenantId, tool: req.params.name, error: 'unknown tool', duration: ms(start) });
136
136
  throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${req.params.name}`);
137
137
  }
138
138
 
139
139
  const raw = req.params.arguments ?? {};
140
140
  const { error, value } = tool.inputSchema.validate(raw, { allowUnknown: false });
141
141
  if (error) {
142
- logger.warn('MCP tools/call', { method: 'tools/call', tenant: tenantId, tool: req.params.name, args: raw, error: 'invalid arguments', duration: ms(start) });
142
+ logger.file('warn', 'MCP tools/call', { method: 'tools/call', tenant: tenantId, tool: req.params.name, args: raw, error: 'invalid arguments', duration: ms(start) });
143
143
  return {
144
144
  content: [{ type: 'text' as const, text: `Invalid arguments: ${error.message}` }],
145
145
  isError: true,
@@ -155,7 +155,7 @@ function buildServer(tenantId: string, tools: McpTool[], resources: McpResource[
155
155
  const text = typeof result === 'string' ? result : JSON.stringify(result);
156
156
  return { content: [{ type: 'text' as const, text }] };
157
157
  } catch (err: any) {
158
- logger.warn('MCP tools/call', { method: 'tools/call', tenant: tenantId, tool: req.params.name, args: value, error: err?.message ?? 'unknown', duration: ms(start) });
158
+ logger.file('warn', 'MCP tools/call', { method: 'tools/call', tenant: tenantId, tool: req.params.name, args: value, error: err?.message ?? 'unknown', duration: ms(start) });
159
159
  return {
160
160
  content: [{ type: 'text' as const, text: `Error: ${err?.message ?? 'unknown'}` }],
161
161
  isError: true,
@@ -173,7 +173,7 @@ function buildServer(tenantId: string, tools: McpTool[], resources: McpResource[
173
173
  description: r.description,
174
174
  mimeType: r.mimeType,
175
175
  }));
176
- logger.info('MCP resources/list', { method: 'resources/list', tenant: tenantId, count: resourcesList.length, duration: ms(start) });
176
+ logger.file('MCP resources/list', { method: 'resources/list', tenant: tenantId, count: resourcesList.length, duration: ms(start) });
177
177
  return { resources: resourcesList };
178
178
  });
179
179
 
@@ -187,7 +187,7 @@ function buildServer(tenantId: string, tools: McpTool[], resources: McpResource[
187
187
  description: r.description,
188
188
  mimeType: r.mimeType,
189
189
  }));
190
- logger.info('MCP resources/templates/list', { method: 'resources/templates/list', tenant: tenantId, count: templates.length, duration: ms(start) });
190
+ logger.file('MCP resources/templates/list', { method: 'resources/templates/list', tenant: tenantId, count: templates.length, duration: ms(start) });
191
191
  return { resourceTemplates: templates };
192
192
  });
193
193
 
@@ -196,7 +196,7 @@ function buildServer(tenantId: string, tools: McpTool[], resources: McpResource[
196
196
  const uri = req.params.uri;
197
197
  const matched = matchUri(uri, resources);
198
198
  if (!matched) {
199
- logger.warn('MCP resources/read', { method: 'resources/read', tenant: tenantId, uri, error: 'unknown uri', duration: ms(start) });
199
+ logger.file('warn', 'MCP resources/read', { method: 'resources/read', tenant: tenantId, uri, error: 'unknown uri', duration: ms(start) });
200
200
  throw new McpError(ErrorCode.InvalidParams, `Unknown resource URI: ${uri}`);
201
201
  }
202
202
 
@@ -208,10 +208,10 @@ function buildServer(tenantId: string, tools: McpTool[], resources: McpResource[
208
208
  params: matched.params,
209
209
  uri,
210
210
  });
211
- logger.info('MCP resources/read', { method: 'resources/read', tenant: tenantId, uri, resource: matched.resource.name, params: matched.params, duration: ms(start) });
211
+ logger.file('MCP resources/read', { method: 'resources/read', tenant: tenantId, uri, resource: matched.resource.name, params: matched.params, duration: ms(start) });
212
212
  return result;
213
213
  } catch (err: any) {
214
- logger.warn('MCP resources/read', { method: 'resources/read', tenant: tenantId, uri, error: err?.message ?? 'unknown', duration: ms(start) });
214
+ logger.file('warn', 'MCP resources/read', { method: 'resources/read', tenant: tenantId, uri, error: err?.message ?? 'unknown', duration: ms(start) });
215
215
  throw new McpError(ErrorCode.InternalError, `Failed to read resource: ${err?.message ?? 'unknown'}`);
216
216
  }
217
217
  });
@@ -121,4 +121,27 @@ describe("logger", () => {
121
121
  expect(out.some((l) => l.includes("visible info"))).toBe(true);
122
122
  expect(out.some((l) => l.includes("Server started"))).toBe(false);
123
123
  });
124
+
125
+ it("logger.file keeps the level when passed explicitly (never on console)", async () => {
126
+ const out: string[] = [];
127
+ const orig = console.log;
128
+ console.log = (...a: any[]) => { out.push(a.join(" ")); };
129
+
130
+ logger.configure({ dir: path.join(DIR, "filelevel"), file: true, console: true, level: "info" });
131
+ logger.file("default level", { a: 1 }); // 2-arg form → level 'info'
132
+ logger.file("warn", "explicit warn", { b: 2 }); // explicit level kept
133
+ logger.file("error", "explicit error", { c: 3 });
134
+ await flush();
135
+ console.log = orig;
136
+
137
+ const lines = readLogLines("filelevel/anteros.log");
138
+ expect(lines.find((l) => l.msg === "default level")!.level).toBe("info");
139
+ expect(lines.find((l) => l.msg === "explicit warn")!.level).toBe("warn");
140
+ expect(lines.find((l) => l.msg === "explicit warn")!.b).toBe(2);
141
+ expect(lines.find((l) => l.msg === "explicit error")!.level).toBe("error");
142
+ // never on the console, whatever the level
143
+ expect(out.some((l) => l.includes("default level"))).toBe(false);
144
+ expect(out.some((l) => l.includes("explicit warn"))).toBe(false);
145
+ expect(out.some((l) => l.includes("explicit error"))).toBe(false);
146
+ });
124
147
  });
package/utils/logger.ts CHANGED
@@ -186,8 +186,20 @@ class Logger {
186
186
  warn(msg: string, meta?: unknown) { this.#write('warn', msg, meta); }
187
187
  error(msg: string, meta?: unknown) { this.#write('error', msg, meta); }
188
188
 
189
- /** Write to the file only (no console output) — for events that would clutter the terminal */
190
- file(msg: string, meta?: unknown) { this.#write('info', msg, meta, { console: false }); }
189
+ /**
190
+ * Write to the file only (no console output) — for framework-internal events
191
+ * (access log, MCP operations, slow queries) that would clutter the terminal.
192
+ * Level defaults to 'info'; `file('warn', msg, meta)` keeps the level.
193
+ */
194
+ file(msg: string, meta?: unknown): void;
195
+ file(level: LogLevel, msg: string, meta?: unknown): void;
196
+ file(levelOrMsg: LogLevel | string, msgOrMeta?: unknown, meta?: unknown): void {
197
+ if (levelOrMsg === 'debug' || levelOrMsg === 'info' || levelOrMsg === 'warn' || levelOrMsg === 'error') {
198
+ this.#write(levelOrMsg, msgOrMeta as string, meta, { console: false });
199
+ } else {
200
+ this.#write('info', levelOrMsg, msgOrMeta, { console: false });
201
+ }
202
+ }
191
203
 
192
204
  /** Current log file path (empty when file logging is disabled) */
193
205
  get filePath(): string { return this.#filePath; }