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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yinzerflow",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "author": "Patrick Rizzardi <patrick@redact.digital> (https://redact.digital)",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/yinzers/YinzerFlow/blob/main/docs/start-here.md",
@@ -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
- ```