Skip to content

Commit da276df

Browse files
committed
feat: add logger middleware demo with simple, advanced, and production configurations
1 parent 9443523 commit da276df

File tree

1 file changed

+296
-0
lines changed

1 file changed

+296
-0
lines changed

demos/logger.ts

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
import {StepFunction, ZeroRequest} from '../index'
2+
import http from '../index'
3+
import {createLogger, simpleLogger} from '../lib/middleware'
4+
import type {LoggerOptions} from '../lib/middleware'
5+
6+
// Create router instance
7+
const {router} = http({})
8+
9+
// Demo 1: Simple Logger (minimal setup)
10+
console.log('🚀 Starting Logger Middleware Demo Server')
11+
console.log('=====================================')
12+
13+
// Basic middleware for context
14+
router.use((req: ZeroRequest, next: StepFunction) => {
15+
req.ctx = {
16+
startTime: Date.now(),
17+
requestId: crypto.randomUUID(),
18+
userAgent: req.headers.get('user-agent') || 'unknown',
19+
}
20+
return next()
21+
})
22+
23+
// Demo 2: Simple logger for basic request logging
24+
router.use('/simple/*', simpleLogger())
25+
26+
// Demo 3: Advanced logger with custom configuration
27+
const advancedLoggerOptions: LoggerOptions = {
28+
pinoOptions: {
29+
level: 'info',
30+
// Use simple formatting instead of pino-pretty for demo
31+
formatters: {
32+
level: (label: string) => {
33+
return {level: label.toUpperCase()}
34+
},
35+
time: () => {
36+
return {time: new Date().toISOString()}
37+
},
38+
},
39+
},
40+
logBody: true,
41+
excludePaths: ['/health', '/metrics'],
42+
serializers: {
43+
req: (req: any) => ({
44+
method: req.method,
45+
url: req.url,
46+
userAgent: req.headers?.get?.('user-agent'),
47+
contentType: req.headers?.get?.('content-type'),
48+
requestId: req.ctx?.requestId,
49+
}),
50+
res: (res: any) => ({
51+
status: res?.status,
52+
contentType: res?.headers?.get?.('content-type'),
53+
responseTime: res?._responseTime,
54+
}),
55+
},
56+
}
57+
58+
router.use('/advanced/*', createLogger(advancedLoggerOptions))
59+
60+
// Demo 4: Production-like logger configuration
61+
const productionLoggerOptions: LoggerOptions = {
62+
pinoOptions: {
63+
level: process.env.LOG_LEVEL || 'info',
64+
base: {
65+
service: '0http-bun-demo',
66+
version: '1.0.0',
67+
environment: process.env.NODE_ENV || 'development',
68+
},
69+
},
70+
logBody: false, // Don't log bodies in production for security
71+
excludePaths: ['/health', '/ping', '/metrics', '/favicon.ico'],
72+
serializers: {
73+
req: (req: any) => ({
74+
method: req.method,
75+
url: req.url,
76+
remoteAddress:
77+
req.headers?.get?.('x-forwarded-for') ||
78+
req.headers?.get?.('x-real-ip') ||
79+
'unknown',
80+
userAgent: req.headers?.get?.('user-agent'),
81+
requestId: req.ctx?.requestId,
82+
userId: req.user?.id,
83+
}),
84+
res: (res: any) => ({
85+
status: res?.status,
86+
duration: res?._responseTime,
87+
size: res?.headers?.get?.('content-length'),
88+
}),
89+
err: (err: any) => ({
90+
type: err?.constructor?.name,
91+
message: err?.message,
92+
stack: process.env.NODE_ENV === 'development' ? err?.stack : undefined,
93+
}),
94+
},
95+
}
96+
97+
router.use('/production/*', createLogger(productionLoggerOptions))
98+
99+
// Routes for testing different scenarios
100+
101+
// Simple routes (with simple logger)
102+
router.get('/simple/hello', (req: ZeroRequest) => {
103+
return Response.json({
104+
message: 'Hello from simple logger!',
105+
timestamp: new Date().toISOString(),
106+
requestId: req.ctx?.requestId,
107+
})
108+
})
109+
110+
router.post('/simple/data', async (req: ZeroRequest) => {
111+
const body = await req.text()
112+
return Response.json({
113+
received: body,
114+
length: body.length,
115+
echo: 'Simple logger POST response',
116+
})
117+
})
118+
119+
// Advanced routes (with detailed logging)
120+
router.get('/advanced/user/:id', (req: ZeroRequest) => {
121+
const userId = req.params?.id
122+
123+
// Simulate processing time
124+
const processingTime = Math.random() * 100
125+
126+
return Response.json({
127+
user: {
128+
id: userId,
129+
name: `User ${userId}`,
130+
email: `user${userId}@example.com`,
131+
createdAt: new Date().toISOString(),
132+
},
133+
meta: {
134+
processingTime: `${processingTime.toFixed(2)}ms`,
135+
requestId: req.ctx?.requestId,
136+
},
137+
})
138+
})
139+
140+
router.post('/advanced/users', async (req: ZeroRequest) => {
141+
try {
142+
const userData = await req.json()
143+
144+
// Simulate user creation
145+
const newUser = {
146+
id: Math.floor(Math.random() * 10000),
147+
...userData,
148+
createdAt: new Date().toISOString(),
149+
}
150+
151+
return Response.json(
152+
{
153+
success: true,
154+
user: newUser,
155+
message: 'User created successfully',
156+
},
157+
{status: 201},
158+
)
159+
} catch (error) {
160+
return Response.json(
161+
{
162+
success: false,
163+
error: 'Invalid JSON payload',
164+
message: 'Please provide valid user data',
165+
},
166+
{status: 400},
167+
)
168+
}
169+
})
170+
171+
// Production routes (with production-level logging)
172+
router.get('/production/api/status', (req: ZeroRequest) => {
173+
return Response.json({
174+
status: 'healthy',
175+
uptime: process.uptime(),
176+
timestamp: new Date().toISOString(),
177+
version: '1.0.0',
178+
environment: process.env.NODE_ENV || 'development',
179+
})
180+
})
181+
182+
router.get('/production/api/users/:id/profile', (req: ZeroRequest) => {
183+
const userId = req.params?.id
184+
185+
// Simulate auth check
186+
const isAuthorized = req.headers.get('authorization') !== null
187+
188+
if (!isAuthorized) {
189+
return Response.json(
190+
{
191+
error: 'Unauthorized',
192+
message: 'Authentication required',
193+
},
194+
{status: 401},
195+
)
196+
}
197+
198+
return Response.json({
199+
profile: {
200+
id: userId,
201+
name: `Production User ${userId}`,
202+
role: 'user',
203+
lastLogin: new Date().toISOString(),
204+
},
205+
requestId: req.ctx?.requestId,
206+
})
207+
})
208+
209+
// Error demonstration route
210+
router.get('/advanced/error', (req: ZeroRequest) => {
211+
// Simulate an error for logging demonstration
212+
throw new Error('Intentional error for logging demo')
213+
})
214+
215+
// Health check (excluded from logging)
216+
router.get('/health', (req: ZeroRequest) => {
217+
return Response.json({status: 'OK', timestamp: new Date().toISOString()})
218+
})
219+
220+
// Metrics endpoint (excluded from logging)
221+
router.get('/metrics', (req: ZeroRequest) => {
222+
return new Response(
223+
`# HELP requests_total Total requests
224+
# TYPE requests_total counter
225+
requests_total 42
226+
`,
227+
{
228+
headers: {'Content-Type': 'text/plain'},
229+
},
230+
)
231+
})
232+
233+
// Root endpoint with demo information
234+
router.get('/', (req: ZeroRequest) => {
235+
return Response.json(
236+
{
237+
message: '0http-bun Logger Middleware Demo',
238+
endpoints: {
239+
simple: {
240+
'/simple/hello': 'GET - Simple hello endpoint with basic logging',
241+
'/simple/data': 'POST - Echo endpoint with simple logging',
242+
},
243+
advanced: {
244+
'/advanced/user/:id': 'GET - User details with advanced logging',
245+
'/advanced/users': 'POST - Create user with body logging',
246+
'/advanced/error': 'GET - Error demonstration',
247+
},
248+
production: {
249+
'/production/api/status':
250+
'GET - System status with production logging',
251+
'/production/api/users/:id/profile':
252+
'GET - User profile (requires auth header)',
253+
},
254+
utility: {
255+
'/health': 'GET - Health check (excluded from logs)',
256+
'/metrics': 'GET - Metrics endpoint (excluded from logs)',
257+
},
258+
},
259+
instructions: {
260+
testCommands: [
261+
'curl http://localhost:3000/simple/hello',
262+
'curl -X POST http://localhost:3000/simple/data -d "test data"',
263+
'curl http://localhost:3000/advanced/user/123',
264+
'curl -X POST http://localhost:3000/advanced/users -H "Content-Type: application/json" -d \'{"name":"John","email":"[email protected]"}\'',
265+
'curl http://localhost:3000/advanced/error',
266+
'curl http://localhost:3000/production/api/status',
267+
'curl -H "Authorization: Bearer token" http://localhost:3000/production/api/users/456/profile',
268+
],
269+
},
270+
},
271+
{
272+
headers: {
273+
'Content-Type': 'application/json; charset=utf-8',
274+
},
275+
},
276+
)
277+
})
278+
279+
// Start the server
280+
const port = process.env.PORT ? parseInt(process.env.PORT) : 3000
281+
282+
console.log(`\n🌟 Logger Demo Features:`)
283+
console.log(` • Simple Logger: /simple/* routes`)
284+
console.log(` • Advanced Logger: /advanced/* routes (with body logging)`)
285+
console.log(` • Production Logger: /production/* routes`)
286+
console.log(` • Health/Metrics: excluded from logging`)
287+
console.log(`\n📋 Test the different logging levels:`)
288+
console.log(` curl http://localhost:${port}/`)
289+
console.log(` curl http://localhost:${port}/simple/hello`)
290+
console.log(` curl http://localhost:${port}/advanced/user/123`)
291+
console.log(` curl http://localhost:${port}/production/api/status`)
292+
293+
export default {
294+
port,
295+
fetch: router.fetch.bind(router),
296+
}

0 commit comments

Comments
 (0)