Skip to content

Commit 2768088

Browse files
authored
Merge pull request #367 from objectstack-ai/copilot/add-configurable-logging-capability
2 parents ee8956a + d9adde6 commit 2768088

13 files changed

Lines changed: 1513 additions & 71 deletions

File tree

examples/basic/logger-example.ts

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
/**
2+
* Logger Example
3+
*
4+
* This example demonstrates the configurable logging capabilities
5+
* of ObjectStack Kernel that work in both Node.js and browser environments.
6+
*
7+
* Node.js: Uses Pino for high-performance structured logging
8+
* Browser: Uses simple console-based logger
9+
*/
10+
11+
import { ObjectKernel, createLogger, type Plugin, type PluginContext } from '@objectstack/core';
12+
13+
// Example 1: Kernel with Different Logger Configurations
14+
async function exampleKernelLogging() {
15+
console.log('\n=== Example 1: Kernel with Different Logger Configurations ===\n');
16+
17+
// Pretty format logger (colored output)
18+
const kernel = new ObjectKernel({
19+
logger: {
20+
level: 'debug',
21+
format: 'pretty'
22+
}
23+
});
24+
25+
const testPlugin: Plugin = {
26+
name: 'test-plugin',
27+
init: async (ctx: PluginContext) => {
28+
ctx.logger.info('Plugin initialized', { version: '1.0.0' });
29+
}
30+
};
31+
32+
console.log('Starting kernel with pretty format:');
33+
kernel.use(testPlugin);
34+
await kernel.bootstrap();
35+
await kernel.shutdown();
36+
}
37+
38+
// Example 2: Standalone Logger Usage
39+
async function exampleStandaloneLogger() {
40+
console.log('\n=== Example 2: Standalone Logger Usage ===\n');
41+
42+
const logger = createLogger({
43+
level: 'debug',
44+
format: 'pretty',
45+
sourceLocation: false
46+
});
47+
48+
// Basic logging
49+
logger.debug('Debug message for development');
50+
logger.info('Application started');
51+
logger.warn('Resource usage is high', { cpu: 85, memory: 90 });
52+
53+
// Error logging
54+
try {
55+
throw new Error('Something went wrong');
56+
} catch (error) {
57+
logger.error('Operation failed', error as Error, { operation: 'database-query' });
58+
}
59+
60+
await logger.destroy();
61+
}
62+
63+
// Example 3: Child Loggers with Context
64+
async function exampleChildLoggers() {
65+
console.log('\n=== Example 3: Child Loggers with Context ===\n');
66+
67+
const logger = createLogger({
68+
level: 'info',
69+
format: 'json'
70+
});
71+
72+
// Create a child logger for API requests
73+
const apiLogger = logger.child({
74+
component: 'api',
75+
version: 'v1'
76+
});
77+
78+
// Create request-specific logger
79+
const requestLogger = apiLogger.child({
80+
requestId: 'req-123',
81+
userId: 'user-456',
82+
method: 'POST',
83+
path: '/api/users'
84+
});
85+
86+
requestLogger.info('Request received');
87+
requestLogger.info('Processing request');
88+
requestLogger.info('Request completed', { duration: 125 });
89+
90+
// Note: Only destroy the parent logger; child loggers share the same file writer
91+
await logger.destroy();
92+
}
93+
94+
// Example 4: Distributed Tracing
95+
async function exampleDistributedTracing() {
96+
console.log('\n=== Example 4: Distributed Tracing ===\n');
97+
98+
const logger = createLogger({
99+
level: 'info',
100+
format: 'json'
101+
});
102+
103+
// Simulate distributed trace
104+
const traceId = 'trace-abc-123';
105+
const spanId = 'span-xyz-789';
106+
107+
const tracedLogger = logger.withTrace(traceId, spanId);
108+
109+
tracedLogger.info('Starting distributed operation');
110+
tracedLogger.info('Calling remote service');
111+
tracedLogger.info('Operation completed');
112+
113+
await logger.destroy();
114+
}
115+
116+
// Example 5: Sensitive Data Redaction
117+
async function exampleSensitiveDataRedaction() {
118+
console.log('\n=== Example 5: Sensitive Data Redaction ===\n');
119+
120+
const logger = createLogger({
121+
level: 'info',
122+
format: 'json',
123+
redact: ['password', 'token', 'apiKey', 'creditCard']
124+
});
125+
126+
// Sensitive data will be automatically redacted
127+
logger.info('User login attempt', {
128+
username: 'john.doe',
129+
password: 'super-secret-123', // Will be redacted
130+
email: 'john@example.com'
131+
});
132+
133+
logger.info('API call', {
134+
endpoint: '/api/payment',
135+
apiKey: 'sk_live_123456789', // Will be redacted
136+
amount: 100
137+
});
138+
139+
logger.info('Payment processing', {
140+
userId: 'user-123',
141+
creditCard: '4111-1111-1111-1111', // Will be redacted
142+
amount: 99.99
143+
});
144+
145+
await logger.destroy();
146+
}
147+
148+
// Example 6: Plugin with Logger
149+
async function examplePluginLogging() {
150+
console.log('\n=== Example 6: Plugin with Logger ===\n');
151+
152+
const databasePlugin: Plugin = {
153+
name: 'database',
154+
155+
init: async (ctx: PluginContext) => {
156+
ctx.logger.info('Connecting to database', {
157+
host: 'localhost',
158+
port: 5432,
159+
database: 'myapp'
160+
});
161+
162+
// Simulate connection
163+
await new Promise(resolve => setTimeout(resolve, 100));
164+
165+
const db = { connected: true };
166+
ctx.registerService('db', db);
167+
168+
ctx.logger.info('Database connected successfully');
169+
},
170+
171+
start: async (ctx: PluginContext) => {
172+
ctx.logger.info('Database plugin started');
173+
},
174+
175+
destroy: async () => {
176+
console.log('[Database] Disconnecting...');
177+
}
178+
};
179+
180+
const apiPlugin: Plugin = {
181+
name: 'api',
182+
dependencies: ['database'],
183+
184+
init: async (ctx: PluginContext) => {
185+
const db = ctx.getService('db');
186+
ctx.logger.info('API plugin initialized', { dbConnected: db.connected });
187+
188+
ctx.registerService('api', { server: 'http://localhost:3000' });
189+
},
190+
191+
start: async (ctx: PluginContext) => {
192+
ctx.logger.info('API server starting', { port: 3000 });
193+
ctx.logger.info('API server ready');
194+
}
195+
};
196+
197+
const kernel = new ObjectKernel({
198+
logger: {
199+
level: 'info',
200+
format: 'pretty'
201+
}
202+
});
203+
204+
kernel.use(databasePlugin);
205+
kernel.use(apiPlugin);
206+
207+
await kernel.bootstrap();
208+
await kernel.shutdown();
209+
}
210+
211+
// Example 7: Different Log Formats
212+
async function exampleLogFormats() {
213+
console.log('\n=== Example 7: Different Log Formats ===\n');
214+
215+
const message = 'User action';
216+
const metadata = { userId: '123', action: 'create', resource: 'document' };
217+
218+
console.log('JSON format:');
219+
const jsonLogger = createLogger({ format: 'json' });
220+
jsonLogger.info(message, metadata);
221+
await jsonLogger.destroy();
222+
223+
console.log('\nText format:');
224+
const textLogger = createLogger({ format: 'text' });
225+
textLogger.info(message, metadata);
226+
await textLogger.destroy();
227+
228+
console.log('\nPretty format:');
229+
const prettyLogger = createLogger({ format: 'pretty' });
230+
prettyLogger.info(message, metadata);
231+
await prettyLogger.destroy();
232+
}
233+
234+
// Run all examples
235+
async function main() {
236+
console.log('ObjectStack Logger Examples');
237+
console.log('============================\n');
238+
239+
await exampleKernelLogging();
240+
await exampleStandaloneLogger();
241+
await exampleChildLoggers();
242+
await exampleDistributedTracing();
243+
await exampleSensitiveDataRedaction();
244+
await examplePluginLogging();
245+
await exampleLogFormats();
246+
247+
console.log('\n✅ All examples completed!\n');
248+
}
249+
250+
// Run if executed directly
251+
if (import.meta.url === `file://${process.argv[1]}`) {
252+
main().catch(console.error);
253+
}
254+
255+
export {
256+
exampleKernelLogging,
257+
exampleStandaloneLogger,
258+
exampleChildLoggers,
259+
exampleDistributedTracing,
260+
exampleSensitiveDataRedaction,
261+
examplePluginLogging,
262+
exampleLogFormats
263+
};

0 commit comments

Comments
 (0)