11'use strict'
22
3- const http = require ( 'http' )
4- const { URL } = require ( 'url' )
5- const log = require ( '../../log' )
3+ const OtlpHttpExporterBase = require ( '../otlp/otlp_http_exporter_base' )
64const OtlpTransformer = require ( './otlp_transformer' )
7- const telemetryMetrics = require ( '../../telemetry/metrics' )
85
96/**
107 * @typedef {import('@opentelemetry/resources').Resource } Resource
118 * @typedef {import('@opentelemetry/api-logs').LogRecord } LogRecord
12- *
13- */
14-
15- const tracerMetrics = telemetryMetrics . manager . namespace ( 'tracers' )
9+ */
1610
1711/**
1812 * OtlpHttpLogExporter exports log records via OTLP over HTTP.
@@ -21,12 +15,9 @@ const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
2115 * https://opentelemetry.io/docs/specs/otlp/#otlphttp
2216 *
2317 * @class OtlpHttpLogExporter
18+ * @extends OtlpHttpExporterBase
2419 */
25- class OtlpHttpLogExporter {
26- #telemetryTags
27-
28- DEFAULT_LOGS_PATH = '/v1/logs'
29-
20+ class OtlpHttpLogExporter extends OtlpHttpExporterBase {
3021 /**
3122 * Creates a new OtlpHttpLogExporter instance.
3223 *
@@ -37,28 +28,8 @@ class OtlpHttpLogExporter {
3728 * @param {Resource } resource - Resource attributes
3829 */
3930 constructor ( url , headers , timeout , protocol , resource ) {
40- const parsedUrl = new URL ( url )
41-
42- this . protocol = protocol
31+ super ( url , headers , timeout , protocol , '/v1/logs' , 'logs' )
4332 this . transformer = new OtlpTransformer ( resource , protocol )
44- // If no path is provided, use default path
45- const path = parsedUrl . pathname === '/' ? this . DEFAULT_LOGS_PATH : parsedUrl . pathname
46- const isJson = protocol === 'http/json'
47- this . options = {
48- hostname : parsedUrl . hostname ,
49- port : parsedUrl . port ,
50- path : path + parsedUrl . search ,
51- method : 'POST' ,
52- timeout,
53- headers : {
54- 'Content-Type' : isJson ? 'application/json' : 'application/x-protobuf' ,
55- ...this . #parseAdditionalHeaders( headers )
56- }
57- }
58- this . #telemetryTags = [
59- 'protocol:http' ,
60- `encoding:${ isJson ? 'json' : 'protobuf' } `
61- ]
6233 }
6334
6435 /**
@@ -74,99 +45,8 @@ class OtlpHttpLogExporter {
7445 }
7546
7647 const payload = this . transformer . transformLogRecords ( logRecords )
77- this . #sendPayload( payload , resultCallback )
78- tracerMetrics . count ( 'otel.log_records' , this . #telemetryTags) . inc ( logRecords . length )
79- }
80-
81- /**
82- * Sends the payload via HTTP request.
83- * @param {Buffer|string } payload - The payload to send
84- * @param {Function } resultCallback - Callback for the result
85- * @private
86- */
87- #sendPayload ( payload , resultCallback ) {
88- const options = {
89- ...this . options ,
90- headers : {
91- ...this . options . headers ,
92- 'Content-Length' : payload . length
93- }
94- }
95-
96- const req = http . request ( options , ( res ) => {
97- let data = ''
98-
99- res . on ( 'data' , ( chunk ) => {
100- data += chunk
101- } )
102-
103- res . on ( 'end' , ( ) => {
104- if ( res . statusCode >= 200 && res . statusCode < 300 ) {
105- resultCallback ( { code : 0 } )
106- } else {
107- const error = new Error ( `HTTP ${ res . statusCode } : ${ data } ` )
108- resultCallback ( { code : 1 , error } )
109- }
110- } )
111- } )
112-
113- req . on ( 'error' , ( error ) => {
114- log . error ( 'Error sending OTLP logs:' , error )
115- resultCallback ( { code : 1 , error } )
116- } )
117-
118- req . on ( 'timeout' , ( ) => {
119- req . destroy ( )
120- const error = new Error ( 'Request timeout' )
121- resultCallback ( { code : 1 , error } )
122- } )
123-
124- req . write ( payload )
125- req . end ( )
126- }
127-
128- /**
129- * Parses additional HTTP headers from a comma-separated string.
130- * @param {string } headersString - Comma-separated key=value pairs
131- * @returns {Record<string, string> } Parsed headers object
132- * @private
133- */
134- #parseAdditionalHeaders ( headersString ) {
135- const headers = { }
136- let key = ''
137- let value = ''
138- let readingKey = true
139-
140- for ( const char of headersString ) {
141- if ( readingKey ) {
142- if ( char === '=' ) {
143- readingKey = false
144- key = key . trim ( )
145- } else {
146- key += char
147- }
148- } else if ( char === ',' ) {
149- value = value . trim ( )
150- if ( key && value ) {
151- headers [ key ] = value
152- }
153- key = ''
154- value = ''
155- readingKey = true
156- } else {
157- value += char
158- }
159- }
160-
161- // Add the last pair if present
162- if ( ! readingKey ) {
163- value = value . trim ( )
164- if ( value ) {
165- headers [ key ] = value
166- }
167- }
168-
169- return headers
48+ this . _sendPayload ( payload , resultCallback )
49+ this . _recordTelemetry ( 'otel.log_records' , logRecords . length )
17050 }
17151}
17252
0 commit comments