1
1
import Koa from "koa" ;
2
2
3
+ import { AsyncLocalStorage } from "async_hooks" ;
3
4
import { ApitallyClient } from "../common/client.js" ;
5
+ import { patchConsole } from "../common/consoleCapture.js" ;
4
6
import { consumerFromStringOrObject } from "../common/consumerRegistry.js" ;
5
7
import { getPackageVersion } from "../common/packageVersions.js" ;
6
- import { convertBody , convertHeaders } from "../common/requestLogger.js" ;
8
+ import {
9
+ convertBody ,
10
+ convertHeaders ,
11
+ LogRecord ,
12
+ } from "../common/requestLogger.js" ;
7
13
import {
8
14
ApitallyConfig ,
9
15
ApitallyConsumer ,
@@ -28,87 +34,97 @@ export function useApitally(app: Koa, config: ApitallyConfig) {
28
34
}
29
35
30
36
function getMiddleware ( client : ApitallyClient ) {
37
+ const logsContext = new AsyncLocalStorage < LogRecord [ ] > ( ) ;
38
+
39
+ if ( client . requestLogger . config . captureLogs ) {
40
+ patchConsole ( logsContext ) ;
41
+ }
42
+
31
43
return async ( ctx : Koa . Context , next : Koa . Next ) => {
32
44
if ( ! client . isEnabled ( ) || ctx . request . method . toUpperCase ( ) === "OPTIONS" ) {
33
45
await next ( ) ;
34
46
return ;
35
47
}
36
48
37
- let path : string | undefined ;
38
- let statusCode : number | undefined ;
39
- let serverError : Error | undefined ;
40
- const startTime = performance . now ( ) ;
41
- try {
42
- await next ( ) ;
43
- } catch ( error : any ) {
44
- path = getPath ( ctx ) ;
45
- statusCode = error . statusCode || error . status || 500 ;
46
- if ( path && statusCode === 500 && error instanceof Error ) {
47
- serverError = error ;
48
- client . serverErrorCounter . addServerError ( {
49
- consumer : getConsumer ( ctx ) ?. identifier ,
50
- method : ctx . request . method ,
51
- path,
52
- type : error . name ,
53
- msg : error . message ,
54
- traceback : error . stack || "" ,
55
- } ) ;
56
- }
57
- throw error ;
58
- } finally {
59
- const responseTime = performance . now ( ) - startTime ;
60
- const consumer = getConsumer ( ctx ) ;
61
- client . consumerRegistry . addOrUpdateConsumer ( consumer ) ;
62
- if ( ! path ) {
49
+ await logsContext . run ( [ ] , async ( ) => {
50
+ let path : string | undefined ;
51
+ let statusCode : number | undefined ;
52
+ let serverError : Error | undefined ;
53
+ const startTime = performance . now ( ) ;
54
+ try {
55
+ await next ( ) ;
56
+ } catch ( error : any ) {
63
57
path = getPath ( ctx ) ;
64
- }
65
- if ( path ) {
66
- try {
67
- client . requestCounter . addRequest ( {
68
- consumer : consumer ?. identifier ,
58
+ statusCode = error . statusCode || error . status || 500 ;
59
+ if ( path && statusCode === 500 && error instanceof Error ) {
60
+ serverError = error ;
61
+ client . serverErrorCounter . addServerError ( {
62
+ consumer : getConsumer ( ctx ) ?. identifier ,
69
63
method : ctx . request . method ,
70
64
path,
71
- statusCode : statusCode || ctx . response . status ,
72
- responseTime,
73
- requestSize : ctx . request . length ,
74
- responseSize : ctx . response . length ,
65
+ type : error . name ,
66
+ msg : error . message ,
67
+ traceback : error . stack || "" ,
75
68
} ) ;
76
- } catch ( error ) {
77
- client . logger . error (
78
- "Error while logging request in Apitally middleware." ,
79
- { context : ctx , error } ,
69
+ }
70
+ throw error ;
71
+ } finally {
72
+ const responseTime = performance . now ( ) - startTime ;
73
+ const consumer = getConsumer ( ctx ) ;
74
+ client . consumerRegistry . addOrUpdateConsumer ( consumer ) ;
75
+ if ( ! path ) {
76
+ path = getPath ( ctx ) ;
77
+ }
78
+ if ( path ) {
79
+ try {
80
+ client . requestCounter . addRequest ( {
81
+ consumer : consumer ?. identifier ,
82
+ method : ctx . request . method ,
83
+ path,
84
+ statusCode : statusCode || ctx . response . status ,
85
+ responseTime,
86
+ requestSize : ctx . request . length ,
87
+ responseSize : ctx . response . length ,
88
+ } ) ;
89
+ } catch ( error ) {
90
+ client . logger . error (
91
+ "Error while logging request in Apitally middleware." ,
92
+ { context : ctx , error } ,
93
+ ) ;
94
+ }
95
+ }
96
+ if ( client . requestLogger . enabled ) {
97
+ const logs = logsContext . getStore ( ) ;
98
+ client . requestLogger . logRequest (
99
+ {
100
+ timestamp : Date . now ( ) / 1000 ,
101
+ method : ctx . request . method ,
102
+ path,
103
+ url : ctx . request . href ,
104
+ headers : convertHeaders ( ctx . request . headers ) ,
105
+ size : ctx . request . length ,
106
+ consumer : consumer ?. identifier ,
107
+ body : convertBody (
108
+ ctx . request . body ,
109
+ ctx . request . get ( "content-type" ) ,
110
+ ) ,
111
+ } ,
112
+ {
113
+ statusCode : statusCode || ctx . response . status ,
114
+ responseTime : responseTime / 1000 ,
115
+ headers : convertHeaders ( ctx . response . headers ) ,
116
+ size : ctx . response . length ,
117
+ body : convertBody (
118
+ ctx . response . body ,
119
+ ctx . response . get ( "content-type" ) ,
120
+ ) ,
121
+ } ,
122
+ serverError ,
123
+ logs ,
80
124
) ;
81
125
}
82
126
}
83
- if ( client . requestLogger . enabled ) {
84
- client . requestLogger . logRequest (
85
- {
86
- timestamp : Date . now ( ) / 1000 ,
87
- method : ctx . request . method ,
88
- path,
89
- url : ctx . request . href ,
90
- headers : convertHeaders ( ctx . request . headers ) ,
91
- size : ctx . request . length ,
92
- consumer : consumer ?. identifier ,
93
- body : convertBody (
94
- ctx . request . body ,
95
- ctx . request . get ( "content-type" ) ,
96
- ) ,
97
- } ,
98
- {
99
- statusCode : statusCode || ctx . response . status ,
100
- responseTime : responseTime / 1000 ,
101
- headers : convertHeaders ( ctx . response . headers ) ,
102
- size : ctx . response . length ,
103
- body : convertBody (
104
- ctx . response . body ,
105
- ctx . response . get ( "content-type" ) ,
106
- ) ,
107
- } ,
108
- serverError ,
109
- ) ;
110
- }
111
- }
127
+ } ) ;
112
128
} ;
113
129
}
114
130
0 commit comments