Skip to content

Commit 543805a

Browse files
committed
add new otel files
1 parent f73d425 commit 543805a

File tree

13 files changed

+1282
-4
lines changed

13 files changed

+1282
-4
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
'use strict'
2+
3+
/**
4+
* @fileoverview BatchLogRecordProcessor implementation for OpenTelemetry logs
5+
*
6+
* VERSION SUPPORT:
7+
* - OTLP Protocol: v1.7.0
8+
* - Protobuf Definitions: v1.7.0 (vendored from opentelemetry-proto)
9+
* - Other versions are not supported
10+
*
11+
* NOTE: The official @opentelemetry/sdk-logs package is tightly coupled to the
12+
* OpenTelemetry SDK and includes many dependencies we don't need. To avoid
13+
* pulling in the full SDK, we provide our own implementation that is heavily inspired
14+
* by the existing OpenTelemetry prior art.
15+
*
16+
* This implementation is based on:
17+
* - Official SDK Documentation: https://open-telemetry.github.io/opentelemetry-js/modules/_opentelemetry_sdk-logs.html
18+
* - BatchLogRecordProcessor Class: https://open-telemetry.github.io/opentelemetry-js/classes/_opentelemetry_sdk-logs.BatchLogRecordProcessor.html
19+
* - OpenTelemetry Logs SDK Specification: https://opentelemetry.io/docs/specs/otel/logs/sdk/
20+
*
21+
* Reference implementation (heavily inspired by):
22+
* - https://github.com/open-telemetry/opentelemetry-js/tree/v2.1.0/experimental/packages/sdk-logs
23+
* - https://github.com/open-telemetry/opentelemetry-proto/tree/v1.7.0
24+
*/
25+
26+
// const { logs } = require('@opentelemetry/api')
27+
const log = require('../../log')
28+
29+
/**
30+
* BatchLogRecordProcessor processes log records in batches for efficient export.
31+
*
32+
* This implementation follows the OpenTelemetry JavaScript SDK BatchLogRecordProcessor:
33+
* https://open-telemetry.github.io/opentelemetry-js/classes/_opentelemetry_sdk-logs.BatchLogRecordProcessor.html
34+
*
35+
* @class BatchLogRecordProcessor
36+
*/
37+
class BatchLogRecordProcessor {
38+
/**
39+
* Creates a new BatchLogRecordProcessor instance.
40+
*
41+
* @param {Array} processors - Array of log processors to process batches
42+
* @param {Object} config - Configuration options
43+
* @param {number} [config.batchTimeout=5000] - Timeout in milliseconds for batch processing
44+
* @param {number} [config.maxExportBatchSize=512] - Maximum number of log records per batch
45+
* @param {number} [config.maxQueueSize=2048] - Maximum number of log records in queue
46+
* @param {number} [config.exportTimeoutMillis=30000] - Timeout for export operations
47+
*/
48+
constructor (processors, config) {
49+
this._processors = processors
50+
this._config = config
51+
this._isShutdown = false
52+
this._batchTimeout = config.batchTimeout || 5000 // 5 seconds default
53+
this._maxExportBatchSize = config.maxExportBatchSize || 512
54+
this._maxQueueSize = config.maxQueueSize || 2048
55+
this._exportTimeoutMillis = config.exportTimeoutMillis || 30_000 // 30 seconds default
56+
57+
this._logRecords = []
58+
this._timer = null
59+
this._shutdownPromise = null
60+
}
61+
62+
/**
63+
* Processes a single log record.
64+
*
65+
* This method is called by the Logger when a log record is emitted.
66+
* It adds the record to the batch and triggers export if conditions are met.
67+
*
68+
* @param {Object} logRecord - The log record to process
69+
* @param {string} logRecord.severityText - Severity text (e.g., 'INFO', 'ERROR')
70+
* @param {number} logRecord.severityNumber - Severity number
71+
* @param {string} logRecord.body - Log message body
72+
* @param {Object} logRecord.attributes - Log attributes
73+
* @param {number} logRecord.timestamp - Timestamp in nanoseconds
74+
*/
75+
onEmit (logRecord) {
76+
if (this._isShutdown) {
77+
return
78+
}
79+
80+
this._logRecords.push(logRecord)
81+
82+
// If we've reached the max batch size, export immediately
83+
if (this._logRecords.length >= this._maxExportBatchSize) {
84+
this._export()
85+
} else if (this._logRecords.length === 1) {
86+
// Start the timer for the first log record
87+
this._startTimer()
88+
}
89+
}
90+
91+
_startTimer () {
92+
if (this._timer) {
93+
return
94+
}
95+
96+
this._timer = setTimeout(() => {
97+
this._export()
98+
}, this._batchTimeout)
99+
}
100+
101+
_export () {
102+
if (this._logRecords.length === 0) {
103+
return
104+
}
105+
106+
const logRecords = this._logRecords.splice(0, this._maxExportBatchSize)
107+
this._clearTimer()
108+
109+
// Process through all registered processors
110+
for (const processor of this._processors) {
111+
try {
112+
processor.export(logRecords, () => {
113+
// Export callback - could be used for error handling
114+
})
115+
} catch (error) {
116+
log.error('Error in log processor export:', error)
117+
}
118+
}
119+
120+
// If there are more records, start the timer again
121+
if (this._logRecords.length > 0) {
122+
this._startTimer()
123+
}
124+
}
125+
126+
_clearTimer () {
127+
if (this._timer) {
128+
clearTimeout(this._timer)
129+
this._timer = null
130+
}
131+
}
132+
133+
forceFlush () {
134+
return new Promise((resolve) => {
135+
if (this._isShutdown) {
136+
resolve()
137+
return
138+
}
139+
140+
this._export()
141+
resolve()
142+
})
143+
}
144+
145+
shutdown () {
146+
if (this._isShutdown) {
147+
return this._shutdownPromise || Promise.resolve()
148+
}
149+
150+
this._isShutdown = true
151+
this._shutdownPromise = new Promise((resolve) => {
152+
this._clearTimer()
153+
154+
// Export any remaining log records
155+
this._export()
156+
157+
// Shutdown all processors
158+
const shutdownPromises = this._processors.map(processor => {
159+
if (typeof processor.shutdown === 'function') {
160+
return processor.shutdown()
161+
}
162+
return Promise.resolve()
163+
})
164+
165+
Promise.all(shutdownPromises).then(() => {
166+
resolve()
167+
})
168+
})
169+
170+
return this._shutdownPromise
171+
}
172+
}
173+
174+
module.exports = BatchLogRecordProcessor
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
syntax = "proto3";
2+
3+
package opentelemetry.proto.common.v1;
4+
5+
option go_package = "go.opentelemetry.io/collector/pdata/pcommon";
6+
7+
// AnyValue is used to represent any type of attribute value. AnyValue may contain a
8+
// simple scalar or an arbitrary complex structure including arrays and nested objects.
9+
// AnyValue is a oneof type and can be one of the following:
10+
// - string_value: A string value.
11+
// - bool_value: A boolean value.
12+
// - int_value: An integer value.
13+
// - double_value: A double value.
14+
// - array_value: An array of AnyValue values.
15+
// - kvlist_value: A key-value list of AnyValue values.
16+
// - bytes_value: A bytes value.
17+
message AnyValue {
18+
oneof value {
19+
string string_value = 1;
20+
bool bool_value = 2;
21+
int64 int_value = 3;
22+
double double_value = 4;
23+
ArrayValue array_value = 5;
24+
KeyValueList kvlist_value = 6;
25+
bytes bytes_value = 7;
26+
}
27+
}
28+
29+
// ArrayValue is a list of AnyValue messages. We need ArrayValue as a message
30+
// since oneof in AnyValue does not allow repeated fields.
31+
message ArrayValue {
32+
// Array of values. The array may be empty (contain 0 elements).
33+
repeated AnyValue values = 1;
34+
}
35+
36+
// KeyValueList is a list of KeyValue messages. We need KeyValueList as a message
37+
// since oneof in AnyValue does not allow repeated fields.
38+
message KeyValueList {
39+
// A collection of key/value pairs of key-value pairs. The list may be empty (may
40+
// contain 0 elements).
41+
repeated KeyValue values = 1;
42+
}
43+
44+
// KeyValue is a key-value pair that is used to store metadata about the telemetry
45+
// record.
46+
message KeyValue {
47+
string key = 1;
48+
AnyValue value = 2;
49+
}
50+
51+
// InstrumentationScope is a message representing the instrumentation scope information
52+
// such as the fully qualified name and version.
53+
message InstrumentationScope {
54+
// An empty instrumentation scope name means the name is unknown.
55+
string name = 1;
56+
string version = 2;
57+
repeated KeyValue attributes = 3;
58+
uint32 dropped_attributes_count = 4;
59+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use strict'
2+
3+
/**
4+
* @fileoverview OpenTelemetry Logs Implementation for dd-trace-js
5+
*
6+
* This module provides OpenTelemetry logs functionality for dd-trace-js.
7+
*
8+
* VERSION SUPPORT:
9+
* - OTLP Protocol: v1.7.0
10+
* - Protobuf Definitions: v1.7.0 (vendored from opentelemetry-proto)
11+
* - Other versions are not supported
12+
*
13+
* TESTING:
14+
* Run the OpenTelemetry logs tests with:
15+
* npx mocha packages/dd-trace/test/opentelemetry/logs.spec.js --timeout 30000
16+
*
17+
* NOTE: The official @opentelemetry/sdk-logs and @opentelemetry/otlp-transformer
18+
* packages are tightly coupled to the OpenTelemetry SDK and require @opentelemetry/sdk-logs
19+
* as a dependency. To avoid pulling in the full SDK, we provide our own implementation
20+
* that is heavily inspired by the existing OpenTelemetry prior art.
21+
*
22+
* Reference implementation (heavily inspired by):
23+
* - https://github.com/open-telemetry/opentelemetry-js/tree/v2.1.0/experimental/packages/sdk-logs
24+
* - https://github.com/open-telemetry/opentelemetry-js/tree/v2.1.0/experimental/packages/otlp-transformer
25+
* - https://github.com/open-telemetry/opentelemetry-proto/tree/v1.7.0
26+
*/
27+
28+
const LoggerProvider = require('./logger_provider')
29+
const Logger = require('./logger')
30+
const BatchLogRecordProcessor = require('./batch_log_processor')
31+
const OtlpHttpLogExporter = require('./otlp_http_log_exporter')
32+
const OtlpTransformer = require('./otlp_transformer')
33+
34+
module.exports = {
35+
LoggerProvider,
36+
Logger,
37+
BatchLogRecordProcessor,
38+
OtlpHttpLogExporter,
39+
OtlpTransformer
40+
}

0 commit comments

Comments
 (0)