@flink-app/debug-plugin 0.12.1-alpha.9 → 0.13.1
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/CHANGELOG.md +22 -0
- package/dist/handlers/Debug/Get.js +2 -2
- package/dist/handlers/Debug/PostDisable.js +2 -2
- package/dist/handlers/Debug/PostEnable.js +2 -2
- package/dist/models/request.d.ts +0 -1
- package/package.json +26 -28
- package/readme.md +560 -28
- package/src/index.ts +2 -3
- package/tsconfig.json +1 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# @flink-app/debug-plugin
|
|
2
|
+
|
|
3
|
+
## 0.13.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fixed invalid types and improve typescript error message during schema compilation
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @flink-app/management-api-plugin@0.13.1
|
|
10
|
+
- @flink-app/flink@0.13.1
|
|
11
|
+
|
|
12
|
+
## 0.13.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- Migrate to pnpm and streamlines build process.
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Updated dependencies
|
|
21
|
+
- @flink-app/management-api-plugin@0.13.0
|
|
22
|
+
- @flink-app/flink@0.13.0
|
|
@@ -9,8 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
-
return g =
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
14
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
15
|
function step(op) {
|
|
16
16
|
if (f) throw new TypeError("Generator is already executing.");
|
|
@@ -9,8 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
-
return g =
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
14
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
15
|
function step(op) {
|
|
16
16
|
if (f) throw new TypeError("Generator is already executing.");
|
|
@@ -9,8 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
-
return g =
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
14
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
15
|
function step(op) {
|
|
16
16
|
if (f) throw new TypeError("Generator is already executing.");
|
package/dist/models/request.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,29 +1,27 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"gitHead": "3007ad036607014176930446fde56203bde8d6f5"
|
|
29
|
-
}
|
|
2
|
+
"name": "@flink-app/debug-plugin",
|
|
3
|
+
"version": "0.13.1",
|
|
4
|
+
"description": "Flink plugin that make it possbile to debug requests",
|
|
5
|
+
"author": "johan@frost.se",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"node-color-log": "^5.3.1",
|
|
14
|
+
"@flink-app/management-api-plugin": "0.13.1",
|
|
15
|
+
"@flink-app/flink": "0.13.1"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "22.13.10",
|
|
19
|
+
"ts-node": "^10.9.2"
|
|
20
|
+
},
|
|
21
|
+
"gitHead": "4243e3b3cd6d4e1ca001a61baa8436bf2bbe4113",
|
|
22
|
+
"scripts": {
|
|
23
|
+
"test": "echo \"Error: no test specified\"",
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"clean": "rimraf dist .flink"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/readme.md
CHANGED
|
@@ -1,74 +1,606 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Debug Plugin
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A Flink plugin for debugging HTTP requests and responses in your application. Capture and inspect request/response data, enable/disable debugging on demand, and integrate with the Management API for admin panel access.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
Install plugin to your
|
|
7
|
+
Install the plugin to your Flink app project:
|
|
8
8
|
|
|
9
|
-
```
|
|
10
|
-
npm
|
|
9
|
+
```bash
|
|
10
|
+
npm install @flink-app/debug-plugin
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## Configuration
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
### Basic Setup
|
|
16
|
+
|
|
17
|
+
Configure the plugin in your app startup:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { FlinkApp } from "@flink-app/flink";
|
|
21
|
+
import { debugPlugin } from "@flink-app/debug-plugin";
|
|
17
22
|
|
|
18
23
|
function start() {
|
|
19
24
|
new FlinkApp<AppContext>({
|
|
20
25
|
name: "My app",
|
|
21
26
|
plugins: [
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
debugPlugin({
|
|
28
|
+
enabledAtStart: false, // Start with debugging disabled
|
|
29
|
+
logToConsole: false, // Don't log to console
|
|
30
|
+
keepLogs: 100 // Keep last 100 requests
|
|
31
|
+
})
|
|
24
32
|
],
|
|
25
33
|
}).start();
|
|
26
34
|
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Plugin Options:**
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
interface StaticOptions {
|
|
41
|
+
logToConsole: boolean; // Log requests/responses to console
|
|
42
|
+
enabledAtStart: boolean; // Enable debugging when app starts
|
|
43
|
+
keepLogs?: number; // Number of requests to keep in memory (default: 100)
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## TypeScript Setup
|
|
48
|
+
|
|
49
|
+
The debug plugin doesn't require adding types to your context, but it does add properties to `ctx.plugins.debugPlugin`:
|
|
27
50
|
|
|
51
|
+
```typescript
|
|
52
|
+
ctx.plugins.debugPlugin: {
|
|
53
|
+
requests: request[]; // Array of captured requests
|
|
54
|
+
enabled: boolean; // Current enabled state
|
|
55
|
+
}
|
|
28
56
|
```
|
|
29
57
|
|
|
30
|
-
##
|
|
58
|
+
## How It Works
|
|
59
|
+
|
|
60
|
+
The debug plugin uses Express middleware to:
|
|
61
|
+
1. Intercept incoming HTTP requests
|
|
62
|
+
2. Capture request details (method, path, body, headers)
|
|
63
|
+
3. Intercept outgoing responses by wrapping `res.write` and `res.end`
|
|
64
|
+
4. Store request/response pairs in memory
|
|
65
|
+
5. Keep a rolling window of the most recent N requests
|
|
66
|
+
|
|
67
|
+
**What's Captured:**
|
|
68
|
+
- Request method (GET, POST, etc.)
|
|
69
|
+
- Request path and query parameters
|
|
70
|
+
- Request headers
|
|
71
|
+
- Request body
|
|
72
|
+
- Response body
|
|
73
|
+
- Request start and end timestamps
|
|
74
|
+
|
|
75
|
+
**What's NOT Captured:**
|
|
76
|
+
- Management API requests (routes starting with `/managementapi`)
|
|
77
|
+
- Requests when debugging is disabled
|
|
78
|
+
|
|
79
|
+
## Accessing Debug Data
|
|
80
|
+
|
|
81
|
+
### From Handlers
|
|
31
82
|
|
|
32
|
-
|
|
83
|
+
Access captured requests directly from context:
|
|
33
84
|
|
|
34
|
-
|
|
85
|
+
```typescript
|
|
86
|
+
import { Handler } from "@flink-app/flink";
|
|
87
|
+
import { Ctx } from "../Ctx";
|
|
35
88
|
|
|
89
|
+
const GetDebugInfo: Handler<Ctx, any, any> = async ({ ctx, req }) => {
|
|
90
|
+
const debugData = ctx.plugins.debugPlugin;
|
|
36
91
|
|
|
37
|
-
|
|
92
|
+
return {
|
|
93
|
+
data: {
|
|
94
|
+
enabled: debugData.enabled,
|
|
95
|
+
requestCount: debugData.requests.length,
|
|
96
|
+
recentRequests: debugData.requests.slice(0, 10)
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
};
|
|
38
100
|
|
|
101
|
+
export default GetDebugInfo;
|
|
39
102
|
```
|
|
40
|
-
|
|
41
|
-
|
|
103
|
+
|
|
104
|
+
### Enabling/Disabling Debug Mode
|
|
105
|
+
|
|
106
|
+
Toggle debug mode programmatically:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// Enable debugging
|
|
110
|
+
ctx.plugins.debugPlugin.enabled = true;
|
|
111
|
+
|
|
112
|
+
// Disable debugging
|
|
113
|
+
ctx.plugins.debugPlugin.enabled = false;
|
|
114
|
+
|
|
115
|
+
// Clear captured requests
|
|
116
|
+
ctx.plugins.debugPlugin.requests = [];
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Management API Integration
|
|
120
|
+
|
|
121
|
+
The debug plugin can be exposed as a Management API module for easy access from admin panels:
|
|
122
|
+
|
|
123
|
+
### Setup Management Module
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import { FlinkApp } from "@flink-app/flink";
|
|
127
|
+
import { Ctx } from "./Ctx";
|
|
42
128
|
import {
|
|
43
129
|
debugPlugin,
|
|
44
|
-
GetManagementModule as GetDebugManagementModule
|
|
45
|
-
} from
|
|
46
|
-
import { managementApiPlugin } from
|
|
130
|
+
GetManagementModule as GetDebugManagementModule
|
|
131
|
+
} from "@flink-app/debug-plugin";
|
|
132
|
+
import { managementApiPlugin } from "@flink-app/management-api-plugin";
|
|
47
133
|
|
|
48
134
|
const debugManagementModule = GetDebugManagementModule({
|
|
49
135
|
ui: true,
|
|
136
|
+
uiSettings: {
|
|
137
|
+
title: "Debug Console"
|
|
138
|
+
}
|
|
50
139
|
});
|
|
51
140
|
|
|
52
141
|
function start() {
|
|
53
142
|
new FlinkApp<Ctx>({
|
|
54
|
-
name:
|
|
143
|
+
name: "My flink app",
|
|
55
144
|
debug: true,
|
|
56
145
|
db: {
|
|
57
|
-
uri:
|
|
146
|
+
uri: "mongodb://localhost:27017/my-flink-app"
|
|
58
147
|
},
|
|
59
148
|
plugins: [
|
|
60
|
-
debugPlugin({
|
|
149
|
+
debugPlugin({
|
|
150
|
+
enabledAtStart: false,
|
|
151
|
+
logToConsole: false,
|
|
152
|
+
keepLogs: 100
|
|
153
|
+
}),
|
|
61
154
|
managementApiPlugin({
|
|
62
|
-
token:
|
|
63
|
-
jwtSecret:
|
|
64
|
-
modules: [debugManagementModule]
|
|
155
|
+
token: process.env.MGMT_TOKEN!,
|
|
156
|
+
jwtSecret: process.env.JWT_SECRET!,
|
|
157
|
+
modules: [debugManagementModule]
|
|
158
|
+
})
|
|
159
|
+
]
|
|
160
|
+
}).start();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
start();
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Management Module Options:**
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
interface GetManagementModuleConfig {
|
|
170
|
+
pluginId?: string; // Default: "debug"
|
|
171
|
+
ui: boolean; // Enable UI in admin panel
|
|
172
|
+
uiSettings?: {
|
|
173
|
+
title: string; // Module title (default: "Debug")
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Management Endpoints
|
|
179
|
+
|
|
180
|
+
When using the Management Module, these endpoints are registered under `/managementapi/{pluginId}`:
|
|
181
|
+
|
|
182
|
+
#### GET /managementapi/debug/
|
|
183
|
+
|
|
184
|
+
Get debug status and captured requests.
|
|
185
|
+
|
|
186
|
+
**Response:**
|
|
187
|
+
```typescript
|
|
188
|
+
{
|
|
189
|
+
data: {
|
|
190
|
+
enabled: boolean; // Current debug state
|
|
191
|
+
requests: request[]; // Array of captured requests
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Example:**
|
|
197
|
+
```bash
|
|
198
|
+
curl http://localhost:3000/managementapi/debug/
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
#### POST /managementapi/debug/enable
|
|
202
|
+
|
|
203
|
+
Enable debug mode.
|
|
204
|
+
|
|
205
|
+
**Response:**
|
|
206
|
+
```typescript
|
|
207
|
+
{
|
|
208
|
+
data: {
|
|
209
|
+
enabled: true
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Example:**
|
|
215
|
+
```bash
|
|
216
|
+
curl -X POST http://localhost:3000/managementapi/debug/enable
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
#### POST /managementapi/debug/disable
|
|
220
|
+
|
|
221
|
+
Disable debug mode.
|
|
222
|
+
|
|
223
|
+
**Response:**
|
|
224
|
+
```typescript
|
|
225
|
+
{
|
|
226
|
+
data: {
|
|
227
|
+
enabled: false
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Example:**
|
|
233
|
+
```bash
|
|
234
|
+
curl -X POST http://localhost:3000/managementapi/debug/disable
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## API Reference
|
|
238
|
+
|
|
239
|
+
### Request Type
|
|
240
|
+
|
|
241
|
+
Each captured request has the following structure:
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
interface request {
|
|
245
|
+
start: Date; // When request started
|
|
246
|
+
end?: Date; // When response finished
|
|
247
|
+
method: string; // HTTP method (GET, POST, etc.)
|
|
248
|
+
path: string; // Request path with query params
|
|
249
|
+
headers?: IncomingHttpHeaders; // Request headers
|
|
250
|
+
body?: any; // Parsed request body
|
|
251
|
+
response?: string; // Response body as string
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Context Properties
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
ctx.plugins.debugPlugin: {
|
|
259
|
+
requests: request[]; // Array of captured requests (newest first)
|
|
260
|
+
enabled: boolean; // Whether debugging is currently enabled
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Complete Example
|
|
265
|
+
|
|
266
|
+
Here's a complete example showing how to use the debug plugin:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
import { FlinkApp } from "@flink-app/flink";
|
|
270
|
+
import { Ctx } from "./Ctx";
|
|
271
|
+
import {
|
|
272
|
+
debugPlugin,
|
|
273
|
+
GetManagementModule as GetDebugManagementModule
|
|
274
|
+
} from "@flink-app/debug-plugin";
|
|
275
|
+
import { managementApiPlugin } from "@flink-app/management-api-plugin";
|
|
276
|
+
|
|
277
|
+
// Create debug management module
|
|
278
|
+
const debugManagementModule = GetDebugManagementModule({
|
|
279
|
+
ui: true,
|
|
280
|
+
uiSettings: {
|
|
281
|
+
title: "Request Debugger"
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
function start() {
|
|
286
|
+
new FlinkApp<Ctx>({
|
|
287
|
+
name: "My API",
|
|
288
|
+
debug: true,
|
|
289
|
+
db: {
|
|
290
|
+
uri: process.env.MONGODB_URI!
|
|
291
|
+
},
|
|
292
|
+
plugins: [
|
|
293
|
+
// Debug plugin - starts disabled, keeps last 200 requests
|
|
294
|
+
debugPlugin({
|
|
295
|
+
enabledAtStart: false,
|
|
296
|
+
logToConsole: true, // Also log to console
|
|
297
|
+
keepLogs: 200
|
|
65
298
|
}),
|
|
66
|
-
|
|
299
|
+
|
|
300
|
+
// Management API with debug module
|
|
301
|
+
managementApiPlugin({
|
|
302
|
+
token: process.env.MGMT_TOKEN!,
|
|
303
|
+
jwtSecret: process.env.JWT_SECRET!,
|
|
304
|
+
modules: [debugManagementModule]
|
|
305
|
+
})
|
|
306
|
+
]
|
|
67
307
|
}).start();
|
|
68
308
|
}
|
|
69
309
|
|
|
70
310
|
start();
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Custom Debug Handler
|
|
314
|
+
|
|
315
|
+
Create a custom handler to analyze debug data:
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
import { Handler } from "@flink-app/flink";
|
|
319
|
+
import { Ctx } from "../Ctx";
|
|
320
|
+
|
|
321
|
+
interface DebugStatsResponse {
|
|
322
|
+
totalRequests: number;
|
|
323
|
+
methodCounts: { [method: string]: number };
|
|
324
|
+
slowestRequests: Array<{
|
|
325
|
+
path: string;
|
|
326
|
+
duration: number;
|
|
327
|
+
}>;
|
|
328
|
+
errorResponses: number;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const GetDebugStats: Handler<Ctx, any, DebugStatsResponse> = async ({ ctx }) => {
|
|
332
|
+
const requests = ctx.plugins.debugPlugin.requests;
|
|
333
|
+
|
|
334
|
+
// Count requests by method
|
|
335
|
+
const methodCounts: { [method: string]: number } = {};
|
|
336
|
+
for (const req of requests) {
|
|
337
|
+
methodCounts[req.method] = (methodCounts[req.method] || 0) + 1;
|
|
338
|
+
}
|
|
71
339
|
|
|
340
|
+
// Find slowest requests
|
|
341
|
+
const slowestRequests = requests
|
|
342
|
+
.filter(req => req.end)
|
|
343
|
+
.map(req => ({
|
|
344
|
+
path: req.path,
|
|
345
|
+
duration: req.end!.getTime() - req.start.getTime()
|
|
346
|
+
}))
|
|
347
|
+
.sort((a, b) => b.duration - a.duration)
|
|
348
|
+
.slice(0, 10);
|
|
349
|
+
|
|
350
|
+
// Count error responses (5xx, 4xx)
|
|
351
|
+
const errorResponses = requests.filter(req => {
|
|
352
|
+
if (!req.response) return false;
|
|
353
|
+
try {
|
|
354
|
+
const response = JSON.parse(req.response);
|
|
355
|
+
return response.status >= 400;
|
|
356
|
+
} catch {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
}).length;
|
|
360
|
+
|
|
361
|
+
return {
|
|
362
|
+
data: {
|
|
363
|
+
totalRequests: requests.length,
|
|
364
|
+
methodCounts,
|
|
365
|
+
slowestRequests,
|
|
366
|
+
errorResponses
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
export default GetDebugStats;
|
|
72
372
|
```
|
|
73
373
|
|
|
74
|
-
|
|
374
|
+
## Use Cases
|
|
375
|
+
|
|
376
|
+
### 1. Development Debugging
|
|
377
|
+
|
|
378
|
+
Enable debug mode during development to inspect requests:
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
debugPlugin({
|
|
382
|
+
enabledAtStart: true,
|
|
383
|
+
logToConsole: true,
|
|
384
|
+
keepLogs: 50
|
|
385
|
+
})
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### 2. Production Issue Investigation
|
|
389
|
+
|
|
390
|
+
Keep debug mode off by default, enable on demand when investigating:
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
debugPlugin({
|
|
394
|
+
enabledAtStart: false,
|
|
395
|
+
logToConsole: false,
|
|
396
|
+
keepLogs: 200 // Keep more logs for analysis
|
|
397
|
+
})
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Then enable via Management API when needed.
|
|
401
|
+
|
|
402
|
+
### 3. API Testing
|
|
403
|
+
|
|
404
|
+
Use debug data to verify request/response pairs:
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
// Make test request
|
|
408
|
+
await fetch("http://localhost:3000/api/users", {
|
|
409
|
+
method: "POST",
|
|
410
|
+
body: JSON.stringify({ name: "John" })
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
// Check debug data
|
|
414
|
+
const debugData = ctx.plugins.debugPlugin.requests[0];
|
|
415
|
+
expect(debugData.body).toEqual({ name: "John" });
|
|
416
|
+
expect(JSON.parse(debugData.response!)).toHaveProperty("id");
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### 4. Performance Monitoring
|
|
420
|
+
|
|
421
|
+
Track request durations to identify slow endpoints:
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
const slowRequests = ctx.plugins.debugPlugin.requests
|
|
425
|
+
.filter(req => req.end)
|
|
426
|
+
.filter(req => {
|
|
427
|
+
const duration = req.end!.getTime() - req.start.getTime();
|
|
428
|
+
return duration > 1000; // Slower than 1 second
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
console.log(`Found ${slowRequests.length} slow requests`);
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
## Best Practices
|
|
435
|
+
|
|
436
|
+
### Memory Management
|
|
437
|
+
|
|
438
|
+
The plugin keeps requests in memory. Be careful with settings:
|
|
439
|
+
|
|
440
|
+
```typescript
|
|
441
|
+
// Good for development
|
|
442
|
+
keepLogs: 50
|
|
443
|
+
|
|
444
|
+
// Good for temporary production debugging
|
|
445
|
+
keepLogs: 200
|
|
446
|
+
|
|
447
|
+
// Be careful - could use significant memory
|
|
448
|
+
keepLogs: 10000 // Avoid in production
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
Each request object includes:
|
|
452
|
+
- Headers (can be large)
|
|
453
|
+
- Request body (can be large)
|
|
454
|
+
- Response body (can be large)
|
|
455
|
+
|
|
456
|
+
### Security Considerations
|
|
457
|
+
|
|
458
|
+
1. **Disable in Production**: Don't enable debug mode in production by default
|
|
459
|
+
2. **Sensitive Data**: Be aware that debug logs capture request bodies and headers
|
|
460
|
+
3. **Access Control**: Use Management API with proper authentication
|
|
461
|
+
4. **Clear Logs**: Regularly clear captured requests to avoid memory leaks
|
|
462
|
+
|
|
463
|
+
```typescript
|
|
464
|
+
// Clear debug logs periodically
|
|
465
|
+
setInterval(() => {
|
|
466
|
+
if (ctx.plugins.debugPlugin.requests.length > 500) {
|
|
467
|
+
ctx.plugins.debugPlugin.requests = [];
|
|
468
|
+
}
|
|
469
|
+
}, 60000); // Every minute
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Console Logging
|
|
473
|
+
|
|
474
|
+
Use `logToConsole: true` carefully:
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
// Development - useful
|
|
478
|
+
debugPlugin({
|
|
479
|
+
logToConsole: true,
|
|
480
|
+
enabledAtStart: true
|
|
481
|
+
})
|
|
482
|
+
|
|
483
|
+
// Production - avoid (too noisy)
|
|
484
|
+
debugPlugin({
|
|
485
|
+
logToConsole: false,
|
|
486
|
+
enabledAtStart: false
|
|
487
|
+
})
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### Filtering Sensitive Data
|
|
491
|
+
|
|
492
|
+
Consider wrapping the plugin to filter sensitive data:
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
// In your handler
|
|
496
|
+
const sanitizedRequests = ctx.plugins.debugPlugin.requests.map(req => ({
|
|
497
|
+
...req,
|
|
498
|
+
headers: {
|
|
499
|
+
...req.headers,
|
|
500
|
+
authorization: req.headers?.authorization ? "[REDACTED]" : undefined
|
|
501
|
+
},
|
|
502
|
+
body: req.body?.password ? { ...req.body, password: "[REDACTED]" } : req.body
|
|
503
|
+
}));
|
|
504
|
+
|
|
505
|
+
return { data: { requests: sanitizedRequests } };
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
## Implementation Details
|
|
509
|
+
|
|
510
|
+
### Middleware Order
|
|
511
|
+
|
|
512
|
+
The debug plugin middleware is registered during plugin initialization and runs for all requests except:
|
|
513
|
+
- Routes starting with `/managementapi` (to avoid recursion)
|
|
514
|
+
- Requests when `enabled` is `false`
|
|
515
|
+
|
|
516
|
+
### Response Interception
|
|
517
|
+
|
|
518
|
+
The plugin intercepts responses by:
|
|
519
|
+
1. Saving original `res.write` and `res.end` functions
|
|
520
|
+
2. Replacing them with custom implementations
|
|
521
|
+
3. Collecting response chunks in a buffer
|
|
522
|
+
4. Restoring original functions after response completes
|
|
523
|
+
|
|
524
|
+
This ensures the plugin captures the full response without affecting normal operation.
|
|
525
|
+
|
|
526
|
+
### Rolling Window
|
|
527
|
+
|
|
528
|
+
When the request array exceeds `keepLogs`:
|
|
529
|
+
```typescript
|
|
530
|
+
requests = requests.splice(0, keep);
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
This keeps only the most recent N requests, with newest first (unshift).
|
|
534
|
+
|
|
535
|
+
## Troubleshooting
|
|
536
|
+
|
|
537
|
+
### Debug Mode Not Working
|
|
538
|
+
|
|
539
|
+
1. **Check enabled state:**
|
|
540
|
+
```typescript
|
|
541
|
+
console.log(ctx.plugins.debugPlugin.enabled);
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
2. **Verify plugin initialization:**
|
|
545
|
+
```typescript
|
|
546
|
+
console.log(app.ctx.plugins.debugPlugin); // Should exist
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
3. **Check Management API routes:**
|
|
550
|
+
```bash
|
|
551
|
+
# Should work
|
|
552
|
+
curl http://localhost:3000/managementapi/debug/
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### Requests Not Being Captured
|
|
556
|
+
|
|
557
|
+
1. **Enable debug mode:**
|
|
558
|
+
```bash
|
|
559
|
+
curl -X POST http://localhost:3000/managementapi/debug/enable
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
2. **Check if route is excluded:**
|
|
563
|
+
- Management API routes are not captured
|
|
564
|
+
- Verify your route doesn't start with `/managementapi`
|
|
565
|
+
|
|
566
|
+
3. **Check keepLogs setting:**
|
|
567
|
+
- If you have many requests, older ones get removed
|
|
568
|
+
- Increase `keepLogs` value
|
|
569
|
+
|
|
570
|
+
### Memory Usage High
|
|
571
|
+
|
|
572
|
+
1. **Reduce keepLogs:**
|
|
573
|
+
```typescript
|
|
574
|
+
keepLogs: 50 // Keep fewer logs
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
2. **Clear logs periodically:**
|
|
578
|
+
```typescript
|
|
579
|
+
ctx.plugins.debugPlugin.requests = [];
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
3. **Disable when not needed:**
|
|
583
|
+
```bash
|
|
584
|
+
curl -X POST http://localhost:3000/managementapi/debug/disable
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
### Console Too Noisy
|
|
588
|
+
|
|
589
|
+
Set `logToConsole: false`:
|
|
590
|
+
|
|
591
|
+
```typescript
|
|
592
|
+
debugPlugin({
|
|
593
|
+
enabledAtStart: true,
|
|
594
|
+
logToConsole: false, // No console output
|
|
595
|
+
keepLogs: 100
|
|
596
|
+
})
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
## Notes
|
|
600
|
+
|
|
601
|
+
- The plugin automatically excludes Management API routes to avoid recursion
|
|
602
|
+
- Request bodies are captured after body-parser middleware processes them
|
|
603
|
+
- Response bodies are captured as strings (includes JSON, HTML, etc.)
|
|
604
|
+
- The plugin adds minimal performance overhead when disabled
|
|
605
|
+
- Debug data is stored in memory only (not persisted to database)
|
|
606
|
+
- The `enabled` flag can be toggled at runtime without restarting the app
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { FlinkApp, FlinkPlugin, HttpMethod } from "@flink-app/flink";
|
|
1
|
+
import { FlinkApp, FlinkPlugin, HttpMethod, ExpressRequest, ExpressResponse, ExpressNextFunction } from "@flink-app/flink";
|
|
2
2
|
import { ManagementApiModule, ManagementApiType } from "@flink-app/management-api-plugin";
|
|
3
|
-
import express from "express";
|
|
4
3
|
import log from "node-color-log";
|
|
5
4
|
import request from "./models/request";
|
|
6
5
|
import * as GetHandler from "./handlers/Debug/Get";
|
|
@@ -44,7 +43,7 @@ function init(app: FlinkApp<any>, options: StaticOptions) {
|
|
|
44
43
|
log.info(`Debug enabled`);
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
expressApp.use((req:
|
|
46
|
+
expressApp.use((req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction) => {
|
|
48
47
|
let requests = app.ctx.plugins.debugPlugin.requests as request[];
|
|
49
48
|
let enabled = app.ctx.plugins.debugPlugin.enabled as boolean;
|
|
50
49
|
if (!enabled) {
|