@@ -21,16 +21,8 @@ import {
21
21
AggregationTemporality ,
22
22
MetricReader ,
23
23
} from "../../opentelemetry-sdk-metrics/mod.ts" ;
24
- import {
25
- createServer ,
26
- IncomingMessage ,
27
- Server ,
28
- ServerResponse ,
29
- } from "node:http" ;
30
24
import { ExporterConfig } from "./export/types.ts" ;
31
25
import { PrometheusSerializer } from "./PrometheusSerializer.ts" ;
32
- /** Node.js v8.x compat */
33
- import { URL } from "node:url" ;
34
26
35
27
export class PrometheusExporter extends MetricReader {
36
28
static readonly DEFAULT_OPTIONS = {
@@ -45,7 +37,8 @@ export class PrometheusExporter extends MetricReader {
45
37
private readonly _port : number ;
46
38
private readonly _baseUrl : string ;
47
39
private readonly _endpoint : string ;
48
- private readonly _server : Server ;
40
+ private _server ?: Deno . Server ;
41
+ private _serverAbort ?: AbortController ;
49
42
private readonly _prefix ?: string ;
50
43
private readonly _appendTimestamp : boolean ;
51
44
private _serializer : PrometheusSerializer ;
@@ -81,8 +74,6 @@ export class PrometheusExporter extends MetricReader {
81
74
typeof config . appendTimestamp === "boolean"
82
75
? config . appendTimestamp
83
76
: PrometheusExporter . DEFAULT_OPTIONS . appendTimestamp ;
84
- // unref to prevent prometheus exporter from holding the process open on exit
85
- this . _server = createServer ( this . _requestHandler ) . unref ( ) ;
86
77
this . _serializer = new PrometheusSerializer (
87
78
this . _prefix ,
88
79
this . _appendTimestamp ,
@@ -120,25 +111,16 @@ export class PrometheusExporter extends MetricReader {
120
111
stopServer ( ) : Promise < void > {
121
112
if ( ! this . _server ) {
122
113
diag . debug (
123
- "Prometheus stopServer() was called but server was never started." ,
114
+ "Prometheus stopServer() was called but server wasn't started." ,
124
115
) ;
125
116
return Promise . resolve ( ) ;
126
117
} else {
127
- return new Promise ( ( resolve ) => {
128
- this . _server . close ( ( err ) => {
129
- if ( ! err ) {
130
- diag . debug ( "Prometheus exporter was stopped" ) ;
131
- } else {
132
- if (
133
- ( err as unknown as { code : string } ) . code !==
134
- "ERR_SERVER_NOT_RUNNING"
135
- ) {
136
- globalErrorHandler ( err ) ;
137
- }
138
- }
139
- resolve ( ) ;
140
- } ) ;
141
- } ) ;
118
+ this . _serverAbort ?. abort ( ) ;
119
+ return this . _server . finished
120
+ . then ( ( ) => {
121
+ this . _server = undefined ;
122
+ } )
123
+ . catch ( globalErrorHandler ) ;
142
124
}
143
125
}
144
126
@@ -147,32 +129,49 @@ export class PrometheusExporter extends MetricReader {
147
129
*/
148
130
startServer ( ) : Promise < void > {
149
131
return new Promise ( ( resolve , reject ) => {
150
- this . _server . once ( "error" , reject ) ;
151
- this . _server . listen (
152
- {
153
- port : this . _port ,
154
- host : this . _host ,
155
- } ,
156
- ( ) => {
157
- diag . debug (
158
- `Prometheus exporter server started: ${ this . _host } :${ this . _port } /${ this . _endpoint } ` ,
159
- ) ;
160
- resolve ( ) ;
161
- } ,
162
- ) ;
132
+ try {
133
+ this . _serverAbort = new AbortController ( ) ;
134
+ this . _server = Deno . serve (
135
+ {
136
+ hostname : this . _host ,
137
+ port : this . _port ,
138
+ onListen : ( ) => {
139
+ diag . debug (
140
+ `Prometheus exporter server started: ${ this . _host } :${ this . _port } /${ this . _endpoint } ` ,
141
+ ) ;
142
+ resolve ( ) ;
143
+ } ,
144
+ signal : this . _serverAbort . signal ,
145
+ } ,
146
+ this . _requestHandler ,
147
+ ) ;
148
+ this . _server . unref ( ) ;
149
+ } catch ( error ) {
150
+ reject ( error ) ;
151
+ }
163
152
} ) ;
164
153
}
165
154
166
155
/**
167
- * Request handler that responds with the current state of metrics
168
- * @param _request Incoming HTTP request of server instance
169
- * @param response HTTP response object used to response to request
156
+ * Creates a response for the current state of metrics.
170
157
*/
171
- public getMetricsRequestHandler (
172
- _request : IncomingMessage ,
173
- response : ServerResponse ,
174
- ) : void {
175
- this . _exportMetrics ( response ) ;
158
+ public async getMetricsResponse ( ) : Promise < Response > {
159
+ try {
160
+ const { resourceMetrics, errors } = await this . collect ( ) ;
161
+ if ( errors . length ) {
162
+ diag . error ( "PrometheusExporter: metrics collection errors" , ...errors ) ;
163
+ }
164
+
165
+ return new Response ( this . _serializer . serialize ( resourceMetrics ) , {
166
+ status : 200 ,
167
+ headers : { "content-type" : "text/plain" } ,
168
+ } ) ;
169
+ } catch ( error ) {
170
+ return new Response ( `# failed to export metrics: ${ error } ` , {
171
+ status : 500 ,
172
+ headers : { "content-type" : "text/plain" } ,
173
+ } ) ;
174
+ }
176
175
}
177
176
178
177
/**
@@ -183,47 +182,22 @@ export class PrometheusExporter extends MetricReader {
183
182
* @param response HTTP response object used to respond to request
184
183
*/
185
184
private _requestHandler = (
186
- request : IncomingMessage ,
187
- response : ServerResponse ,
188
- ) => {
185
+ request : Request ,
186
+ ) : Response | Promise < Response > => {
189
187
if (
190
188
request . url != null &&
191
189
new URL ( request . url , this . _baseUrl ) . pathname === this . _endpoint
192
190
) {
193
- this . _exportMetrics ( response ) ;
191
+ return this . getMetricsResponse ( ) ;
194
192
} else {
195
- this . _notFound ( response ) ;
193
+ return this . _notFound ( ) ;
196
194
}
197
195
} ;
198
196
199
- /**
200
- * Responds to incoming message with current state of all metrics.
201
- */
202
- private _exportMetrics = ( response : ServerResponse ) => {
203
- response . statusCode = 200 ;
204
- response . setHeader ( "content-type" , "text/plain" ) ;
205
- this . collect ( ) . then (
206
- ( collectionResult ) => {
207
- const { resourceMetrics, errors } = collectionResult ;
208
- if ( errors . length ) {
209
- diag . error (
210
- "PrometheusExporter: metrics collection errors" ,
211
- ...errors ,
212
- ) ;
213
- }
214
- response . end ( this . _serializer . serialize ( resourceMetrics ) ) ;
215
- } ,
216
- ( err ) => {
217
- response . end ( `# failed to export metrics: ${ err } ` ) ;
218
- } ,
219
- ) ;
220
- } ;
221
-
222
197
/**
223
198
* Responds with 404 status code to all requests that do not match the configured endpoint.
224
199
*/
225
- private _notFound = ( response : ServerResponse ) => {
226
- response . statusCode = 404 ;
227
- response . end ( ) ;
228
- } ;
200
+ private _notFound ( ) : Response {
201
+ return new Response ( null , { status : 404 } ) ;
202
+ }
229
203
}
0 commit comments