yinzerflow 0.3.0 → 0.4.0
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 +1 -1
- package/docs/configuration/advanced-configuration-options.md +1 -1
- package/docs/configuration/configuration-patterns.md +1 -1
- package/docs/core/logging.md +130 -0
- package/docs/security/security-overview.md +2 -2
- package/docs/start-here.md +2 -2
- package/example/README.md +11 -0
- package/example/app/handlers/example.ts +27 -0
- package/example/app/index.ts +163 -0
- package/example/app/routes/example.ts +18 -0
- package/example/app/routes/group-example.ts +13 -0
- package/example/app/util/customLogger.ts +166 -0
- package/example/docker-compose.yml +28 -0
- package/example/package.json +16 -0
- package/example/tsconfig.json +54 -0
- package/index.d.ts +45 -24
- package/index.js +24 -14
- package/index.js.map +13 -12
- package/package.json +1 -1
- package/docs/security/logging.md +0 -348
package/package.json
CHANGED
package/docs/security/logging.md
DELETED
|
@@ -1,348 +0,0 @@
|
|
|
1
|
-
# Logging
|
|
2
|
-
|
|
3
|
-
YinzerFlow provides a flexible logging system with built-in Pittsburgh personality and support for custom logging libraries. All framework and user log calls use the familiar `log.info()`, `log.warn()`, `log.error()` interface, which can be routed to custom logging libraries like Winston or Pino.
|
|
4
|
-
|
|
5
|
-
## Configuration
|
|
6
|
-
|
|
7
|
-
Basic setup with default YinzerFlow logger:
|
|
8
|
-
|
|
9
|
-
```typescript
|
|
10
|
-
import { YinzerFlow } from 'yinzerflow';
|
|
11
|
-
|
|
12
|
-
const server = new YinzerFlow({
|
|
13
|
-
logLevel: 'info',
|
|
14
|
-
networkLogs: true
|
|
15
|
-
});
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
### Configuration Options
|
|
19
|
-
|
|
20
|
-
| Option | Type | Default | Description |
|
|
21
|
-
|--------|------|---------|-------------|
|
|
22
|
-
| `logLevel` | `'off' \| 'error' \| 'warn' \| 'info'` | `'warn'` | Application logging level |
|
|
23
|
-
| `networkLogs` | `boolean` | `false` | Enable nginx-style network request logging |
|
|
24
|
-
| `logger` | `Logger` | `undefined` | Custom logger for application logs |
|
|
25
|
-
| `networkLogger` | `Logger` | `undefined` | Custom logger for network logs (optional) |
|
|
26
|
-
|
|
27
|
-
## Examples
|
|
28
|
-
|
|
29
|
-
### Basic Example
|
|
30
|
-
```typescript
|
|
31
|
-
import { YinzerFlow } from 'yinzerflow';
|
|
32
|
-
|
|
33
|
-
const server = new YinzerFlow({
|
|
34
|
-
logLevel: 'info',
|
|
35
|
-
networkLogs: true
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
await server.listen();
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Users can also use the built in logger as well by importing the log directly from yinzerflow
|
|
42
|
-
```typescript
|
|
43
|
-
import { YinzerFlow, log } from 'yinzerflow';
|
|
44
|
-
|
|
45
|
-
const server = new YinzerFlow({
|
|
46
|
-
logLevel: 'info',
|
|
47
|
-
networkLogs: true
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
log.info('The server is starting')
|
|
51
|
-
|
|
52
|
-
await server.listen();
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Custom Logger Example
|
|
56
|
-
```typescript
|
|
57
|
-
import { YinzerFlow } from 'yinzerflow';
|
|
58
|
-
import winston from 'winston';
|
|
59
|
-
import type { Logger } from 'yinzerflow';
|
|
60
|
-
|
|
61
|
-
// Create Winston logger
|
|
62
|
-
const winstonLogger = winston.createLogger({
|
|
63
|
-
level: 'info',
|
|
64
|
-
format: winston.format.combine(
|
|
65
|
-
winston.format.timestamp(),
|
|
66
|
-
winston.format.json()
|
|
67
|
-
),
|
|
68
|
-
transports: [
|
|
69
|
-
new winston.transports.Console(),
|
|
70
|
-
new winston.transports.File({ filename: 'app.log' })
|
|
71
|
-
]
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// Winston adapter implementing YinzerFlow's Logger interface
|
|
75
|
-
const winstonAdapter: Logger = {
|
|
76
|
-
info: (...args) => winstonLogger.info(...args),
|
|
77
|
-
warn: (...args) => winstonLogger.warn(...args),
|
|
78
|
-
error: (...args) => winstonLogger.error(...args),
|
|
79
|
-
debug: (...args) => winstonLogger.debug(...args),
|
|
80
|
-
trace: (...args) => winstonLogger.silly(...args),
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
// Use custom logger - all log.info(), log.warn(), etc. calls will route to Winston
|
|
84
|
-
const server = new YinzerFlow({
|
|
85
|
-
logger: winstonAdapter,
|
|
86
|
-
logLevel: 'info',
|
|
87
|
-
networkLogs: true
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
// User can also use the same log interface in their code
|
|
91
|
-
log.info('User action', { userId: 123, action: 'login' });
|
|
92
|
-
// This also routes to Winston!
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### Unified Logging with Datadog Example
|
|
96
|
-
```typescript
|
|
97
|
-
import { YinzerFlow } from 'yinzerflow';
|
|
98
|
-
import winston from 'winston';
|
|
99
|
-
import type { Logger } from 'yinzerflow';
|
|
100
|
-
|
|
101
|
-
// Create Winston logger with Datadog transport
|
|
102
|
-
const winstonLogger = winston.createLogger({
|
|
103
|
-
level: 'info',
|
|
104
|
-
format: winston.format.combine(
|
|
105
|
-
winston.format.timestamp(),
|
|
106
|
-
winston.format.json()
|
|
107
|
-
),
|
|
108
|
-
transports: [
|
|
109
|
-
new winston.transports.Console(),
|
|
110
|
-
new winston.transports.Http({
|
|
111
|
-
host: 'http-intake.logs.datadoghq.com',
|
|
112
|
-
path: `/api/v2/logs?dd-api-key=${process.env.DD_API_KEY}&ddsource=nodejs&service=yinzerflow`,
|
|
113
|
-
ssl: true
|
|
114
|
-
})
|
|
115
|
-
]
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
const winstonAdapter: Logger = {
|
|
119
|
-
info: (...args) => winstonLogger.info(...args),
|
|
120
|
-
warn: (...args) => winstonLogger.warn(...args),
|
|
121
|
-
error: (...args) => winstonLogger.error(...args),
|
|
122
|
-
debug: (...args) => winstonLogger.debug(...args),
|
|
123
|
-
trace: (...args) => winstonLogger.silly(...args),
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
// Use same logger for both application and network logs
|
|
127
|
-
const server = new YinzerFlow({
|
|
128
|
-
logger: winstonAdapter, // Application logs → Winston → Datadog
|
|
129
|
-
networkLogger: winstonAdapter, // Network logs → Winston → Datadog
|
|
130
|
-
logLevel: 'info',
|
|
131
|
-
networkLogs: true
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
// Now both application and network logs go to Datadog!
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### Pino Logger Example
|
|
138
|
-
```typescript
|
|
139
|
-
import { YinzerFlow } from 'yinzerflow';
|
|
140
|
-
import pino from 'pino';
|
|
141
|
-
import type { Logger } from 'yinzerflow';
|
|
142
|
-
|
|
143
|
-
const pinoLogger = pino({
|
|
144
|
-
level: 'info',
|
|
145
|
-
transport: {
|
|
146
|
-
target: 'pino-pretty'
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
const pinoAdapter: Logger = {
|
|
151
|
-
info: (...args) => pinoLogger.info(...args),
|
|
152
|
-
warn: (...args) => pinoLogger.warn(...args),
|
|
153
|
-
error: (...args) => pinoLogger.error(...args),
|
|
154
|
-
debug: (...args) => pinoLogger.debug(...args),
|
|
155
|
-
trace: (...args) => pinoLogger.trace(...args),
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
const server = new YinzerFlow({
|
|
159
|
-
logger: pinoAdapter
|
|
160
|
-
});
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
## Common Use Cases
|
|
164
|
-
|
|
165
|
-
- **Development Debugging**: Use `logLevel: 'info'` with network logs enabled for comprehensive debugging
|
|
166
|
-
- **Production Monitoring**: Use custom Winston/Pino logger with structured logging and file output
|
|
167
|
-
- **Silent Operation**: Set `logLevel: 'off'` for production environments where logging is handled externally
|
|
168
|
-
- **Error Tracking**: Use `logLevel: 'error'` to capture only critical errors with custom error reporting
|
|
169
|
-
- **Performance Monitoring**: Enable network logs to track request/response times and identify bottlenecks
|
|
170
|
-
- **Security Auditing**: Use custom logger with audit trails for compliance and security monitoring
|
|
171
|
-
- **Unified Logging**: Framework and user logs both use the same `log.info()` interface and route to the same custom logger
|
|
172
|
-
- **Infrastructure Monitoring**: Network logs provide nginx-style request/response logging separate from application logs
|
|
173
|
-
|
|
174
|
-
## Logger Interface
|
|
175
|
-
|
|
176
|
-
To use a custom logger, implement the `Logger` interface:
|
|
177
|
-
|
|
178
|
-
```typescript
|
|
179
|
-
interface Logger {
|
|
180
|
-
info(...args: unknown[]): void;
|
|
181
|
-
warn(...args: unknown[]): void;
|
|
182
|
-
error(...args: unknown[]): void;
|
|
183
|
-
debug?(...args: unknown[]): void;
|
|
184
|
-
trace?(...args: unknown[]): void;
|
|
185
|
-
}
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
All methods accept unlimited arguments just like `console.log()`. The interface is designed to be simple and compatible with most logging libraries.
|
|
189
|
-
|
|
190
|
-
## How It Works
|
|
191
|
-
|
|
192
|
-
1. **Framework Integration**: YinzerFlow automatically routes all internal log calls through the LoggerFactory
|
|
193
|
-
2. **User Code**: Your application code uses the same `log.info()`, `log.warn()`, etc. interface
|
|
194
|
-
3. **Custom Logger**: If provided, all log calls route to your custom logger implementation
|
|
195
|
-
4. **Built-in Fallback**: If no custom logger is set, YinzerFlow uses its built-in styled logger
|
|
196
|
-
5. **Network Logs**: Network request/response logs can route to custom logger or use built-in formatting
|
|
197
|
-
|
|
198
|
-
This design ensures:
|
|
199
|
-
- **Consistent API**: Same logging interface everywhere
|
|
200
|
-
- **Flexible Output**: Route to any logging library or transport
|
|
201
|
-
- **Zero Breaking Changes**: Existing code continues to work
|
|
202
|
-
- **Clear Separation**: Application logs vs infrastructure logs (but can be unified)
|
|
203
|
-
|
|
204
|
-
## Network Logs vs Application Logs
|
|
205
|
-
|
|
206
|
-
YinzerFlow maintains a clear separation between two types of logging:
|
|
207
|
-
|
|
208
|
-
### Application Logs
|
|
209
|
-
- **Purpose**: Business logic, user actions, errors, debugging
|
|
210
|
-
- **Interface**: `log.info()`, `log.warn()`, `log.error()`, etc.
|
|
211
|
-
- **Custom Logger**: Routes to your custom logger if provided
|
|
212
|
-
- **Examples**: User login, database errors, validation failures
|
|
213
|
-
|
|
214
|
-
### Network Logs
|
|
215
|
-
- **Purpose**: Infrastructure monitoring, request/response tracking
|
|
216
|
-
- **Interface**: Automatic nginx-style logging
|
|
217
|
-
- **Custom Logger**: **Optional** - can route to custom logger or use built-in formatting
|
|
218
|
-
- **Examples**: HTTP requests, response times, connection events
|
|
219
|
-
|
|
220
|
-
This separation allows you to:
|
|
221
|
-
- Use structured logging for application events (Winston/Pino)
|
|
222
|
-
- Keep infrastructure logs in a consistent, readable format
|
|
223
|
-
- Route application logs to different destinations than network logs
|
|
224
|
-
- Maintain clear boundaries between business and infrastructure concerns
|
|
225
|
-
- **Unified monitoring**: Use same logger for both (e.g., Winston with Datadog transport)
|
|
226
|
-
- **Flexible routing**: Route network logs to monitoring systems while keeping app logs separate
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### Built-in Logger Features
|
|
230
|
-
|
|
231
|
-
The default YinzerFlow logger includes:
|
|
232
|
-
|
|
233
|
-
- **Pittsburgh Personality**: Random phrases and emojis for friendly logging
|
|
234
|
-
- **Performance Logging**: `perf()` method for timing operations
|
|
235
|
-
- **Level Management**: `setLogLevel()` for runtime level changes
|
|
236
|
-
- **Console-like Behavior**: Accepts unlimited arguments like `console.log`
|
|
237
|
-
|
|
238
|
-
### Methods
|
|
239
|
-
|
|
240
|
-
| Method | Description |
|
|
241
|
-
|--------|-------------|
|
|
242
|
-
| `info(...args)` | Log informational messages |
|
|
243
|
-
| `warn(...args)` | Log warning messages |
|
|
244
|
-
| `error(...args)` | Log error messages |
|
|
245
|
-
| `debug(...args)` | Log debug messages (optional) |
|
|
246
|
-
| `trace(...args)` | Log trace messages (optional) |
|
|
247
|
-
|
|
248
|
-
## Error Handling
|
|
249
|
-
|
|
250
|
-
YinzerFlow's logging system handles errors gracefully:
|
|
251
|
-
|
|
252
|
-
- **Invalid Log Levels**: Defaults to `'warn'` if invalid level provided
|
|
253
|
-
- **Custom Logger Failures**: Falls back to built-in logger if custom logger throws errors
|
|
254
|
-
- **Network Log Errors**: Network logging failures don't affect application logging
|
|
255
|
-
- **Missing Logger Methods**: Optional methods (`debug`, `trace`) are safely ignored if not implemented
|
|
256
|
-
|
|
257
|
-
## Security Considerations
|
|
258
|
-
|
|
259
|
-
YinzerFlow implements several security measures for logging:
|
|
260
|
-
|
|
261
|
-
### 🛡️ Input Sanitization
|
|
262
|
-
- **Problem**: Malicious log input can cause injection attacks or log poisoning
|
|
263
|
-
- **YinzerFlow Solution**: All log arguments are safely handled through console.log's native formatting
|
|
264
|
-
|
|
265
|
-
### 🛡️ Sensitive Data Protection
|
|
266
|
-
- **Problem**: Logs may accidentally expose sensitive information like passwords or tokens
|
|
267
|
-
- **YinzerFlow Solution**: Built-in logger uses console.log's safe object formatting, custom loggers can implement their own sanitization
|
|
268
|
-
|
|
269
|
-
### 🛡️ Log Level Validation
|
|
270
|
-
- **Problem**: Invalid log levels could cause unexpected behavior or information leakage
|
|
271
|
-
- **YinzerFlow Solution**: Strict validation of log levels with safe defaults
|
|
272
|
-
|
|
273
|
-
### 🛡️ Custom Logger Isolation
|
|
274
|
-
- **Problem**: Custom loggers with vulnerabilities could compromise the application
|
|
275
|
-
- **YinzerFlow Solution**: Custom loggers are isolated and failures don't affect core functionality
|
|
276
|
-
|
|
277
|
-
These security measures ensure YinzerFlow's logging implementation follows security best practices and prevents common attack vectors while maintaining spec compliance.
|
|
278
|
-
|
|
279
|
-
## Integration with Other Systems
|
|
280
|
-
|
|
281
|
-
### Winston Integration
|
|
282
|
-
```typescript
|
|
283
|
-
import winston from 'winston';
|
|
284
|
-
|
|
285
|
-
const winstonLogger = winston.createLogger({
|
|
286
|
-
level: 'info',
|
|
287
|
-
format: winston.format.combine(
|
|
288
|
-
winston.format.timestamp(),
|
|
289
|
-
winston.format.errors({ stack: true }),
|
|
290
|
-
winston.format.json()
|
|
291
|
-
),
|
|
292
|
-
defaultMeta: { service: 'yinzerflow' },
|
|
293
|
-
transports: [
|
|
294
|
-
new winston.transports.Console(),
|
|
295
|
-
new winston.transports.File({ filename: 'error.log', level: 'error' }),
|
|
296
|
-
new winston.transports.File({ filename: 'combined.log' })
|
|
297
|
-
]
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
const winstonAdapter: Logger = {
|
|
301
|
-
info: (...args) => winstonLogger.info(...args),
|
|
302
|
-
warn: (...args) => winstonLogger.warn(...args),
|
|
303
|
-
error: (...args) => winstonLogger.error(...args),
|
|
304
|
-
debug: (...args) => winstonLogger.debug(...args),
|
|
305
|
-
trace: (...args) => winstonLogger.silly(...args),
|
|
306
|
-
};
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
### Pino Integration
|
|
310
|
-
```typescript
|
|
311
|
-
import pino from 'pino';
|
|
312
|
-
|
|
313
|
-
const pinoLogger = pino({
|
|
314
|
-
level: 'info',
|
|
315
|
-
transport: {
|
|
316
|
-
target: 'pino-pretty',
|
|
317
|
-
options: {
|
|
318
|
-
colorize: true,
|
|
319
|
-
translateTime: 'SYS:standard',
|
|
320
|
-
ignore: 'pid,hostname'
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
const pinoAdapter: Logger = {
|
|
326
|
-
info: (...args) => pinoLogger.info(...args),
|
|
327
|
-
warn: (...args) => pinoLogger.warn(...args),
|
|
328
|
-
error: (...args) => pinoLogger.error(...args),
|
|
329
|
-
debug: (...args) => pinoLogger.debug(...args),
|
|
330
|
-
trace: (...args) => pinoLogger.trace(...args),
|
|
331
|
-
};
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
### Custom Structured Logger
|
|
335
|
-
```typescript
|
|
336
|
-
interface StructuredLogger extends Logger {
|
|
337
|
-
log(level: string, message: string, meta?: Record<string, unknown>): void;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
const structuredAdapter: StructuredLogger = {
|
|
341
|
-
info: (...args) => console.log(JSON.stringify({ level: 'info', message: args[0], data: args.slice(1) })),
|
|
342
|
-
warn: (...args) => console.log(JSON.stringify({ level: 'warn', message: args[0], data: args.slice(1) })),
|
|
343
|
-
error: (...args) => console.log(JSON.stringify({ level: 'error', message: args[0], data: args.slice(1) })),
|
|
344
|
-
debug: (...args) => console.log(JSON.stringify({ level: 'debug', message: args[0], data: args.slice(1) })),
|
|
345
|
-
trace: (...args) => console.log(JSON.stringify({ level: 'trace', message: args[0], data: args.slice(1) })),
|
|
346
|
-
log: (level, message, meta) => console.log(JSON.stringify({ level, message, ...meta }))
|
|
347
|
-
};
|
|
348
|
-
```
|