Skip to content

feat: Add structured logging throughout core for plugin developer debuggability - #368

Merged
hotlong merged 4 commits into
mainfrom
copilot/add-debug-logs-to-kernel
Jan 29, 2026
Merged

hotlong merged 4 commits into
mainfrom
copilot/add-debug-logs-to-kernel

Conversation

Copilot AI commented Jan 29, 2026 •

Copy link
Copy Markdown
Contributor

Plugin developers lacked visibility into runtime behavior. Most packages used console.log or had no logging at all.

Changes

Logging Infrastructure

  • Replaced console.log with structured logger (Pino for Node.js, console fallback for browser)
  • Added logger to packages: objectql, driver-memory, runtime, client, plugin-hono-server, plugin-msw

ObjectQL Engine (packages/objectql/src/engine.ts)

  • Data operations: find, insert, update, delete with query details and result counts
  • Driver registration and resolution
  • Hook execution with handler counts and error tracking

Driver & Plugins

  • Memory driver: CRUD operations with table statistics
  • Runtime plugins: Lifecycle events (init, start, destroy)
  • HTTP plugins: Request/response logging with status codes
  • Client: HTTP calls with configurable debug mode

Example

Before:

console.log(`[ObjectQL] Registered driver: ${driver.name}`);

After:

this.logger.info('Registered driver', { 
  driverName: driver.name, 
  version: driver.version
});
this.logger.debug('Find operation starting', { object, query });
this.logger.debug('Find operation completed', { object, resultCount: 5 });

Log levels: debug (operations), info (lifecycle), warn (issues), error (failures with stack traces)

Dependencies

Added @objectstack/core to client and examples/basic packages (required for logger import).

Original prompt

完善整个内核的日志,添加必要的调试日志,让插件开发者更容易融入生态。


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@vercel

vercel Bot commented Jan 29, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jan 29, 2026 11:41pm

Request Review

Copilot AI and others added 2 commits January 29, 2026 23:29
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Add comprehensive logging to kernel for debugging feat: Add structured logging throughout core for plugin developer debuggability Jan 29, 2026
Copilot AI requested a review from hotlong January 29, 2026 23:47
@hotlong
hotlong marked this pull request as ready for review January 29, 2026 23:56
Copilot AI review requested due to automatic review settings January 29, 2026 23:56
@hotlong
hotlong merged commit f56c419 into main Jan 29, 2026
4 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds comprehensive structured logging throughout the ObjectStack core packages to improve debuggability for plugin developers. The implementation replaces ad-hoc console.log statements with a structured logger (Pino for Node.js, console fallback for browsers) that provides consistent logging with proper log levels, structured metadata, and contextual information.

Changes:

  • Introduced structured logging infrastructure with Logger interface and createLogger factory function that works in both Node.js and browser environments
  • Added detailed logging to core packages (objectql, driver-memory, runtime, client, plugin-hono-server, plugin-msw) covering lifecycle events, data operations, HTTP requests, and error conditions
  • Added logger dependencies to client and examples/basic packages to support the new logging infrastructure

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
pnpm-lock.yaml Added @objectstack/core dependency to client and examples/basic packages
packages/runtime/src/driver-plugin.ts Replaced console.log with structured logging for driver registration and lifecycle
packages/runtime/src/app-plugin.ts Added detailed logging for app plugin initialization and runtime execution
packages/plugins/plugin-msw/src/msw-plugin.ts Replaced console.log with structured logging for MSW operations and request handling
packages/plugins/plugin-hono-server/src/hono-plugin.ts Added comprehensive logging for HTTP server operations and API route handling
packages/plugins/driver-memory/src/memory-driver.ts Added structured logging for all CRUD operations with statistics
packages/objectql/src/plugin.ts Converted console.log to structured logging for ObjectQL plugin lifecycle
packages/objectql/src/engine.ts Added comprehensive logging for engine initialization, driver operations, and data operations with error tracking
packages/client/src/index.ts Added HTTP request/response logging with optional debug mode
packages/client/package.json Added @objectstack/core dependency
examples/basic/package.json Added @objectstack/core dependency
examples/basic/logger-example.ts Fixed type annotation for service retrieval
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

return hookContext.result;
} catch (e) {
// hookContext.error = e;
this.logger.error('Find operation failed', e as Error, { object });

Copilot AI Jan 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using type assertion e as Error doesn't guarantee that e is actually an Error instance. In JavaScript, catch blocks can catch any value (string, number, object, etc.).

Consider checking the error type:

catch (e) {
  const error = e instanceof Error ? e : new Error(String(e));
  this.logger.error('Find operation failed', error, { object });
  throw error;
}

This pattern appears throughout this file in multiple catch blocks (lines 367, 402, 453, 491, 529).

Copilot uses AI. Check for mistakes.
this.logger.debug('FindOne operation completed', { object, found: !!result });
return result;
} catch (e) {
this.logger.error('FindOne operation failed', e as Error, { object });

Copilot AI Jan 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using type assertion e as Error doesn't guarantee that e is actually an Error instance. Same issue as line 367.

Copilot uses AI. Check for mistakes.
return hookContext.result;
return hookContext.result;
} catch (e) {
this.logger.error('Insert operation failed', e as Error, { object });

Copilot AI Jan 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using type assertion e as Error doesn't guarantee that e is actually an Error instance. Same issue as line 367.

Copilot uses AI. Check for mistakes.
res.json(result);
}
catch(e:any) {
ctx.logger.error('Data update failed', e, { object: req.params.object, id: req.params.id });

Copilot AI Jan 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caught error e (typed as any) is passed directly to the logger without ensuring it's an Error object. This is the same issue as line 100.

Copilot uses AI. Check for mistakes.

return hookContext.result;
} catch (e) {
this.logger.error('Update operation failed', e as Error, { object, id });

Copilot AI Jan 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using type assertion e as Error doesn't guarantee that e is actually an Error instance. Same issue as line 367.

Copilot uses AI. Check for mistakes.
data: result
};
} catch (error) {
this.logger?.error?.('MSW: Create failed', error, { object });

Copilot AI Jan 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caught error is passed directly to the logger without ensuring it's an Error object. In JavaScript, catch blocks can catch any value (string, number, object, etc.), not just Error instances. This could cause issues if the logger expects an Error object.

Consider checking the error type before passing it to the logger:

catch (error) {
  const err = error instanceof Error ? error : new Error(String(error));
  this.logger?.error?.('MSW: Create failed', err, { object });
  // ... rest of the code
}

Copilot uses AI. Check for mistakes.
data: result
};
} catch (error) {
this.logger?.error?.('MSW: Delete failed', error, { object, id });

Copilot AI Jan 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caught error is passed directly to the logger without ensuring it's an Error object. In JavaScript, catch blocks can catch any value (string, number, object, etc.), not just Error instances.

Consider checking the error type before passing it to the logger:

catch (error) {
  const err = error instanceof Error ? error : new Error(String(error));
  this.logger?.error?.('MSW: Delete failed', err, { object, id });
  // ... rest of the code
}

Copilot uses AI. Check for mistakes.
res.status(201).json(result);
}
catch(e:any) {
ctx.logger.error('Data create failed', e, { object: req.params.object });

Copilot AI Jan 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caught error e (typed as any) is passed directly to the logger without ensuring it's an Error object. This is the same issue as line 100.

Copilot uses AI. Check for mistakes.
res.json(result);
}
catch(e:any) {
ctx.logger.error('Data delete failed', e, { object: req.params.object, id: req.params.id });

Copilot AI Jan 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caught error e (typed as any) is passed directly to the logger without ensuring it's an Error object. This is the same issue as line 100.

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +49
this.logger = logger || {
info: console.log,
debug: console.debug,
warn: console.warn,
error: console.error
};

Copilot AI Jan 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fallback logger maps info to console.log, but this is inconsistent with the typical console API where console.info exists. While this works, it's semantically confusing.

Consider using console.info for consistency:

this.logger = logger || { 
    info: console.info, 
    debug: console.debug, 
    warn: console.warn, 
    error: console.error 
};

Copilot uses AI. Check for mistakes.
This was referenced Oct 19, 2026

This branch was successfully deployed

1 active deployment
Preview — bab3d28a Deployed Jan 29, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants