kafka-crab-js 2.1.0-alpha.2 → 2.1.0
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/README.md +66 -3
- package/dist/index.cjs +7 -46
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +7 -46
- package/dist/index.js.map +2 -2
- package/dist/otel/constants.d.ts +1 -1
- package/dist/otel/instrumentation.d.ts +2 -3
- package/dist/otel/types.d.ts +3 -1
- package/dist/otel/utils.d.ts +1 -2
- package/dist/streams/base-kafka-stream-readable.d.ts +0 -6
- package/js-binding.cjs +52 -52
- package/js-binding.d.ts +92 -0
- package/js-binding.js +52 -52
- package/package.json +13 -11
package/README.md
CHANGED
|
@@ -10,6 +10,44 @@ A lightweight, flexible, and reliable Kafka client for JavaScript/TypeScript. It
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
+
## What's New in Version 2.1.0
|
|
14
|
+
|
|
15
|
+
### New Features
|
|
16
|
+
|
|
17
|
+
1. **Simplified Message Commits with `commitMessage()`**:
|
|
18
|
+
- New convenience method that accepts a message and commit mode directly
|
|
19
|
+
- Automatically handles `offset + 1` increment internally - no more manual offset arithmetic
|
|
20
|
+
- Available on both `KafkaConsumer` and stream consumers
|
|
21
|
+
- **Before** (v2.0.0):
|
|
22
|
+
```javascript
|
|
23
|
+
const message = await consumer.recv();
|
|
24
|
+
await consumer.commit(message.topic, message.partition, message.offset + 1, 'Sync');
|
|
25
|
+
```
|
|
26
|
+
- **After** (v2.1.0):
|
|
27
|
+
```javascript
|
|
28
|
+
const message = await consumer.recv();
|
|
29
|
+
await consumer.commitMessage(message, 'Sync');
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
2. **Enhanced OpenTelemetry Support**:
|
|
33
|
+
- Improved OTEL context propagation for better distributed tracing
|
|
34
|
+
- Safe handling when OTEL SDK is not installed (no-op behavior)
|
|
35
|
+
- Better span context management across producer and consumer operations
|
|
36
|
+
- Seamless integration with standard OTEL SDK setup
|
|
37
|
+
|
|
38
|
+
3. **CI/CD Improvements**:
|
|
39
|
+
- Updated to Node.js 24 support
|
|
40
|
+
- GitHub Actions updated to v6
|
|
41
|
+
- Improved caching with actions/cache v4
|
|
42
|
+
|
|
43
|
+
### Migration from 2.0.x
|
|
44
|
+
|
|
45
|
+
- **No breaking changes** - all existing code continues to work
|
|
46
|
+
- The new `commitMessage()` method is additive - existing `commit()` calls remain valid
|
|
47
|
+
- OTEL improvements are transparent and require no code changes
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
13
51
|
## What's New in Version 2.0.0
|
|
14
52
|
|
|
15
53
|
### BREAKING CHANGES ⚠️
|
|
@@ -23,7 +61,7 @@ This major version includes important breaking changes that improve API consiste
|
|
|
23
61
|
- **After**: `consumer.subscribe([{ topic: 'my-topic', createTopic: true }])`
|
|
24
62
|
|
|
25
63
|
2. **Stream Lifecycle Management**:
|
|
26
|
-
- Stream consumers now properly implement Node.js stream lifecycle methods (`_destroy()
|
|
64
|
+
- Stream consumers now properly implement Node.js stream lifecycle methods (`_destroy()`)
|
|
27
65
|
- **Memory leak prevention**: Streams now automatically disconnect Kafka consumers during destruction
|
|
28
66
|
- Better resource cleanup ensures no hanging connections or memory leaks
|
|
29
67
|
- Error handling during stream destruction is improved with proper error propagation
|
|
@@ -179,8 +217,12 @@ async function run() {
|
|
|
179
217
|
value: payload.toString()
|
|
180
218
|
});
|
|
181
219
|
|
|
182
|
-
// Manual commit
|
|
183
|
-
|
|
220
|
+
// Manual commit - two options:
|
|
221
|
+
// Option 1 (v2.1.0+): Simplified with commitMessage
|
|
222
|
+
await consumer.commitMessage(message, 'Sync');
|
|
223
|
+
|
|
224
|
+
// Option 2: Traditional commit with manual offset increment
|
|
225
|
+
// await consumer.commit(topic, partition, offset + 1, 'Sync');
|
|
184
226
|
|
|
185
227
|
consumer.unsubscribe();
|
|
186
228
|
}
|
|
@@ -481,6 +523,27 @@ You can find some examples on the [example](https://github.com/flash-tecnologia/
|
|
|
481
523
|
| `fetchMetadataTimeout` | `number` | `60000` | Timeout for fetching metadata (ms) |
|
|
482
524
|
| `maxBatchMessages` | `number` | `1000` | Maximum messages in a batch operation |
|
|
483
525
|
|
|
526
|
+
### Consumer Commit Methods
|
|
527
|
+
|
|
528
|
+
kafka-crab-js provides two methods for committing offsets:
|
|
529
|
+
|
|
530
|
+
| Method | Signature | Description |
|
|
531
|
+
| --- | --- | --- |
|
|
532
|
+
| `commit` | `commit(topic, partition, offset, mode)` | Traditional commit - you must calculate `offset + 1` |
|
|
533
|
+
| `commitMessage` | `commitMessage(message, mode)` | **v2.1.0+**: Simplified commit - automatically handles offset increment |
|
|
534
|
+
|
|
535
|
+
```javascript
|
|
536
|
+
// Using commitMessage (recommended for v2.1.0+)
|
|
537
|
+
const message = await consumer.recv();
|
|
538
|
+
await consumer.commitMessage(message, 'Sync');
|
|
539
|
+
|
|
540
|
+
// Using commit (traditional)
|
|
541
|
+
const message = await consumer.recv();
|
|
542
|
+
await consumer.commit(message.topic, message.partition, message.offset + 1, 'Sync');
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
Both methods support `'Sync'` and `'Async'` commit modes.
|
|
546
|
+
|
|
484
547
|
### ProducerConfiguration
|
|
485
548
|
|
|
486
549
|
| Property | Type | Default | Description |
|
package/dist/index.cjs
CHANGED
|
@@ -47,7 +47,6 @@ var import_js_binding = require("../js-binding.cjs");
|
|
|
47
47
|
|
|
48
48
|
// js-src/otel/instrumentation.ts
|
|
49
49
|
var import_api2 = require("@opentelemetry/api");
|
|
50
|
-
var import_instrumentation = require("@opentelemetry/instrumentation");
|
|
51
50
|
|
|
52
51
|
// js-src/otel/constants.ts
|
|
53
52
|
var KAFKA_SEMANTIC_CONVENTIONS = {
|
|
@@ -84,7 +83,7 @@ var KAFKA_DEFAULTS = {
|
|
|
84
83
|
};
|
|
85
84
|
var PACKAGE_INFO = {
|
|
86
85
|
NAME: "kafka-crab-js",
|
|
87
|
-
VERSION: "2.0
|
|
86
|
+
VERSION: "2.1.0"
|
|
88
87
|
// Should match package.json
|
|
89
88
|
};
|
|
90
89
|
|
|
@@ -100,17 +99,7 @@ var DEFAULT_OTEL_CONFIG = {
|
|
|
100
99
|
|
|
101
100
|
// js-src/otel/utils.ts
|
|
102
101
|
var import_api = require("@opentelemetry/api");
|
|
103
|
-
function isOtelAvailable() {
|
|
104
|
-
try {
|
|
105
|
-
return typeof import_api.trace !== "undefined";
|
|
106
|
-
} catch {
|
|
107
|
-
return false;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
102
|
function getTracer(name, version) {
|
|
111
|
-
if (!isOtelAvailable()) {
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
103
|
return import_api.trace.getTracer(name, version);
|
|
115
104
|
}
|
|
116
105
|
function setSpanStatus(span, error) {
|
|
@@ -316,13 +305,12 @@ function createBatchSpan(tracer, batchSize, topic, operation = "batch_process",
|
|
|
316
305
|
}
|
|
317
306
|
|
|
318
307
|
// js-src/otel/instrumentation.ts
|
|
319
|
-
var KafkaCrabInstrumentation = class
|
|
308
|
+
var KafkaCrabInstrumentation = class {
|
|
320
309
|
_kafkaTracer = null;
|
|
321
310
|
_kafkaConfig;
|
|
311
|
+
_enabled = false;
|
|
322
312
|
constructor(config = {}) {
|
|
323
|
-
|
|
324
|
-
super(PACKAGE_INFO.NAME, PACKAGE_INFO.VERSION, mergedConfig);
|
|
325
|
-
this._kafkaConfig = mergedConfig;
|
|
313
|
+
this._kafkaConfig = { ...DEFAULT_OTEL_CONFIG, ...config };
|
|
326
314
|
}
|
|
327
315
|
get kafkaConfig() {
|
|
328
316
|
return this._kafkaConfig;
|
|
@@ -336,29 +324,21 @@ var KafkaCrabInstrumentation = class extends import_instrumentation.Instrumentat
|
|
|
336
324
|
setTracerProvider(provider) {
|
|
337
325
|
this._kafkaTracer = provider.getTracer(PACKAGE_INFO.NAME, PACKAGE_INFO.VERSION);
|
|
338
326
|
}
|
|
339
|
-
// eslint-disable-next-line class-methods-use-this
|
|
340
|
-
init() {
|
|
341
|
-
return [];
|
|
342
|
-
}
|
|
343
327
|
enable() {
|
|
344
|
-
if (!isOtelAvailable()) {
|
|
345
|
-
import_api2.diag.warn("OpenTelemetry API not available, instrumentation disabled");
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
328
|
this._kafkaTracer = getTracer(PACKAGE_INFO.NAME, PACKAGE_INFO.VERSION);
|
|
329
|
+
this._enabled = true;
|
|
349
330
|
if (this._kafkaConfig?.registerOnInitialization && this._kafkaTracer) {
|
|
350
331
|
import_api2.diag.debug("Kafka OTEL instrumentation enabled");
|
|
351
332
|
}
|
|
352
333
|
}
|
|
353
334
|
disable() {
|
|
354
335
|
this._kafkaTracer = null;
|
|
336
|
+
this._enabled = false;
|
|
355
337
|
import_api2.diag.debug("Kafka OTEL instrumentation disabled");
|
|
356
338
|
}
|
|
357
|
-
// Check if instrumentation is enabled and available
|
|
358
339
|
isEnabled() {
|
|
359
|
-
return this._kafkaTracer !== null
|
|
340
|
+
return this._enabled && this._kafkaTracer !== null;
|
|
360
341
|
}
|
|
361
|
-
// Create OTEL context for Kafka clients
|
|
362
342
|
createOtelContext() {
|
|
363
343
|
if (!this.isEnabled()) {
|
|
364
344
|
return this._createDisabledContext();
|
|
@@ -400,7 +380,6 @@ var KafkaCrabInstrumentation = class extends import_instrumentation.Instrumentat
|
|
|
400
380
|
}
|
|
401
381
|
};
|
|
402
382
|
}
|
|
403
|
-
// Instrument producer send operation
|
|
404
383
|
instrumentProducerSend(originalSend, clientId) {
|
|
405
384
|
if (!this.isEnabled()) {
|
|
406
385
|
return originalSend;
|
|
@@ -500,7 +479,6 @@ var KafkaCrabInstrumentation = class extends import_instrumentation.Instrumentat
|
|
|
500
479
|
}
|
|
501
480
|
};
|
|
502
481
|
}
|
|
503
|
-
// Instrument consumer receive operation
|
|
504
482
|
instrumentConsumerReceive(originalReceive, groupId) {
|
|
505
483
|
if (!this.isEnabled()) {
|
|
506
484
|
return originalReceive;
|
|
@@ -537,7 +515,6 @@ var KafkaCrabInstrumentation = class extends import_instrumentation.Instrumentat
|
|
|
537
515
|
return message;
|
|
538
516
|
};
|
|
539
517
|
}
|
|
540
|
-
// Instrument batch consumer receive operation
|
|
541
518
|
instrumentBatchReceive(originalBatchReceive, groupId) {
|
|
542
519
|
if (!this.isEnabled() || !this._kafkaConfig.enableBatchInstrumentation) {
|
|
543
520
|
return originalBatchReceive;
|
|
@@ -708,14 +685,6 @@ var BaseKafkaStreamReadable = class extends import_node_stream.Readable {
|
|
|
708
685
|
* @private
|
|
709
686
|
*/
|
|
710
687
|
_destroy(error, callback) {
|
|
711
|
-
try {
|
|
712
|
-
this.push(null);
|
|
713
|
-
} catch {
|
|
714
|
-
}
|
|
715
|
-
try {
|
|
716
|
-
this.emit("end");
|
|
717
|
-
} catch {
|
|
718
|
-
}
|
|
719
688
|
try {
|
|
720
689
|
this.kafkaConsumer.unsubscribe();
|
|
721
690
|
} catch {
|
|
@@ -727,14 +696,6 @@ var BaseKafkaStreamReadable = class extends import_node_stream.Readable {
|
|
|
727
696
|
callback(combinedError);
|
|
728
697
|
});
|
|
729
698
|
}
|
|
730
|
-
/**
|
|
731
|
-
* Called when the stream is finishing (no more data will be written)
|
|
732
|
-
* Ensures proper cleanup when stream ends normally
|
|
733
|
-
* @private
|
|
734
|
-
*/
|
|
735
|
-
_final(callback) {
|
|
736
|
-
this.kafkaConsumer.disconnect().then(() => callback()).catch((error) => callback(error));
|
|
737
|
-
}
|
|
738
699
|
};
|
|
739
700
|
|
|
740
701
|
// js-src/streams/kafka-batch-stream-readable.ts
|
package/dist/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../js-src/index.ts", "../js-src/kafka-client.ts", "../js-src/otel/instrumentation.ts", "../js-src/otel/constants.ts", "../js-src/otel/types.ts", "../js-src/otel/utils.ts", "../js-src/streams/base-kafka-stream-readable.ts", "../js-src/streams/kafka-batch-stream-readable.ts", "../js-src/streams/kafka-stream-readable.ts"],
|
|
4
|
-
"sourcesContent": ["export type {\n ConsumerConfiguration,\n KafkaConfiguration,\n KafkaCrabError,\n KafkaEvent,\n KafkaEventPayload,\n Message,\n MessageProducer,\n OffsetModel,\n PartitionOffset,\n ProducerConfiguration,\n ProducerRecord,\n RecordMetadata,\n TopicPartition,\n TopicPartitionConfig,\n} from '../js-binding.js'\n\nexport {\n CommitMode,\n KafkaClientConfig,\n KafkaConsumer,\n KafkaEventName,\n KafkaProducer,\n PartitionPosition,\n SecurityProtocol,\n} from '../js-binding.js'\nexport { KafkaClient } from './kafka-client.js'\nexport { BaseKafkaStreamReadable } from './streams/base-kafka-stream-readable.js'\nexport { KafkaBatchStreamReadable } from './streams/kafka-batch-stream-readable.js'\nexport { KafkaStreamReadable } from './streams/kafka-stream-readable.js'\n\nexport type { KafkaClientConfiguration, StreamConsumerConfiguration } from './kafka-client.js'\n\n// OpenTelemetry exports\nexport type {\n BatchOtelContext,\n InstrumentedMessage,\n InstrumentedProducerRecord,\n KafkaOtelContext,\n KafkaOtelInstrumentationConfig,\n MessageHookFn,\n ProducerHookFn,\n TopicFilterFn,\n} from './otel/types.js'\n\nexport { getKafkaInstrumentation, KafkaCrabInstrumentation, resetKafkaInstrumentation } from './otel/instrumentation.js'\n\nexport { KAFKA_OPERATION_TYPES, KAFKA_SEMANTIC_CONVENTIONS, PACKAGE_INFO } from './otel/constants.js'\n", "import { context, type Span } from '@opentelemetry/api'\nimport type { ReadableOptions } from 'node:stream'\nimport {\n type ConsumerConfiguration,\n KafkaClientConfig,\n type KafkaConfiguration,\n type KafkaConsumer,\n type KafkaProducer,\n type ProducerConfiguration,\n} from '../js-binding.js'\n\nimport { getKafkaInstrumentation } from './otel/instrumentation.js'\nimport type { KafkaOtelContext, KafkaOtelInstrumentationConfig } from './otel/types.js'\nimport { KafkaBatchStreamReadable } from './streams/kafka-batch-stream-readable.js'\nimport { KafkaStreamReadable } from './streams/kafka-stream-readable.js'\n\nexport interface StreamConsumerConfiguration extends ConsumerConfiguration {\n batchSize?: number // Default 1 (single mode), > 1 enables batch mode\n batchTimeout?: number // Default 100ms, only used when batchSize > 1\n streamOptions?: ReadableOptions\n}\n\nexport interface KafkaClientConfiguration extends KafkaConfiguration {\n otel?: KafkaOtelInstrumentationConfig | false // OTEL configuration or false to disable\n}\n\n/**\n * KafkaClient class\n */\nexport class KafkaClient {\n private readonly kafkaClientConfig: KafkaClientConfig\n private readonly _otelEnabled: boolean\n private readonly _otelContext: KafkaOtelContext\n\n /**\n * Creates a KafkaClient instance\n * @throws {Error} If the configuration is invalid\n */\n constructor(private readonly kafkaConfiguration: KafkaClientConfiguration) {\n // Extract OTEL configuration\n const { otel, ...kafkaConfig } = kafkaConfiguration\n this.kafkaClientConfig = new KafkaClientConfig(kafkaConfig)\n\n // Initialize OTEL instrumentation\n this._otelEnabled = otel !== false && otel !== null\n if (this._otelEnabled && typeof otel === 'object') {\n const instrumentation = getKafkaInstrumentation(otel)\n this._otelContext = instrumentation.createOtelContext()\n } else if (this._otelEnabled) {\n const instrumentation = getKafkaInstrumentation()\n this._otelContext = instrumentation.createOtelContext()\n } else {\n this._otelContext = this._createDisabledOtelContext()\n }\n }\n\n /**\n * Get the OpenTelemetry context for this client\n * @returns {KafkaOtelContext} The OTEL context\n */\n get otel(): KafkaOtelContext {\n return this._otelContext\n }\n\n /**\n * Creates a KafkaProducer instance\n * @param {ProducerConfiguration} [producerConfiguration] - Optional producer configuration\n * @returns {KafkaProducer} A KafkaProducer instance\n */\n createProducer(producerConfiguration?: ProducerConfiguration) {\n const producer = producerConfiguration\n ? this.kafkaClientConfig.createProducer(producerConfiguration)\n : this.kafkaClientConfig.createProducer({})\n\n // Instrument producer if OTEL is enabled\n if (this._otelEnabled && this._otelContext.enabled) {\n return this._instrumentProducer(producer)\n }\n\n return producer\n }\n\n /**\n * Creates a KafkaConsumer instance\n * @param {ConsumerConfiguration} consumerConfiguration - Consumer configuration\n * @returns {KafkaConsumer} A KafkaConsumer instance\n * @throws {Error} If the configuration is invalid\n */\n createConsumer(consumerConfiguration: ConsumerConfiguration) {\n const consumer = this.kafkaClientConfig.createConsumer(consumerConfiguration)\n\n // Instrument consumer if OTEL is enabled\n if (this._otelEnabled && this._otelContext.enabled) {\n return KafkaClient._instrumentConsumer(consumer, consumerConfiguration.groupId)\n }\n\n return consumer\n }\n\n /**\n * Creates a stream consumer instance\n * @param {StreamConsumerConfiguration} streamConfiguration - Stream consumer configuration including batch mode and stream options\n * @returns {KafkaStreamReadable | KafkaBatchStreamReadable} A stream consumer instance\n * @throws {Error} If the configuration is invalid\n */\n createStreamConsumer(\n streamConfiguration: StreamConsumerConfiguration,\n ): KafkaStreamReadable | KafkaBatchStreamReadable {\n const { batchSize, batchTimeout, streamOptions, ...consumerConfiguration } = streamConfiguration\n const kafkaConsumer = this.kafkaClientConfig.createConsumer(consumerConfiguration)\n const instrumentedConsumer = this._otelEnabled && this._otelContext.enabled\n ? KafkaClient._instrumentConsumer(kafkaConsumer, consumerConfiguration.groupId)\n : kafkaConsumer\n const opts = streamOptions ?? { objectMode: true }\n\n // Return appropriate class based on batch configuration\n if (batchSize && batchSize > 1) {\n return new KafkaBatchStreamReadable({ kafkaConsumer: instrumentedConsumer, batchSize, batchTimeout, ...opts })\n }\n\n return new KafkaStreamReadable({ kafkaConsumer: instrumentedConsumer, ...opts })\n }\n\n private _instrumentProducer(producer: KafkaProducer) {\n const instrumentation = getKafkaInstrumentation()\n const originalSend = producer.send.bind(producer)\n\n producer.send = instrumentation.instrumentProducerSend(\n originalSend,\n this.kafkaConfiguration.clientId,\n )\n\n return producer\n }\n\n private static _instrumentConsumer(consumer: KafkaConsumer, groupId?: string) {\n const instrumentation = getKafkaInstrumentation()\n const originalRecv = consumer.recv.bind(consumer)\n const originalRecvBatch = consumer.recvBatch.bind(consumer)\n\n consumer.recv = instrumentation.instrumentConsumerReceive(originalRecv, groupId)\n consumer.recvBatch = instrumentation.instrumentBatchReceive(originalRecvBatch, groupId)\n\n return consumer\n }\n\n // eslint-disable-next-line class-methods-use-this\n private _createDisabledOtelContext(): KafkaOtelContext {\n // Provide safe no-op implementations so callers can still invoke methods without guarding\n return {\n enabled: false,\n span: null,\n tracer: null,\n context: context.active(),\n inject: () => {\n /* no-op */\n },\n extract: () => context.active(),\n startSpan: () => null,\n endSpan: (span?: Span | null) => {\n if (span && typeof span.end === 'function') {\n span.end()\n }\n },\n }\n }\n}\n", "import { type Attributes, context, diag, type Span, trace, type Tracer } from '@opentelemetry/api'\nimport { InstrumentationBase, type InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation'\n\nimport type { KafkaConsumer, KafkaProducer, Message, ProducerRecord, RecordMetadata } from '../../js-binding.js'\nimport { PACKAGE_INFO } from './constants.js'\nimport {\n DEFAULT_OTEL_CONFIG,\n type KafkaOtelContext,\n type KafkaOtelInstrumentationConfig,\n type TracerProvider,\n} from './types.js'\nimport {\n createBatchSpan,\n createConsumerSpan,\n createProducerSpan,\n extractTraceContext,\n getTracer,\n injectTraceContext,\n isOtelAvailable,\n normalizeHeadersToBuffer,\n setSpanStatus,\n shouldIgnoreTopic,\n} from './utils.js'\n\nexport class KafkaCrabInstrumentation extends InstrumentationBase {\n private _kafkaTracer: Tracer | null = null\n private _kafkaConfig: KafkaOtelInstrumentationConfig\n\n constructor(config: KafkaOtelInstrumentationConfig = {}) {\n // Initialize kafka config before calling super to avoid undefined access in enable()\n const mergedConfig = { ...DEFAULT_OTEL_CONFIG, ...config }\n super(PACKAGE_INFO.NAME, PACKAGE_INFO.VERSION, mergedConfig)\n this._kafkaConfig = mergedConfig\n }\n\n public get kafkaConfig(): KafkaOtelInstrumentationConfig {\n return this._kafkaConfig\n }\n\n public get kafkaTracer(): Tracer | null {\n return this._kafkaTracer\n }\n\n public updateConfig(config: KafkaOtelInstrumentationConfig): void {\n // Merge new config with existing config\n this._kafkaConfig = { ...this._kafkaConfig, ...config }\n }\n\n public setTracerProvider(provider: TracerProvider): void {\n // Re-initialize tracer with the new provider\n this._kafkaTracer = provider.getTracer(PACKAGE_INFO.NAME, PACKAGE_INFO.VERSION)\n }\n\n // eslint-disable-next-line class-methods-use-this\n protected init(): InstrumentationNodeModuleDefinition[] {\n // We don't need module patching since we'll instrument directly\n return []\n }\n\n public enable(): void {\n if (!isOtelAvailable()) {\n diag.warn('OpenTelemetry API not available, instrumentation disabled')\n return\n }\n\n this._kafkaTracer = getTracer(PACKAGE_INFO.NAME, PACKAGE_INFO.VERSION)\n\n if (this._kafkaConfig?.registerOnInitialization && this._kafkaTracer) {\n diag.debug('Kafka OTEL instrumentation enabled')\n }\n }\n\n public disable(): void {\n this._kafkaTracer = null\n diag.debug('Kafka OTEL instrumentation disabled')\n }\n\n // Check if instrumentation is enabled and available\n public isEnabled(): boolean {\n return this._kafkaTracer !== null && isOtelAvailable()\n }\n\n // Create OTEL context for Kafka clients\n public createOtelContext(): KafkaOtelContext {\n if (!this.isEnabled()) {\n return this._createDisabledContext()\n }\n\n return {\n enabled: true,\n span: trace.getActiveSpan() || null,\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n tracer: this._kafkaTracer!,\n context: context.active(),\n inject: (carrier, spanToInject?: Span) => {\n // If a specific span is provided, use its context\n if (spanToInject) {\n const spanContext = trace.setSpan(context.active(), spanToInject)\n injectTraceContext(carrier, spanContext)\n return\n }\n\n // Otherwise try to get the active span\n const activeSpan = trace.getActiveSpan()\n if (activeSpan) {\n const spanContext = trace.setSpan(context.active(), activeSpan)\n injectTraceContext(carrier, spanContext)\n } else {\n // Fallback to active context\n injectTraceContext(carrier, context.active())\n }\n },\n extract: (carrier) => extractTraceContext(carrier),\n startSpan: (name, attributes: Attributes = {}) => {\n if (!this._kafkaTracer) {\n throw new Error('Tracer not available')\n }\n const span = this._kafkaTracer.startSpan(name, { attributes })\n return span\n },\n endSpan: (span, error) => {\n if (!span) {\n return\n }\n setSpanStatus(span, error)\n span.end()\n },\n }\n }\n\n // Instrument producer send operation\n public instrumentProducerSend(\n originalSend: Function,\n clientId?: string,\n ): (producerRecord: ProducerRecord) => Promise<RecordMetadata[]> {\n if (!this.isEnabled()) {\n return originalSend as (producerRecord: ProducerRecord) => Promise<RecordMetadata[]>\n }\n\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const instrumentation = this\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const tracer = this._kafkaTracer!\n\n return async function instrumentedSend(this: KafkaProducer, record: ProducerRecord | ProducerRecord[]) {\n if (!record) {\n return originalSend.call(this, record as ProducerRecord)\n }\n\n // Capture the current caller context to preserve parent relationships across async boundaries\n const callerContext = context.active()\n\n const isArrayInput = Array.isArray(record)\n const records = isArrayInput ? record : [record]\n\n if (records.length === 0) {\n return originalSend.call(this, isArrayInput ? records : (record as ProducerRecord))\n }\n\n // If every record should be ignored, bypass instrumentation altogether\n const allIgnored = records.every((currentRecord) =>\n shouldIgnoreTopic(currentRecord.topic, instrumentation._kafkaConfig.ignoreTopics)\n )\n\n if (allIgnored) {\n return originalSend.call(this, isArrayInput ? records : records[0])\n }\n\n const spans: Span[] = []\n\n const spanMetadata: { span: Span; record: ProducerRecord }[] = []\n\n const instrumentedRecords = records.map((currentRecord) => {\n if (!currentRecord || shouldIgnoreTopic(currentRecord.topic, instrumentation._kafkaConfig.ignoreTopics)) {\n return currentRecord\n }\n\n // Make producer span a child of the caller's active context\n const span = createProducerSpan(tracer, currentRecord, 'send', callerContext)\n\n if (!span) {\n return currentRecord\n }\n\n if (clientId) {\n span.setAttributes({ 'messaging.client.id': clientId })\n }\n\n spans.push(span)\n spanMetadata.push({ span, record: currentRecord })\n\n const spanContext = trace.setSpan(callerContext, span)\n\n const instrumentedRecord: ProducerRecord = {\n ...currentRecord,\n messages: (currentRecord.messages ?? []).map(message => {\n const originalHeaders = { ...message.headers }\n const injectedHeaders = injectTraceContext(originalHeaders, spanContext)\n const normalizedHeaders = normalizeHeadersToBuffer(injectedHeaders)\n\n return {\n ...message,\n headers: normalizedHeaders,\n }\n }),\n }\n\n if (instrumentation._kafkaConfig.producerHook) {\n try {\n context.with(spanContext, () => {\n instrumentation._kafkaConfig.producerHook?.(span, currentRecord)\n })\n } catch (error) {\n diag.warn('Producer hook failed:', error)\n }\n }\n\n return instrumentedRecord\n })\n\n const payload = isArrayInput ? instrumentedRecords : instrumentedRecords[0]\n\n try {\n const result = await context.with(callerContext, async () => originalSend.call(this, payload as ProducerRecord))\n\n // Enrich spans with delivery metadata when available\n const metadataArray = Array.isArray(result) ? result : []\n for (let idx = 0; idx < spanMetadata.length; idx++) {\n const { span } = spanMetadata[idx]\n const metadata = metadataArray[idx]\n if (metadata) {\n if (metadata.partition !== undefined) {\n span.setAttribute('messaging.kafka.partition', metadata.partition)\n }\n if (metadata.offset !== undefined) {\n span.setAttribute('messaging.kafka.offset', metadata.offset)\n }\n }\n setSpanStatus(span, metadata?.error ? new Error(metadata.error.message) : undefined)\n span.end()\n }\n\n // If a producerHook is configured, invoke it with metadata for the first record\n if (instrumentation._kafkaConfig.producerHook && metadataArray.length) {\n const [first] = spanMetadata\n if (first) {\n try {\n instrumentation._kafkaConfig.producerHook(first.span, first.record, metadataArray[0])\n } catch (error) {\n diag.warn('Producer hook failed with metadata:', error)\n }\n }\n }\n\n return result\n } catch (error) {\n for (const span of spans) {\n setSpanStatus(span, error instanceof Error ? error : new Error(String(error)))\n span.end()\n }\n throw error\n }\n }\n }\n\n // Instrument consumer receive operation\n public instrumentConsumerReceive(originalReceive: Function, groupId?: string): () => Promise<Message | null> {\n if (!this.isEnabled()) {\n return originalReceive as () => Promise<Message | null>\n }\n\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const instrumentation = this\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const tracer = this._kafkaTracer!\n\n return async function instrumentedReceive(this: KafkaConsumer) {\n const message = await originalReceive.call(this)\n\n if (!message) {\n return message\n }\n\n // Check if topic should be ignored\n if (shouldIgnoreTopic(message.topic, instrumentation._kafkaConfig.ignoreTopics)) {\n return message\n }\n\n // Extract trace context from message headers\n const parentContext = extractTraceContext(message.headers || {}) || context.active()\n\n // Create consumer span with extracted context\n const span = createConsumerSpan(tracer, message, 'process', parentContext)\n\n if (span) {\n const spanCtx = trace.setSpan(parentContext, span)\n\n context.with(spanCtx, () => {\n // Add consumer group if available\n if (groupId) {\n span.setAttributes({ 'messaging.consumer.group.name': groupId })\n }\n\n // Call message hook if configured\n if (instrumentation._kafkaConfig.messageHook) {\n try {\n instrumentation._kafkaConfig.messageHook(span, message)\n } catch (error) {\n diag.warn('Message hook failed:', error)\n }\n }\n\n // End span immediately for receive operation\n setSpanStatus(span)\n })\n\n span.end()\n }\n\n return message\n }\n }\n\n // Instrument batch consumer receive operation\n public instrumentBatchReceive(\n originalBatchReceive: Function,\n groupId?: string,\n ): (size: number, timeoutMs: number) => Promise<Message[]> {\n if (!this.isEnabled() || !this._kafkaConfig.enableBatchInstrumentation) {\n return originalBatchReceive as (size: number, timeoutMs: number) => Promise<Message[]>\n }\n\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const instrumentation = this\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const tracer = this._kafkaTracer!\n\n return async function instrumentedBatchReceive(this: KafkaConsumer, size: number, timeoutMs: number) {\n const messages = await originalBatchReceive.call(this, size, timeoutMs)\n\n if (!Array.isArray(messages) || messages.length === 0) {\n return messages\n }\n\n // Filter out ignored topics\n const instrumentedMessages = messages.filter((message: Message) =>\n !shouldIgnoreTopic(message.topic, instrumentation._kafkaConfig.ignoreTopics)\n )\n\n if (instrumentedMessages.length === 0) {\n return messages\n }\n\n // Create batch span; prefer extracted context, fallback to active context\n const [firstMessage] = instrumentedMessages\n const parentContext = extractTraceContext(firstMessage.headers || {}) || context.active()\n const batchSpan = createBatchSpan(\n tracer,\n instrumentedMessages.length,\n firstMessage.topic,\n 'batch_process',\n parentContext,\n )\n\n if (batchSpan) {\n // Add consumer group if available\n if (groupId) {\n batchSpan.setAttributes({ 'messaging.consumer.group.name': groupId })\n }\n\n try {\n // Create individual spans for each message in the batch within parent context\n for (const message of instrumentedMessages) {\n const msgParentContext = extractTraceContext(message.headers || {}) || parentContext\n const messageSpan = createConsumerSpan(tracer, message, 'process', msgParentContext)\n\n if (messageSpan) {\n const messageSpanContext = trace.setSpan(msgParentContext || context.active(), messageSpan)\n context.with(messageSpanContext, () => {\n // Link to batch span\n messageSpan.setAttributes({\n 'messaging.batch.message_count': instrumentedMessages.length,\n })\n\n // Call message hook if configured\n if (instrumentation._kafkaConfig.messageHook) {\n try {\n instrumentation._kafkaConfig.messageHook(messageSpan, message)\n } catch (error) {\n diag.warn('Message hook failed:', error)\n }\n }\n\n setSpanStatus(messageSpan)\n })\n messageSpan.end()\n }\n }\n\n setSpanStatus(batchSpan)\n } catch (error) {\n setSpanStatus(batchSpan, error instanceof Error ? error : new Error(String(error)))\n } finally {\n batchSpan.end()\n }\n }\n\n return messages\n }\n }\n\n // eslint-disable-next-line class-methods-use-this\n private _createDisabledContext(): KafkaOtelContext {\n return {\n enabled: false,\n span: null,\n tracer: null,\n context: context.active(),\n inject: () => {\n /* no-op */\n },\n extract: () => context.active(),\n startSpan: () => null,\n endSpan: () => {\n /* no-op */\n },\n }\n }\n}\n\n// Singleton instance for global use\nlet globalInstrumentation: KafkaCrabInstrumentation | null = null\n\nexport function getKafkaInstrumentation(config?: KafkaOtelInstrumentationConfig): KafkaCrabInstrumentation {\n if (!globalInstrumentation) {\n globalInstrumentation = new KafkaCrabInstrumentation(config)\n globalInstrumentation.enable()\n } else if (config) {\n // Update existing instrumentation with new configuration\n globalInstrumentation.updateConfig(config)\n }\n return globalInstrumentation\n}\n\nexport function resetKafkaInstrumentation(): void {\n if (globalInstrumentation) {\n globalInstrumentation.disable()\n globalInstrumentation = null\n }\n}\n", "// OpenTelemetry semantic conventions for Kafka messaging\nexport const KAFKA_SEMANTIC_CONVENTIONS = {\n // Messaging system attributes (https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/)\n MESSAGING_SYSTEM: 'messaging.system',\n MESSAGING_DESTINATION_NAME: 'messaging.destination.name',\n MESSAGING_DESTINATION_KIND: 'messaging.destination.kind',\n MESSAGING_OPERATION_NAME: 'messaging.operation.name',\n MESSAGING_OPERATION_TYPE: 'messaging.operation.type',\n MESSAGING_CLIENT_ID: 'messaging.client.id',\n MESSAGING_MESSAGE_ID: 'messaging.message.id',\n MESSAGING_MESSAGE_BODY_SIZE: 'messaging.message.body.size',\n MESSAGING_BATCH_MESSAGE_COUNT: 'messaging.batch.message_count',\n\n // Kafka-specific attributes\n MESSAGING_KAFKA_OFFSET: 'messaging.kafka.offset',\n MESSAGING_KAFKA_PARTITION: 'messaging.kafka.partition',\n MESSAGING_KAFKA_MESSAGE_KEY: 'messaging.kafka.message.key',\n MESSAGING_KAFKA_CONSUMER_GROUP: 'messaging.kafka.consumer.group',\n MESSAGING_KAFKA_TOMBSTONE: 'messaging.kafka.tombstone',\n\n // Consumer-specific attributes\n MESSAGING_CONSUMER_GROUP_NAME: 'messaging.consumer.group.name',\n} as const\n\n// Operation types\nexport const KAFKA_OPERATION_TYPES = {\n SEND: 'send',\n RECEIVE: 'receive',\n PROCESS: 'process',\n BATCH_RECEIVE: 'batch_receive',\n BATCH_PROCESS: 'batch_process',\n} as const\n\n// Span names\nexport const KAFKA_SPAN_NAMES = {\n PRODUCER_SEND: (topic: string) => `${topic} send`,\n CONSUMER_RECEIVE: (topic: string) => `${topic} receive`,\n CONSUMER_PROCESS: (topic: string) => `${topic} process`,\n BATCH_RECEIVE: 'kafka batch receive',\n BATCH_PROCESS: (topic: string) => `${topic} batch process`,\n} as const\n\n// Default values\nexport const KAFKA_DEFAULTS = {\n MESSAGING_SYSTEM: 'kafka',\n DESTINATION_KIND: 'topic',\n BATCH_TIMEOUT_MS: 1000,\n} as const\n\n// Package information\nexport const PACKAGE_INFO = {\n NAME: 'kafka-crab-js',\n VERSION: '2.0.1', // Should match package.json\n} as const\n", "import type { Attributes, Context, Span, Tracer } from '@opentelemetry/api'\nimport type { InstrumentationConfig } from '@opentelemetry/instrumentation'\nimport type { Message, ProducerRecord, RecordMetadata } from '../../js-binding.js'\n\n// OpenTelemetry TracerProvider interface\nexport interface TracerProvider {\n getTracer(name: string, version?: string, options?: unknown): Tracer\n}\n\n// Use the actual types from js-binding instead of custom interfaces\n// This avoids type compatibility issues with the real implementations\n\n// Configuration interface for Kafka OTEL instrumentation\nexport interface KafkaOtelInstrumentationConfig extends InstrumentationConfig {\n // Service name for telemetry (defaults to OTEL_SERVICE_NAME env var or 'kafka-client')\n serviceName?: string\n\n // Whether to register instrumentation automatically on initialization\n registerOnInitialization?: boolean\n\n // Function to filter topics from instrumentation\n ignoreTopics?: string[] | ((topic: string) => boolean)\n\n // Custom hook called for each message/span\n messageHook?: (span: Span, message: Message) => void\n\n // Custom hook called for producer operations\n producerHook?: (span: Span, record: ProducerRecord, metadata?: RecordMetadata) => void\n\n // Whether to capture message payloads as span attributes (security sensitive)\n captureMessagePayload?: boolean\n\n // Maximum size of message payload to capture (in bytes)\n maxPayloadSize?: number\n\n // Whether to capture message headers as span attributes\n captureMessageHeaders?: boolean\n\n // Whether to enable batch operation instrumentation\n enableBatchInstrumentation?: boolean\n}\n\n// OpenTelemetry context interface exposed by clients\nexport interface KafkaOtelContext {\n // Whether OTEL is enabled for this client\n enabled: boolean\n\n // Current active span (if any)\n span: Span | null\n\n // Tracer instance for creating spans\n tracer: Tracer | null\n\n // Current OTEL context\n context: Context | null\n\n // Inject trace context into carrier (e.g., Kafka headers)\n inject: (carrier: Record<string, string | string[] | undefined>) => void\n\n // Extract trace context from carrier (e.g., Kafka headers)\n extract: (carrier: Record<string, string | string[] | undefined>) => Context\n\n // Create a child span with proper context\n startSpan: (name: string, attributes?: Attributes) => Span | null\n\n // End a span with proper status handling\n endSpan: (span: Span | null | undefined, error?: Error) => void\n}\n\n// Enhanced message interface with OTEL context\nexport interface InstrumentedMessage extends Message {\n // Extracted OTEL context from message headers\n otelContext?: Context\n\n // Optional span created for this message\n span?: Span\n}\n\n// Enhanced producer record with OTEL context injection\nexport interface InstrumentedProducerRecord extends ProducerRecord {\n // Headers will be automatically injected with trace context\n headers?: Record<string, string | string[] | undefined>\n\n // Optional span for tracking this record\n span?: Span\n}\n\n// Batch processing context\nexport interface BatchOtelContext {\n // Parent span for the entire batch\n batchSpan: Span\n\n // Individual message spans within the batch\n messageSpans: Span[]\n\n // Batch size for telemetry\n batchSize: number\n\n // Processing start time\n startTime: number\n}\n\n// Hook function signatures\nexport type MessageHookFn = (span: Span, message: Message) => void\nexport type ProducerHookFn = (span: Span, record: ProducerRecord, metadata?: RecordMetadata) => void\nexport type TopicFilterFn = (topic: string) => boolean\n\n// Configuration defaults\nexport const DEFAULT_OTEL_CONFIG: Required<\n Pick<\n KafkaOtelInstrumentationConfig,\n | 'serviceName'\n | 'registerOnInitialization'\n | 'captureMessagePayload'\n | 'maxPayloadSize'\n | 'captureMessageHeaders'\n | 'enableBatchInstrumentation'\n >\n> = {\n serviceName: process.env.OTEL_SERVICE_NAME || 'kafka-client',\n registerOnInitialization: true,\n captureMessagePayload: false,\n maxPayloadSize: 1024,\n captureMessageHeaders: true,\n enableBatchInstrumentation: true,\n} as const\n", "import {\n type Attributes,\n type Context,\n context,\n propagation,\n type Span,\n SpanKind,\n SpanStatusCode,\n trace,\n type Tracer,\n} from '@opentelemetry/api'\nimport type { Message, ProducerRecord } from '../../js-binding.js'\nimport { KAFKA_DEFAULTS, KAFKA_SEMANTIC_CONVENTIONS } from './constants.js'\n\n// Check if OpenTelemetry is available\nexport function isOtelAvailable(): boolean {\n try {\n // Use dynamic import instead of require\n return typeof trace !== 'undefined'\n } catch {\n return false\n }\n}\n\n// Safely get tracer if OTEL is available\nexport function getTracer(name: string, version?: string) {\n if (!isOtelAvailable()) {\n return null\n }\n return trace.getTracer(name, version)\n}\n\n// Set span status based on error\nexport function setSpanStatus(span: Span, error?: Error): void {\n if (error) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message,\n })\n span.recordException(error)\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n}\n\n// Extract common Kafka attributes from message\nexport function getMessageAttributes(message: Message, operation: string): Attributes {\n const attributes: Attributes = {\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_SYSTEM]: KAFKA_DEFAULTS.MESSAGING_SYSTEM,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_DESTINATION_NAME]: message.topic,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_DESTINATION_KIND]: KAFKA_DEFAULTS.DESTINATION_KIND,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_OPERATION_NAME]: operation,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_KAFKA_PARTITION]: message.partition,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_KAFKA_OFFSET]: message.offset,\n }\n\n // Add optional attributes if present\n if (message.key !== null && message.key !== undefined) {\n attributes[KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_KAFKA_MESSAGE_KEY] = typeof message.key === 'string'\n ? message.key\n : String(message.key)\n }\n\n if (message.payload) {\n let payloadSize: number\n if (Buffer.isBuffer(message.payload)) {\n payloadSize = message.payload.length\n } else if (typeof message.payload === 'string') {\n payloadSize = Buffer.byteLength(message.payload, 'utf8')\n } else {\n payloadSize = JSON.stringify(message.payload).length\n }\n attributes[KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_MESSAGE_BODY_SIZE] = payloadSize\n }\n\n return attributes\n}\n\n// Extract common Kafka attributes from producer record\nexport function getProducerRecordAttributes(record: ProducerRecord, operation: string): Attributes {\n const attributes: Attributes = {\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_SYSTEM]: KAFKA_DEFAULTS.MESSAGING_SYSTEM,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_DESTINATION_NAME]: record.topic,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_DESTINATION_KIND]: KAFKA_DEFAULTS.DESTINATION_KIND,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_OPERATION_NAME]: operation,\n }\n\n // Add message count\n if (record.messages && record.messages.length > 0) {\n attributes[KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_BATCH_MESSAGE_COUNT] = record.messages.length\n\n // Use first message for key and payload size\n const [firstMessage] = record.messages\n\n // Add key if present\n if (firstMessage.key !== null && firstMessage.key !== undefined) {\n attributes[KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_KAFKA_MESSAGE_KEY] = Buffer.isBuffer(firstMessage.key)\n ? firstMessage.key.toString()\n : String(firstMessage.key)\n }\n\n // Add payload size if present\n if (firstMessage.payload) {\n let payloadSize: number\n if (Buffer.isBuffer(firstMessage.payload)) {\n payloadSize = firstMessage.payload.length\n } else if (typeof firstMessage.payload === 'string') {\n payloadSize = Buffer.byteLength(firstMessage.payload, 'utf8')\n } else {\n payloadSize = JSON.stringify(firstMessage.payload).length\n }\n attributes[KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_MESSAGE_BODY_SIZE] = payloadSize\n }\n }\n\n return attributes\n}\n\n// Convert Buffer headers to string headers for trace context injection\nfunction convertBufferHeaders(\n bufferHeaders: Record<string, Buffer> = {},\n): Record<string, string | string[] | undefined> {\n const stringHeaders: Record<string, string | string[] | undefined> = {}\n for (const [key, value] of Object.entries(bufferHeaders)) {\n stringHeaders[key] = value.toString('utf8')\n }\n return stringHeaders\n}\n\n// Convert string headers back to Buffer headers\nfunction convertToBufferHeaders(stringHeaders: Record<string, string | string[] | undefined>): Record<string, Buffer> {\n const bufferHeaders: Record<string, Buffer> = {}\n for (const [key, value] of Object.entries(stringHeaders)) {\n if (value !== undefined) {\n const stringValue = Array.isArray(value) ? value.join(',') : value\n bufferHeaders[key] = Buffer.from(stringValue, 'utf8')\n }\n }\n return bufferHeaders\n}\n\nexport type KafkaHeaderValue = Buffer | string | string[] | undefined\nexport type KafkaHeaderCarrier = Record<string, KafkaHeaderValue>\n\n// Inject trace context into Kafka headers (works with both string and Buffer headers)\nexport function injectTraceContext(\n headers: KafkaHeaderCarrier = {},\n ctx?: Context,\n): KafkaHeaderCarrier {\n const activeContext = ctx || context.active()\n const headerEntries = Object.entries(headers)\n const hasBufferValues = headerEntries.some(([, value]) => Buffer.isBuffer(value))\n\n // Convert Buffer headers to string headers if needed\n if (hasBufferValues) {\n const bufferCarrier = headers as Record<string, Buffer>\n const stringHeaders = convertBufferHeaders(bufferCarrier)\n\n propagation.inject(activeContext, stringHeaders, {\n set: (carrier, key, value) => {\n carrier[key] = value\n },\n })\n\n const bufferHeaders = convertToBufferHeaders(stringHeaders)\n\n for (const [key, value] of Object.entries(bufferHeaders)) {\n bufferCarrier[key] = value\n }\n\n return bufferCarrier\n }\n\n const stringCarrier = headers as Record<string, string | string[] | undefined>\n\n propagation.inject(activeContext, stringCarrier, {\n set: (carrier, key, value) => {\n carrier[key] = value\n },\n })\n\n // Preserve original string-based carrier for callers expecting strings\n return stringCarrier\n}\n\n// Normalize any header carrier into Buffer headers for Kafka bindings\nexport function normalizeHeadersToBuffer(headers: KafkaHeaderCarrier): Record<string, Buffer> {\n const bufferHeaders: Record<string, Buffer> = {}\n\n for (const [key, value] of Object.entries(headers)) {\n if (value !== undefined) {\n if (Buffer.isBuffer(value)) {\n bufferHeaders[key] = value\n } else if (Array.isArray(value)) {\n bufferHeaders[key] = Buffer.from(value.join(','), 'utf8')\n } else {\n bufferHeaders[key] = Buffer.from(value, 'utf8')\n }\n }\n }\n\n return bufferHeaders\n}\n\n// Extract trace context from Kafka headers\nexport function extractTraceContext(\n headers: Record<string, string | string[] | undefined> = {},\n): Context {\n return propagation.extract(context.active(), headers, {\n get: (carrier, key) => {\n const value = carrier[key]\n const singleValue = Array.isArray(value) ? value[0] : value\n\n if (Buffer.isBuffer(singleValue)) {\n return singleValue.toString('utf8')\n }\n\n return singleValue\n },\n keys: (carrier) => Object.keys(carrier),\n })\n}\n\n// Check if topic should be ignored based on filter configuration\nexport function shouldIgnoreTopic(\n topic: string,\n ignoreTopics?: string[] | ((topic: string) => boolean),\n): boolean {\n if (!ignoreTopics) {\n return false\n }\n\n if (Array.isArray(ignoreTopics)) {\n return ignoreTopics.includes(topic)\n }\n\n if (typeof ignoreTopics === 'function') {\n try {\n return ignoreTopics(topic)\n } catch {\n // If filter function throws, don't ignore the topic\n return false\n }\n }\n\n return false\n}\n\n// Create span for producer operation\nexport function createProducerSpan(\n tracer: Tracer,\n record: ProducerRecord,\n operation = 'send',\n parentContext?: Context,\n): Span | null {\n if (!tracer) {\n return null\n }\n const parent = parentContext ?? context.active()\n\n const spanName = `${record.topic} ${operation}`\n const attributes = getProducerRecordAttributes(record, operation)\n\n const spanOptions = {\n kind: SpanKind.PRODUCER,\n attributes,\n }\n\n return tracer.startSpan(spanName, spanOptions, parent)\n}\n\n// Create span for consumer operation\nexport function createConsumerSpan(\n tracer: Tracer,\n message: Message,\n operation = 'process',\n parentContext?: Context,\n): Span | null {\n if (!tracer) {\n return null\n }\n\n const spanName = `${message.topic} ${operation}`\n const attributes = getMessageAttributes(message, operation)\n\n const spanOptions = {\n kind: SpanKind.CONSUMER,\n attributes,\n }\n\n // Start span with parent context if provided\n if (parentContext) {\n return tracer.startSpan(spanName, spanOptions, parentContext)\n }\n\n return tracer.startSpan(spanName, spanOptions)\n}\n\n// Create batch span for batch operations\nexport function createBatchSpan(\n tracer: Tracer,\n batchSize: number,\n topic?: string,\n operation = 'batch_process',\n parentContext?: Context,\n): Span | null {\n if (!tracer) {\n return null\n }\n\n const spanName = topic ? `${topic} ${operation}` : `kafka ${operation}`\n const attributes: Attributes = {\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_SYSTEM]: KAFKA_DEFAULTS.MESSAGING_SYSTEM,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_OPERATION_NAME]: operation,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_BATCH_MESSAGE_COUNT]: batchSize,\n }\n\n if (topic) {\n attributes[KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_DESTINATION_NAME] = topic\n attributes[KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_DESTINATION_KIND] = KAFKA_DEFAULTS.DESTINATION_KIND\n }\n\n const spanOptions = {\n kind: SpanKind.CONSUMER,\n attributes,\n }\n\n if (parentContext) {\n return tracer.startSpan(spanName, spanOptions, parentContext)\n }\n\n return tracer.startSpan(spanName, spanOptions)\n}\n", "import { Readable, type ReadableOptions } from 'node:stream'\n\nimport type { CommitMode, KafkaConsumer, Message, OffsetModel, TopicPartitionConfig } from '../../js-binding.js'\n\nexport interface KafkaStreamReadableOptions extends ReadableOptions<Readable> {\n kafkaConsumer: KafkaConsumer\n}\n\n/**\n * Abstract base class for Kafka stream readers\n * @extends Readable\n */\nexport abstract class BaseKafkaStreamReadable extends Readable {\n private _kafkaConsumer: KafkaConsumer\n\n /**\n * Creates a BaseKafkaStreamReadable instance\n */\n constructor(\n streamOptions: KafkaStreamReadableOptions,\n ) {\n const { kafkaConsumer, ...opts } = streamOptions\n\n super(opts)\n\n if (!kafkaConsumer) {\n throw new Error('A valid KafkaConsumer instance is required.')\n }\n\n this._kafkaConsumer = kafkaConsumer\n }\n\n get kafkaConsumer(): KafkaConsumer {\n return this._kafkaConsumer\n }\n\n /**\n * Checks if the stream is currently paused\n * @returns {boolean} True if the stream is paused\n */\n isPaused(): boolean {\n return this.readableFlowing === false\n }\n\n /**\n * Subscribes to topics\n */\n async subscribe(topics: string | Array<TopicPartitionConfig>) {\n if (!topics || (Array.isArray(topics) && topics.length === 0)) {\n throw new Error('Topics must be a non-empty string or array.')\n }\n await this.kafkaConsumer.subscribe(topics)\n }\n\n seek(topic: string, partition: number, offsetModel: OffsetModel, timeout?: number) {\n this.kafkaConsumer.seek(topic, partition, offsetModel, timeout)\n }\n\n async commit(topic: string, partition: number, offset: number, commitMode: CommitMode) {\n return this.kafkaConsumer.commit(topic, partition, offset, commitMode)\n }\n\n /**\n * Commits the offset for a message.\n * This is a convenience method that automatically increments the offset by 1.\n * The offset committed is `message.offset + 1` since Kafka expects the next offset to be consumed.\n * @param message - The message to commit\n * @param commitMode - The commit mode ('Sync' or 'Async')\n */\n async commitMessage(message: Message, commitMode: CommitMode) {\n return this.kafkaConsumer.commitMessage(message, commitMode)\n }\n\n /**\n * Unsubscribe from topics\n */\n unsubscribe() {\n this.kafkaConsumer.unsubscribe()\n }\n\n /**\n * Disconnects the Kafka consumer\n */\n async disconnect() {\n await this.kafkaConsumer.disconnect()\n }\n\n /**\n * Returns the raw Kafka consumer\n * @returns {KafkaConsumer} The Kafka consumer instance\n */\n rawConsumer() {\n return this.kafkaConsumer\n }\n\n /**\n * Called when the stream is being destroyed\n * Ensures proper cleanup of the Kafka consumer\n * @private\n */\n _destroy(error: Error | null, callback: (error?: Error | null) => void): void {\n // Signal end-of-stream to ensure 'end' listeners fire even when destroyed early\n try {\n this.push(null)\n } catch {\n // ignore if already ended\n }\n try {\n this.emit('end')\n } catch {\n // ignore if already emitted\n }\n // Always unsubscribe first to stop receiving messages\n try {\n this.kafkaConsumer.unsubscribe()\n } catch {\n // Silently ignore unsubscribe errors during cleanup - they're non-critical\n // Common when consumer is already disconnected or in invalid state\n }\n\n // Disconnect the consumer\n this.kafkaConsumer\n .disconnect()\n .then(() => {\n // Success: pass through the original error (if any)\n callback(error)\n })\n // eslint-disable-next-line unicorn/catch-error-name\n .catch((disconnectError) => {\n // Failed to disconnect: combine errors\n const combinedError = error\n ? new Error(`Stream error: ${error.message}; Disconnect error: ${disconnectError.message}`)\n : disconnectError\n callback(combinedError)\n })\n }\n\n /**\n * Called when the stream is finishing (no more data will be written)\n * Ensures proper cleanup when stream ends normally\n * @private\n */\n _final(callback: (error?: Error | null) => void): void {\n // For readable streams, _final is called when we push(null)\n // Ensure consumer is properly cleaned up\n this.kafkaConsumer\n .disconnect()\n .then(() => callback())\n .catch((error) => callback(error))\n }\n\n /**\n * Abstract method that must be implemented by concrete classes\n * @private\n */\n abstract _read(): void\n}\n", "import type { Message } from '../../js-binding.js'\nimport { BaseKafkaStreamReadable, type KafkaStreamReadableOptions } from './base-kafka-stream-readable.js'\n\n// Constants for batch configuration\nconst DEFAULT_BATCH_TIMEOUT = 1000\n\nexport interface KafkaBatchStreamReadableOptions extends KafkaStreamReadableOptions {\n batchSize: number\n batchTimeout?: number\n}\n\n/**\n * KafkaBatchStreamReadable class for batch message processing\n * @extends BaseKafkaStreamReadable\n */\nexport class KafkaBatchStreamReadable extends BaseKafkaStreamReadable {\n private pendingMessages: Message[] = []\n private readonly batchSize: number\n private readonly batchTimeout: number\n\n /**\n * Creates a KafkaBatchStreamReadable instance\n */\n constructor(\n streamOptions: KafkaBatchStreamReadableOptions,\n ) {\n const { batchSize, batchTimeout = DEFAULT_BATCH_TIMEOUT, ...opts } = streamOptions\n\n // Set highWaterMark to batch size for optimal performance\n opts.highWaterMark = Math.max(batchSize, opts.highWaterMark || 16)\n\n super({ ...streamOptions, ...opts })\n this.batchSize = batchSize\n this.batchTimeout = batchTimeout\n }\n\n /**\n * Gets current batch configuration\n * @returns {object} Current batch settings\n */\n getBatchConfig(): { batchSize: number; batchTimeout: number } {\n return {\n batchSize: this.batchSize,\n batchTimeout: this.batchTimeout,\n }\n }\n\n /**\n * Internal method called by the Readable stream to fetch batch messages\n * @private\n */\n async _read() {\n if (this.destroyed) {\n return\n }\n try {\n // First, push any pending messages\n while (this.pendingMessages.length > 0) {\n const message = this.pendingMessages.shift()\n if (!this.push(message)) {\n return // Backpressure, wait for next _read()\n }\n }\n\n // Fetch new batch if no pending messages\n const messages = await this.kafkaConsumer.recvBatch(this.batchSize, this.batchTimeout)\n\n if (messages.length === 0) {\n // No data this poll; schedule another read instead of ending the stream\n if (!this.destroyed) {\n setImmediate(() => this._read())\n }\n return\n }\n\n // Try to push messages, buffer remainder\n for (let idx = 0; idx < messages.length; idx++) {\n if (!this.push(messages[idx])) {\n // Buffer remaining messages\n this.pendingMessages = messages.slice(idx + 1)\n break\n }\n }\n } catch (error) {\n // Use destroy() instead of emit('error') to properly terminate the stream\n this.destroy(error instanceof Error ? error : new Error(String(error)))\n }\n }\n}\n", "import { BaseKafkaStreamReadable } from './base-kafka-stream-readable.js'\n\n/**\n * KafkaStreamReadable class for single message processing\n * @extends BaseKafkaStreamReadable\n */\nexport class KafkaStreamReadable extends BaseKafkaStreamReadable {\n /**\n * Internal method called by the Readable stream to fetch single messages\n * @private\n */\n async _read() {\n try {\n const message = await this.kafkaConsumer.recv()\n if (message) {\n this.push(message)\n } else {\n this.push(null) // No more data, end of stream\n }\n } catch (error) {\n if (error instanceof Error) {\n this.destroy(error)\n } else {\n this.destroy(new Error(`Unknown error: ${String(error)}`))\n }\n }\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["export type {\n ConsumerConfiguration,\n KafkaConfiguration,\n KafkaCrabError,\n KafkaEvent,\n KafkaEventPayload,\n Message,\n MessageProducer,\n OffsetModel,\n PartitionOffset,\n ProducerConfiguration,\n ProducerRecord,\n RecordMetadata,\n TopicPartition,\n TopicPartitionConfig,\n} from '../js-binding.js'\n\nexport {\n CommitMode,\n KafkaClientConfig,\n KafkaConsumer,\n KafkaEventName,\n KafkaProducer,\n PartitionPosition,\n SecurityProtocol,\n} from '../js-binding.js'\nexport { KafkaClient } from './kafka-client.js'\nexport { BaseKafkaStreamReadable } from './streams/base-kafka-stream-readable.js'\nexport { KafkaBatchStreamReadable } from './streams/kafka-batch-stream-readable.js'\nexport { KafkaStreamReadable } from './streams/kafka-stream-readable.js'\n\nexport type { KafkaClientConfiguration, StreamConsumerConfiguration } from './kafka-client.js'\n\n// OpenTelemetry exports\nexport type {\n BatchOtelContext,\n InstrumentedMessage,\n InstrumentedProducerRecord,\n KafkaOtelContext,\n KafkaOtelInstrumentationConfig,\n MessageHookFn,\n ProducerHookFn,\n TopicFilterFn,\n} from './otel/types.js'\n\nexport { getKafkaInstrumentation, KafkaCrabInstrumentation, resetKafkaInstrumentation } from './otel/instrumentation.js'\n\nexport { KAFKA_OPERATION_TYPES, KAFKA_SEMANTIC_CONVENTIONS, PACKAGE_INFO } from './otel/constants.js'\n", "import { context, type Span } from '@opentelemetry/api'\nimport type { ReadableOptions } from 'node:stream'\nimport {\n type ConsumerConfiguration,\n KafkaClientConfig,\n type KafkaConfiguration,\n type KafkaConsumer,\n type KafkaProducer,\n type ProducerConfiguration,\n} from '../js-binding.js'\n\nimport { getKafkaInstrumentation } from './otel/instrumentation.js'\nimport type { KafkaOtelContext, KafkaOtelInstrumentationConfig } from './otel/types.js'\nimport { KafkaBatchStreamReadable } from './streams/kafka-batch-stream-readable.js'\nimport { KafkaStreamReadable } from './streams/kafka-stream-readable.js'\n\nexport interface StreamConsumerConfiguration extends ConsumerConfiguration {\n batchSize?: number // Default 1 (single mode), > 1 enables batch mode\n batchTimeout?: number // Default 100ms, only used when batchSize > 1\n streamOptions?: ReadableOptions\n}\n\nexport interface KafkaClientConfiguration extends KafkaConfiguration {\n otel?: KafkaOtelInstrumentationConfig | false // OTEL configuration or false to disable\n}\n\n/**\n * KafkaClient class\n */\nexport class KafkaClient {\n private readonly kafkaClientConfig: KafkaClientConfig\n private readonly _otelEnabled: boolean\n private readonly _otelContext: KafkaOtelContext\n\n /**\n * Creates a KafkaClient instance\n * @throws {Error} If the configuration is invalid\n */\n constructor(private readonly kafkaConfiguration: KafkaClientConfiguration) {\n // Extract OTEL configuration\n const { otel, ...kafkaConfig } = kafkaConfiguration\n this.kafkaClientConfig = new KafkaClientConfig(kafkaConfig)\n\n // Initialize OTEL instrumentation\n this._otelEnabled = otel !== false && otel !== null\n if (this._otelEnabled && typeof otel === 'object') {\n const instrumentation = getKafkaInstrumentation(otel)\n this._otelContext = instrumentation.createOtelContext()\n } else if (this._otelEnabled) {\n const instrumentation = getKafkaInstrumentation()\n this._otelContext = instrumentation.createOtelContext()\n } else {\n this._otelContext = this._createDisabledOtelContext()\n }\n }\n\n /**\n * Get the OpenTelemetry context for this client\n * @returns {KafkaOtelContext} The OTEL context\n */\n get otel(): KafkaOtelContext {\n return this._otelContext\n }\n\n /**\n * Creates a KafkaProducer instance\n * @param {ProducerConfiguration} [producerConfiguration] - Optional producer configuration\n * @returns {KafkaProducer} A KafkaProducer instance\n */\n createProducer(producerConfiguration?: ProducerConfiguration) {\n const producer = producerConfiguration\n ? this.kafkaClientConfig.createProducer(producerConfiguration)\n : this.kafkaClientConfig.createProducer({})\n\n // Instrument producer if OTEL is enabled\n if (this._otelEnabled && this._otelContext.enabled) {\n return this._instrumentProducer(producer)\n }\n\n return producer\n }\n\n /**\n * Creates a KafkaConsumer instance\n * @param {ConsumerConfiguration} consumerConfiguration - Consumer configuration\n * @returns {KafkaConsumer} A KafkaConsumer instance\n * @throws {Error} If the configuration is invalid\n */\n createConsumer(consumerConfiguration: ConsumerConfiguration) {\n const consumer = this.kafkaClientConfig.createConsumer(consumerConfiguration)\n\n // Instrument consumer if OTEL is enabled\n if (this._otelEnabled && this._otelContext.enabled) {\n return KafkaClient._instrumentConsumer(consumer, consumerConfiguration.groupId)\n }\n\n return consumer\n }\n\n /**\n * Creates a stream consumer instance\n * @param {StreamConsumerConfiguration} streamConfiguration - Stream consumer configuration including batch mode and stream options\n * @returns {KafkaStreamReadable | KafkaBatchStreamReadable} A stream consumer instance\n * @throws {Error} If the configuration is invalid\n */\n createStreamConsumer(\n streamConfiguration: StreamConsumerConfiguration,\n ): KafkaStreamReadable | KafkaBatchStreamReadable {\n const { batchSize, batchTimeout, streamOptions, ...consumerConfiguration } = streamConfiguration\n const kafkaConsumer = this.kafkaClientConfig.createConsumer(consumerConfiguration)\n const instrumentedConsumer = this._otelEnabled && this._otelContext.enabled\n ? KafkaClient._instrumentConsumer(kafkaConsumer, consumerConfiguration.groupId)\n : kafkaConsumer\n const opts = streamOptions ?? { objectMode: true }\n\n // Return appropriate class based on batch configuration\n if (batchSize && batchSize > 1) {\n return new KafkaBatchStreamReadable({ kafkaConsumer: instrumentedConsumer, batchSize, batchTimeout, ...opts })\n }\n\n return new KafkaStreamReadable({ kafkaConsumer: instrumentedConsumer, ...opts })\n }\n\n private _instrumentProducer(producer: KafkaProducer) {\n const instrumentation = getKafkaInstrumentation()\n const originalSend = producer.send.bind(producer)\n\n producer.send = instrumentation.instrumentProducerSend(\n originalSend,\n this.kafkaConfiguration.clientId,\n )\n\n return producer\n }\n\n private static _instrumentConsumer(consumer: KafkaConsumer, groupId?: string) {\n const instrumentation = getKafkaInstrumentation()\n const originalRecv = consumer.recv.bind(consumer)\n const originalRecvBatch = consumer.recvBatch.bind(consumer)\n\n consumer.recv = instrumentation.instrumentConsumerReceive(originalRecv, groupId)\n consumer.recvBatch = instrumentation.instrumentBatchReceive(originalRecvBatch, groupId)\n\n return consumer\n }\n\n // eslint-disable-next-line class-methods-use-this\n private _createDisabledOtelContext(): KafkaOtelContext {\n // Provide safe no-op implementations so callers can still invoke methods without guarding\n return {\n enabled: false,\n span: null,\n tracer: null,\n context: context.active(),\n inject: () => {\n /* no-op */\n },\n extract: () => context.active(),\n startSpan: () => null,\n endSpan: (span?: Span | null) => {\n if (span && typeof span.end === 'function') {\n span.end()\n }\n },\n }\n }\n}\n", "import { type Attributes, context, diag, type Span, trace, type Tracer } from '@opentelemetry/api'\n\nimport type { KafkaConsumer, KafkaProducer, Message, ProducerRecord, RecordMetadata } from '../../js-binding.js'\nimport { PACKAGE_INFO } from './constants.js'\nimport {\n DEFAULT_OTEL_CONFIG,\n type KafkaOtelContext,\n type KafkaOtelInstrumentationConfig,\n type TracerProvider,\n} from './types.js'\nimport {\n createBatchSpan,\n createConsumerSpan,\n createProducerSpan,\n extractTraceContext,\n getTracer,\n injectTraceContext,\n normalizeHeadersToBuffer,\n setSpanStatus,\n shouldIgnoreTopic,\n} from './utils.js'\n\nexport class KafkaCrabInstrumentation {\n private _kafkaTracer: Tracer | null = null\n private _kafkaConfig: KafkaOtelInstrumentationConfig\n private _enabled = false\n\n constructor(config: KafkaOtelInstrumentationConfig = {}) {\n this._kafkaConfig = { ...DEFAULT_OTEL_CONFIG, ...config }\n }\n\n public get kafkaConfig(): KafkaOtelInstrumentationConfig {\n return this._kafkaConfig\n }\n\n public get kafkaTracer(): Tracer | null {\n return this._kafkaTracer\n }\n\n public updateConfig(config: KafkaOtelInstrumentationConfig): void {\n this._kafkaConfig = { ...this._kafkaConfig, ...config }\n }\n\n public setTracerProvider(provider: TracerProvider): void {\n this._kafkaTracer = provider.getTracer(PACKAGE_INFO.NAME, PACKAGE_INFO.VERSION)\n }\n\n public enable(): void {\n this._kafkaTracer = getTracer(PACKAGE_INFO.NAME, PACKAGE_INFO.VERSION)\n this._enabled = true\n\n if (this._kafkaConfig?.registerOnInitialization && this._kafkaTracer) {\n diag.debug('Kafka OTEL instrumentation enabled')\n }\n }\n\n public disable(): void {\n this._kafkaTracer = null\n this._enabled = false\n diag.debug('Kafka OTEL instrumentation disabled')\n }\n\n public isEnabled(): boolean {\n return this._enabled && this._kafkaTracer !== null\n }\n\n public createOtelContext(): KafkaOtelContext {\n if (!this.isEnabled()) {\n return this._createDisabledContext()\n }\n\n return {\n enabled: true,\n span: trace.getActiveSpan() || null,\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n tracer: this._kafkaTracer!,\n context: context.active(),\n inject: (carrier, spanToInject?: Span) => {\n if (spanToInject) {\n const spanContext = trace.setSpan(context.active(), spanToInject)\n injectTraceContext(carrier, spanContext)\n return\n }\n\n const activeSpan = trace.getActiveSpan()\n if (activeSpan) {\n const spanContext = trace.setSpan(context.active(), activeSpan)\n injectTraceContext(carrier, spanContext)\n } else {\n injectTraceContext(carrier, context.active())\n }\n },\n extract: (carrier) => extractTraceContext(carrier),\n startSpan: (name, attributes: Attributes = {}) => {\n if (!this._kafkaTracer) {\n throw new Error('Tracer not available')\n }\n const span = this._kafkaTracer.startSpan(name, { attributes })\n return span\n },\n endSpan: (span, error) => {\n if (!span) {\n return\n }\n setSpanStatus(span, error)\n span.end()\n },\n }\n }\n\n public instrumentProducerSend(\n originalSend: Function,\n clientId?: string,\n ): (producerRecord: ProducerRecord) => Promise<RecordMetadata[]> {\n if (!this.isEnabled()) {\n return originalSend as (producerRecord: ProducerRecord) => Promise<RecordMetadata[]>\n }\n\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const instrumentation = this\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const tracer = this._kafkaTracer!\n\n return async function instrumentedSend(this: KafkaProducer, record: ProducerRecord | ProducerRecord[]) {\n if (!record) {\n return originalSend.call(this, record as ProducerRecord)\n }\n\n const callerContext = context.active()\n\n const isArrayInput = Array.isArray(record)\n const records = isArrayInput ? record : [record]\n\n if (records.length === 0) {\n return originalSend.call(this, isArrayInput ? records : (record as ProducerRecord))\n }\n\n const allIgnored = records.every((currentRecord) =>\n shouldIgnoreTopic(currentRecord.topic, instrumentation._kafkaConfig.ignoreTopics)\n )\n\n if (allIgnored) {\n return originalSend.call(this, isArrayInput ? records : records[0])\n }\n\n const spans: Span[] = []\n const spanMetadata: { span: Span; record: ProducerRecord }[] = []\n\n const instrumentedRecords = records.map((currentRecord) => {\n if (!currentRecord || shouldIgnoreTopic(currentRecord.topic, instrumentation._kafkaConfig.ignoreTopics)) {\n return currentRecord\n }\n\n const span = createProducerSpan(tracer, currentRecord, 'send', callerContext)\n\n if (!span) {\n return currentRecord\n }\n\n if (clientId) {\n span.setAttributes({ 'messaging.client.id': clientId })\n }\n\n spans.push(span)\n spanMetadata.push({ span, record: currentRecord })\n\n const spanContext = trace.setSpan(callerContext, span)\n\n const instrumentedRecord: ProducerRecord = {\n ...currentRecord,\n messages: (currentRecord.messages ?? []).map(message => {\n const originalHeaders = { ...message.headers }\n const injectedHeaders = injectTraceContext(originalHeaders, spanContext)\n const normalizedHeaders = normalizeHeadersToBuffer(injectedHeaders)\n\n return {\n ...message,\n headers: normalizedHeaders,\n }\n }),\n }\n\n if (instrumentation._kafkaConfig.producerHook) {\n try {\n context.with(spanContext, () => {\n instrumentation._kafkaConfig.producerHook?.(span, currentRecord)\n })\n } catch (error) {\n diag.warn('Producer hook failed:', error)\n }\n }\n\n return instrumentedRecord\n })\n\n const payload = isArrayInput ? instrumentedRecords : instrumentedRecords[0]\n\n try {\n const result = await context.with(callerContext, async () => originalSend.call(this, payload as ProducerRecord))\n\n const metadataArray = Array.isArray(result) ? result : []\n for (let idx = 0; idx < spanMetadata.length; idx++) {\n const { span } = spanMetadata[idx]\n const metadata = metadataArray[idx]\n if (metadata) {\n if (metadata.partition !== undefined) {\n span.setAttribute('messaging.kafka.partition', metadata.partition)\n }\n if (metadata.offset !== undefined) {\n span.setAttribute('messaging.kafka.offset', metadata.offset)\n }\n }\n setSpanStatus(span, metadata?.error ? new Error(metadata.error.message) : undefined)\n span.end()\n }\n\n if (instrumentation._kafkaConfig.producerHook && metadataArray.length) {\n const [first] = spanMetadata\n if (first) {\n try {\n instrumentation._kafkaConfig.producerHook(first.span, first.record, metadataArray[0])\n } catch (error) {\n diag.warn('Producer hook failed with metadata:', error)\n }\n }\n }\n\n return result\n } catch (error) {\n for (const span of spans) {\n setSpanStatus(span, error instanceof Error ? error : new Error(String(error)))\n span.end()\n }\n throw error\n }\n }\n }\n\n public instrumentConsumerReceive(originalReceive: Function, groupId?: string): () => Promise<Message | null> {\n if (!this.isEnabled()) {\n return originalReceive as () => Promise<Message | null>\n }\n\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const instrumentation = this\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const tracer = this._kafkaTracer!\n\n return async function instrumentedReceive(this: KafkaConsumer) {\n const message = await originalReceive.call(this)\n\n if (!message) {\n return message\n }\n\n if (shouldIgnoreTopic(message.topic, instrumentation._kafkaConfig.ignoreTopics)) {\n return message\n }\n\n const parentContext = extractTraceContext(message.headers || {}) || context.active()\n const span = createConsumerSpan(tracer, message, 'process', parentContext)\n\n if (span) {\n const spanCtx = trace.setSpan(parentContext, span)\n\n context.with(spanCtx, () => {\n if (groupId) {\n span.setAttributes({ 'messaging.consumer.group.name': groupId })\n }\n\n if (instrumentation._kafkaConfig.messageHook) {\n try {\n instrumentation._kafkaConfig.messageHook(span, message)\n } catch (error) {\n diag.warn('Message hook failed:', error)\n }\n }\n\n setSpanStatus(span)\n })\n\n span.end()\n }\n\n return message\n }\n }\n\n public instrumentBatchReceive(\n originalBatchReceive: Function,\n groupId?: string,\n ): (size: number, timeoutMs: number) => Promise<Message[]> {\n if (!this.isEnabled() || !this._kafkaConfig.enableBatchInstrumentation) {\n return originalBatchReceive as (size: number, timeoutMs: number) => Promise<Message[]>\n }\n\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const instrumentation = this\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const tracer = this._kafkaTracer!\n\n return async function instrumentedBatchReceive(this: KafkaConsumer, size: number, timeoutMs: number) {\n const messages = await originalBatchReceive.call(this, size, timeoutMs)\n\n if (!Array.isArray(messages) || messages.length === 0) {\n return messages\n }\n\n const instrumentedMessages = messages.filter((message: Message) =>\n !shouldIgnoreTopic(message.topic, instrumentation._kafkaConfig.ignoreTopics)\n )\n\n if (instrumentedMessages.length === 0) {\n return messages\n }\n\n const [firstMessage] = instrumentedMessages\n const parentContext = extractTraceContext(firstMessage.headers || {}) || context.active()\n const batchSpan = createBatchSpan(\n tracer,\n instrumentedMessages.length,\n firstMessage.topic,\n 'batch_process',\n parentContext,\n )\n\n if (batchSpan) {\n if (groupId) {\n batchSpan.setAttributes({ 'messaging.consumer.group.name': groupId })\n }\n\n try {\n for (const message of instrumentedMessages) {\n const msgParentContext = extractTraceContext(message.headers || {}) || parentContext\n const messageSpan = createConsumerSpan(tracer, message, 'process', msgParentContext)\n\n if (messageSpan) {\n const messageSpanContext = trace.setSpan(msgParentContext || context.active(), messageSpan)\n context.with(messageSpanContext, () => {\n messageSpan.setAttributes({\n 'messaging.batch.message_count': instrumentedMessages.length,\n })\n\n if (instrumentation._kafkaConfig.messageHook) {\n try {\n instrumentation._kafkaConfig.messageHook(messageSpan, message)\n } catch (error) {\n diag.warn('Message hook failed:', error)\n }\n }\n\n setSpanStatus(messageSpan)\n })\n messageSpan.end()\n }\n }\n\n setSpanStatus(batchSpan)\n } catch (error) {\n setSpanStatus(batchSpan, error instanceof Error ? error : new Error(String(error)))\n } finally {\n batchSpan.end()\n }\n }\n\n return messages\n }\n }\n\n // eslint-disable-next-line class-methods-use-this\n private _createDisabledContext(): KafkaOtelContext {\n return {\n enabled: false,\n span: null,\n tracer: null,\n context: context.active(),\n inject: () => {\n /* no-op */\n },\n extract: () => context.active(),\n startSpan: () => null,\n endSpan: () => {\n /* no-op */\n },\n }\n }\n}\n\n// Singleton instance for global use\nlet globalInstrumentation: KafkaCrabInstrumentation | null = null\n\nexport function getKafkaInstrumentation(config?: KafkaOtelInstrumentationConfig): KafkaCrabInstrumentation {\n if (!globalInstrumentation) {\n globalInstrumentation = new KafkaCrabInstrumentation(config)\n globalInstrumentation.enable()\n } else if (config) {\n globalInstrumentation.updateConfig(config)\n }\n return globalInstrumentation\n}\n\nexport function resetKafkaInstrumentation(): void {\n if (globalInstrumentation) {\n globalInstrumentation.disable()\n globalInstrumentation = null\n }\n}\n", "// OpenTelemetry semantic conventions for Kafka messaging\nexport const KAFKA_SEMANTIC_CONVENTIONS = {\n // Messaging system attributes (https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/)\n MESSAGING_SYSTEM: 'messaging.system',\n MESSAGING_DESTINATION_NAME: 'messaging.destination.name',\n MESSAGING_DESTINATION_KIND: 'messaging.destination.kind',\n MESSAGING_OPERATION_NAME: 'messaging.operation.name',\n MESSAGING_OPERATION_TYPE: 'messaging.operation.type',\n MESSAGING_CLIENT_ID: 'messaging.client.id',\n MESSAGING_MESSAGE_ID: 'messaging.message.id',\n MESSAGING_MESSAGE_BODY_SIZE: 'messaging.message.body.size',\n MESSAGING_BATCH_MESSAGE_COUNT: 'messaging.batch.message_count',\n\n // Kafka-specific attributes\n MESSAGING_KAFKA_OFFSET: 'messaging.kafka.offset',\n MESSAGING_KAFKA_PARTITION: 'messaging.kafka.partition',\n MESSAGING_KAFKA_MESSAGE_KEY: 'messaging.kafka.message.key',\n MESSAGING_KAFKA_CONSUMER_GROUP: 'messaging.kafka.consumer.group',\n MESSAGING_KAFKA_TOMBSTONE: 'messaging.kafka.tombstone',\n\n // Consumer-specific attributes\n MESSAGING_CONSUMER_GROUP_NAME: 'messaging.consumer.group.name',\n} as const\n\n// Operation types\nexport const KAFKA_OPERATION_TYPES = {\n SEND: 'send',\n RECEIVE: 'receive',\n PROCESS: 'process',\n BATCH_RECEIVE: 'batch_receive',\n BATCH_PROCESS: 'batch_process',\n} as const\n\n// Span names\nexport const KAFKA_SPAN_NAMES = {\n PRODUCER_SEND: (topic: string) => `${topic} send`,\n CONSUMER_RECEIVE: (topic: string) => `${topic} receive`,\n CONSUMER_PROCESS: (topic: string) => `${topic} process`,\n BATCH_RECEIVE: 'kafka batch receive',\n BATCH_PROCESS: (topic: string) => `${topic} batch process`,\n} as const\n\n// Default values\nexport const KAFKA_DEFAULTS = {\n MESSAGING_SYSTEM: 'kafka',\n DESTINATION_KIND: 'topic',\n BATCH_TIMEOUT_MS: 1000,\n} as const\n\n// Package information\nexport const PACKAGE_INFO = {\n NAME: 'kafka-crab-js',\n VERSION: '2.1.0', // Should match package.json\n} as const\n", "import type { Attributes, Context, Span, Tracer } from '@opentelemetry/api'\nimport type { Message, ProducerRecord, RecordMetadata } from '../../js-binding.js'\n\n// InstrumentationConfig interface (simplified from @opentelemetry/instrumentation)\nexport interface InstrumentationConfig {\n enabled?: boolean\n}\n\n// OpenTelemetry TracerProvider interface\nexport interface TracerProvider {\n getTracer(name: string, version?: string, options?: unknown): Tracer\n}\n\n// Use the actual types from js-binding instead of custom interfaces\n// This avoids type compatibility issues with the real implementations\n\n// Configuration interface for Kafka OTEL instrumentation\nexport interface KafkaOtelInstrumentationConfig extends InstrumentationConfig {\n // Service name for telemetry (defaults to OTEL_SERVICE_NAME env var or 'kafka-client')\n serviceName?: string\n\n // Whether to register instrumentation automatically on initialization\n registerOnInitialization?: boolean\n\n // Function to filter topics from instrumentation\n ignoreTopics?: string[] | ((topic: string) => boolean)\n\n // Custom hook called for each message/span\n messageHook?: (span: Span, message: Message) => void\n\n // Custom hook called for producer operations\n producerHook?: (span: Span, record: ProducerRecord, metadata?: RecordMetadata) => void\n\n // Whether to capture message payloads as span attributes (security sensitive)\n captureMessagePayload?: boolean\n\n // Maximum size of message payload to capture (in bytes)\n maxPayloadSize?: number\n\n // Whether to capture message headers as span attributes\n captureMessageHeaders?: boolean\n\n // Whether to enable batch operation instrumentation\n enableBatchInstrumentation?: boolean\n}\n\n// OpenTelemetry context interface exposed by clients\nexport interface KafkaOtelContext {\n // Whether OTEL is enabled for this client\n enabled: boolean\n\n // Current active span (if any)\n span: Span | null\n\n // Tracer instance for creating spans\n tracer: Tracer | null\n\n // Current OTEL context\n context: Context | null\n\n // Inject trace context into carrier (e.g., Kafka headers)\n inject: (carrier: Record<string, string | string[] | undefined>) => void\n\n // Extract trace context from carrier (e.g., Kafka headers)\n extract: (carrier: Record<string, string | string[] | undefined>) => Context\n\n // Create a child span with proper context\n startSpan: (name: string, attributes?: Attributes) => Span | null\n\n // End a span with proper status handling\n endSpan: (span: Span | null | undefined, error?: Error) => void\n}\n\n// Enhanced message interface with OTEL context\nexport interface InstrumentedMessage extends Message {\n // Extracted OTEL context from message headers\n otelContext?: Context\n\n // Optional span created for this message\n span?: Span\n}\n\n// Enhanced producer record with OTEL context injection\nexport interface InstrumentedProducerRecord extends ProducerRecord {\n // Headers will be automatically injected with trace context\n headers?: Record<string, string | string[] | undefined>\n\n // Optional span for tracking this record\n span?: Span\n}\n\n// Batch processing context\nexport interface BatchOtelContext {\n // Parent span for the entire batch\n batchSpan: Span\n\n // Individual message spans within the batch\n messageSpans: Span[]\n\n // Batch size for telemetry\n batchSize: number\n\n // Processing start time\n startTime: number\n}\n\n// Hook function signatures\nexport type MessageHookFn = (span: Span, message: Message) => void\nexport type ProducerHookFn = (span: Span, record: ProducerRecord, metadata?: RecordMetadata) => void\nexport type TopicFilterFn = (topic: string) => boolean\n\n// Configuration defaults\nexport const DEFAULT_OTEL_CONFIG: Required<\n Pick<\n KafkaOtelInstrumentationConfig,\n | 'serviceName'\n | 'registerOnInitialization'\n | 'captureMessagePayload'\n | 'maxPayloadSize'\n | 'captureMessageHeaders'\n | 'enableBatchInstrumentation'\n >\n> = {\n serviceName: process.env.OTEL_SERVICE_NAME || 'kafka-client',\n registerOnInitialization: true,\n captureMessagePayload: false,\n maxPayloadSize: 1024,\n captureMessageHeaders: true,\n enableBatchInstrumentation: true,\n} as const\n", "import {\n type Attributes,\n type Context,\n context,\n propagation,\n type Span,\n SpanKind,\n SpanStatusCode,\n trace,\n type Tracer,\n} from '@opentelemetry/api'\nimport type { Message, ProducerRecord } from '../../js-binding.js'\nimport { KAFKA_DEFAULTS, KAFKA_SEMANTIC_CONVENTIONS } from './constants.js'\n\n// Safely get tracer\nexport function getTracer(name: string, version?: string) {\n return trace.getTracer(name, version)\n}\n\n// Set span status based on error\nexport function setSpanStatus(span: Span, error?: Error): void {\n if (error) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message,\n })\n span.recordException(error)\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n}\n\n// Extract common Kafka attributes from message\nexport function getMessageAttributes(message: Message, operation: string): Attributes {\n const attributes: Attributes = {\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_SYSTEM]: KAFKA_DEFAULTS.MESSAGING_SYSTEM,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_DESTINATION_NAME]: message.topic,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_DESTINATION_KIND]: KAFKA_DEFAULTS.DESTINATION_KIND,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_OPERATION_NAME]: operation,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_KAFKA_PARTITION]: message.partition,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_KAFKA_OFFSET]: message.offset,\n }\n\n // Add optional attributes if present\n if (message.key !== null && message.key !== undefined) {\n attributes[KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_KAFKA_MESSAGE_KEY] = typeof message.key === 'string'\n ? message.key\n : String(message.key)\n }\n\n if (message.payload) {\n let payloadSize: number\n if (Buffer.isBuffer(message.payload)) {\n payloadSize = message.payload.length\n } else if (typeof message.payload === 'string') {\n payloadSize = Buffer.byteLength(message.payload, 'utf8')\n } else {\n payloadSize = JSON.stringify(message.payload).length\n }\n attributes[KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_MESSAGE_BODY_SIZE] = payloadSize\n }\n\n return attributes\n}\n\n// Extract common Kafka attributes from producer record\nexport function getProducerRecordAttributes(record: ProducerRecord, operation: string): Attributes {\n const attributes: Attributes = {\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_SYSTEM]: KAFKA_DEFAULTS.MESSAGING_SYSTEM,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_DESTINATION_NAME]: record.topic,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_DESTINATION_KIND]: KAFKA_DEFAULTS.DESTINATION_KIND,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_OPERATION_NAME]: operation,\n }\n\n // Add message count\n if (record.messages && record.messages.length > 0) {\n attributes[KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_BATCH_MESSAGE_COUNT] = record.messages.length\n\n // Use first message for key and payload size\n const [firstMessage] = record.messages\n\n // Add key if present\n if (firstMessage.key !== null && firstMessage.key !== undefined) {\n attributes[KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_KAFKA_MESSAGE_KEY] = Buffer.isBuffer(firstMessage.key)\n ? firstMessage.key.toString()\n : String(firstMessage.key)\n }\n\n // Add payload size if present\n if (firstMessage.payload) {\n let payloadSize: number\n if (Buffer.isBuffer(firstMessage.payload)) {\n payloadSize = firstMessage.payload.length\n } else if (typeof firstMessage.payload === 'string') {\n payloadSize = Buffer.byteLength(firstMessage.payload, 'utf8')\n } else {\n payloadSize = JSON.stringify(firstMessage.payload).length\n }\n attributes[KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_MESSAGE_BODY_SIZE] = payloadSize\n }\n }\n\n return attributes\n}\n\n// Convert Buffer headers to string headers for trace context injection\nfunction convertBufferHeaders(\n bufferHeaders: Record<string, Buffer> = {},\n): Record<string, string | string[] | undefined> {\n const stringHeaders: Record<string, string | string[] | undefined> = {}\n for (const [key, value] of Object.entries(bufferHeaders)) {\n stringHeaders[key] = value.toString('utf8')\n }\n return stringHeaders\n}\n\n// Convert string headers back to Buffer headers\nfunction convertToBufferHeaders(stringHeaders: Record<string, string | string[] | undefined>): Record<string, Buffer> {\n const bufferHeaders: Record<string, Buffer> = {}\n for (const [key, value] of Object.entries(stringHeaders)) {\n if (value !== undefined) {\n const stringValue = Array.isArray(value) ? value.join(',') : value\n bufferHeaders[key] = Buffer.from(stringValue, 'utf8')\n }\n }\n return bufferHeaders\n}\n\nexport type KafkaHeaderValue = Buffer | string | string[] | undefined\nexport type KafkaHeaderCarrier = Record<string, KafkaHeaderValue>\n\n// Inject trace context into Kafka headers (works with both string and Buffer headers)\nexport function injectTraceContext(\n headers: KafkaHeaderCarrier = {},\n ctx?: Context,\n): KafkaHeaderCarrier {\n const activeContext = ctx || context.active()\n const headerEntries = Object.entries(headers)\n const hasBufferValues = headerEntries.some(([, value]) => Buffer.isBuffer(value))\n\n // Convert Buffer headers to string headers if needed\n if (hasBufferValues) {\n const bufferCarrier = headers as Record<string, Buffer>\n const stringHeaders = convertBufferHeaders(bufferCarrier)\n\n propagation.inject(activeContext, stringHeaders, {\n set: (carrier: Record<string, string | string[] | undefined>, key: string, value: string) => {\n carrier[key] = value\n },\n })\n\n const bufferHeaders = convertToBufferHeaders(stringHeaders)\n\n for (const [key, value] of Object.entries(bufferHeaders)) {\n bufferCarrier[key] = value\n }\n\n return bufferCarrier\n }\n\n const stringCarrier = headers as Record<string, string | string[] | undefined>\n\n propagation.inject(activeContext, stringCarrier, {\n set: (carrier: Record<string, string | string[] | undefined>, key: string, value: string) => {\n carrier[key] = value\n },\n })\n\n // Preserve original string-based carrier for callers expecting strings\n return stringCarrier\n}\n\n// Normalize any header carrier into Buffer headers for Kafka bindings\nexport function normalizeHeadersToBuffer(headers: KafkaHeaderCarrier): Record<string, Buffer> {\n const bufferHeaders: Record<string, Buffer> = {}\n\n for (const [key, value] of Object.entries(headers)) {\n if (value !== undefined) {\n if (Buffer.isBuffer(value)) {\n bufferHeaders[key] = value\n } else if (Array.isArray(value)) {\n bufferHeaders[key] = Buffer.from(value.join(','), 'utf8')\n } else {\n bufferHeaders[key] = Buffer.from(value, 'utf8')\n }\n }\n }\n\n return bufferHeaders\n}\n\n// Extract trace context from Kafka headers\nexport function extractTraceContext(\n headers: Record<string, string | string[] | undefined> = {},\n): Context {\n return propagation.extract(context.active(), headers, {\n get: (carrier: Record<string, string | string[] | undefined>, key: string) => {\n const value = carrier[key]\n const singleValue = Array.isArray(value) ? value[0] : value\n\n if (Buffer.isBuffer(singleValue)) {\n return singleValue.toString('utf8')\n }\n\n return singleValue\n },\n keys: (carrier: Record<string, string | string[] | undefined>) => Object.keys(carrier),\n })\n}\n\n// Check if topic should be ignored based on filter configuration\nexport function shouldIgnoreTopic(\n topic: string,\n ignoreTopics?: string[] | ((topic: string) => boolean),\n): boolean {\n if (!ignoreTopics) {\n return false\n }\n\n if (Array.isArray(ignoreTopics)) {\n return ignoreTopics.includes(topic)\n }\n\n if (typeof ignoreTopics === 'function') {\n try {\n return ignoreTopics(topic)\n } catch {\n // If filter function throws, don't ignore the topic\n return false\n }\n }\n\n return false\n}\n\n// Create span for producer operation\nexport function createProducerSpan(\n tracer: Tracer,\n record: ProducerRecord,\n operation = 'send',\n parentContext?: Context,\n): Span | null {\n if (!tracer) {\n return null\n }\n const parent = parentContext ?? context.active()\n\n const spanName = `${record.topic} ${operation}`\n const attributes = getProducerRecordAttributes(record, operation)\n\n const spanOptions = {\n kind: SpanKind.PRODUCER,\n attributes,\n }\n\n return tracer.startSpan(spanName, spanOptions, parent)\n}\n\n// Create span for consumer operation\nexport function createConsumerSpan(\n tracer: Tracer,\n message: Message,\n operation = 'process',\n parentContext?: Context,\n): Span | null {\n if (!tracer) {\n return null\n }\n\n const spanName = `${message.topic} ${operation}`\n const attributes = getMessageAttributes(message, operation)\n\n const spanOptions = {\n kind: SpanKind.CONSUMER,\n attributes,\n }\n\n // Start span with parent context if provided\n if (parentContext) {\n return tracer.startSpan(spanName, spanOptions, parentContext)\n }\n\n return tracer.startSpan(spanName, spanOptions)\n}\n\n// Create batch span for batch operations\nexport function createBatchSpan(\n tracer: Tracer,\n batchSize: number,\n topic?: string,\n operation = 'batch_process',\n parentContext?: Context,\n): Span | null {\n if (!tracer) {\n return null\n }\n\n const spanName = topic ? `${topic} ${operation}` : `kafka ${operation}`\n const attributes: Attributes = {\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_SYSTEM]: KAFKA_DEFAULTS.MESSAGING_SYSTEM,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_OPERATION_NAME]: operation,\n [KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_BATCH_MESSAGE_COUNT]: batchSize,\n }\n\n if (topic) {\n attributes[KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_DESTINATION_NAME] = topic\n attributes[KAFKA_SEMANTIC_CONVENTIONS.MESSAGING_DESTINATION_KIND] = KAFKA_DEFAULTS.DESTINATION_KIND\n }\n\n const spanOptions = {\n kind: SpanKind.CONSUMER,\n attributes,\n }\n\n if (parentContext) {\n return tracer.startSpan(spanName, spanOptions, parentContext)\n }\n\n return tracer.startSpan(spanName, spanOptions)\n}\n", "import { Readable, type ReadableOptions } from 'node:stream'\n\nimport type { CommitMode, KafkaConsumer, Message, OffsetModel, TopicPartitionConfig } from '../../js-binding.js'\n\nexport interface KafkaStreamReadableOptions extends ReadableOptions<Readable> {\n kafkaConsumer: KafkaConsumer\n}\n\n/**\n * Abstract base class for Kafka stream readers\n * @extends Readable\n */\nexport abstract class BaseKafkaStreamReadable extends Readable {\n private _kafkaConsumer: KafkaConsumer\n\n /**\n * Creates a BaseKafkaStreamReadable instance\n */\n constructor(\n streamOptions: KafkaStreamReadableOptions,\n ) {\n const { kafkaConsumer, ...opts } = streamOptions\n\n super(opts)\n\n if (!kafkaConsumer) {\n throw new Error('A valid KafkaConsumer instance is required.')\n }\n\n this._kafkaConsumer = kafkaConsumer\n }\n\n get kafkaConsumer(): KafkaConsumer {\n return this._kafkaConsumer\n }\n\n /**\n * Checks if the stream is currently paused\n * @returns {boolean} True if the stream is paused\n */\n isPaused(): boolean {\n return this.readableFlowing === false\n }\n\n /**\n * Subscribes to topics\n */\n async subscribe(topics: string | Array<TopicPartitionConfig>) {\n if (!topics || (Array.isArray(topics) && topics.length === 0)) {\n throw new Error('Topics must be a non-empty string or array.')\n }\n await this.kafkaConsumer.subscribe(topics)\n }\n\n seek(topic: string, partition: number, offsetModel: OffsetModel, timeout?: number) {\n this.kafkaConsumer.seek(topic, partition, offsetModel, timeout)\n }\n\n async commit(topic: string, partition: number, offset: number, commitMode: CommitMode) {\n return this.kafkaConsumer.commit(topic, partition, offset, commitMode)\n }\n\n /**\n * Commits the offset for a message.\n * This is a convenience method that automatically increments the offset by 1.\n * The offset committed is `message.offset + 1` since Kafka expects the next offset to be consumed.\n * @param message - The message to commit\n * @param commitMode - The commit mode ('Sync' or 'Async')\n */\n async commitMessage(message: Message, commitMode: CommitMode) {\n return this.kafkaConsumer.commitMessage(message, commitMode)\n }\n\n /**\n * Unsubscribe from topics\n */\n unsubscribe() {\n this.kafkaConsumer.unsubscribe()\n }\n\n /**\n * Disconnects the Kafka consumer\n */\n async disconnect() {\n await this.kafkaConsumer.disconnect()\n }\n\n /**\n * Returns the raw Kafka consumer\n * @returns {KafkaConsumer} The Kafka consumer instance\n */\n rawConsumer() {\n return this.kafkaConsumer\n }\n\n /**\n * Called when the stream is being destroyed\n * Ensures proper cleanup of the Kafka consumer\n * @private\n */\n _destroy(error: Error | null, callback: (error?: Error | null) => void): void {\n // Always unsubscribe first to stop receiving messages\n try {\n this.kafkaConsumer.unsubscribe()\n } catch {\n // Silently ignore unsubscribe errors during cleanup - they're non-critical\n // Common when consumer is already disconnected or in invalid state\n }\n\n // Disconnect the consumer\n this.kafkaConsumer\n .disconnect()\n .then(() => {\n // Success: pass through the original error (if any)\n callback(error)\n })\n // eslint-disable-next-line unicorn/catch-error-name\n .catch((disconnectError) => {\n // Failed to disconnect: combine errors\n const combinedError = error\n ? new Error(`Stream error: ${error.message}; Disconnect error: ${disconnectError.message}`)\n : disconnectError\n callback(combinedError)\n })\n }\n\n /**\n * Abstract method that must be implemented by concrete classes\n * @private\n */\n abstract _read(): void\n}\n", "import type { Message } from '../../js-binding.js'\nimport { BaseKafkaStreamReadable, type KafkaStreamReadableOptions } from './base-kafka-stream-readable.js'\n\n// Constants for batch configuration\nconst DEFAULT_BATCH_TIMEOUT = 1000\n\nexport interface KafkaBatchStreamReadableOptions extends KafkaStreamReadableOptions {\n batchSize: number\n batchTimeout?: number\n}\n\n/**\n * KafkaBatchStreamReadable class for batch message processing\n * @extends BaseKafkaStreamReadable\n */\nexport class KafkaBatchStreamReadable extends BaseKafkaStreamReadable {\n private pendingMessages: Message[] = []\n private readonly batchSize: number\n private readonly batchTimeout: number\n\n /**\n * Creates a KafkaBatchStreamReadable instance\n */\n constructor(\n streamOptions: KafkaBatchStreamReadableOptions,\n ) {\n const { batchSize, batchTimeout = DEFAULT_BATCH_TIMEOUT, ...opts } = streamOptions\n\n // Set highWaterMark to batch size for optimal performance\n opts.highWaterMark = Math.max(batchSize, opts.highWaterMark || 16)\n\n super({ ...streamOptions, ...opts })\n this.batchSize = batchSize\n this.batchTimeout = batchTimeout\n }\n\n /**\n * Gets current batch configuration\n * @returns {object} Current batch settings\n */\n getBatchConfig(): { batchSize: number; batchTimeout: number } {\n return {\n batchSize: this.batchSize,\n batchTimeout: this.batchTimeout,\n }\n }\n\n /**\n * Internal method called by the Readable stream to fetch batch messages\n * @private\n */\n async _read() {\n if (this.destroyed) {\n return\n }\n try {\n // First, push any pending messages\n while (this.pendingMessages.length > 0) {\n const message = this.pendingMessages.shift()\n if (!this.push(message)) {\n return // Backpressure, wait for next _read()\n }\n }\n\n // Fetch new batch if no pending messages\n const messages = await this.kafkaConsumer.recvBatch(this.batchSize, this.batchTimeout)\n\n if (messages.length === 0) {\n // No data this poll; schedule another read instead of ending the stream\n if (!this.destroyed) {\n setImmediate(() => this._read())\n }\n return\n }\n\n // Try to push messages, buffer remainder\n for (let idx = 0; idx < messages.length; idx++) {\n if (!this.push(messages[idx])) {\n // Buffer remaining messages\n this.pendingMessages = messages.slice(idx + 1)\n break\n }\n }\n } catch (error) {\n // Use destroy() instead of emit('error') to properly terminate the stream\n this.destroy(error instanceof Error ? error : new Error(String(error)))\n }\n }\n}\n", "import { BaseKafkaStreamReadable } from './base-kafka-stream-readable.js'\n\n/**\n * KafkaStreamReadable class for single message processing\n * @extends BaseKafkaStreamReadable\n */\nexport class KafkaStreamReadable extends BaseKafkaStreamReadable {\n /**\n * Internal method called by the Readable stream to fetch single messages\n * @private\n */\n async _read() {\n try {\n const message = await this.kafkaConsumer.recv()\n if (message) {\n this.push(message)\n } else {\n this.push(null) // No more data, end of stream\n }\n } catch (error) {\n if (error instanceof Error) {\n this.destroy(error)\n } else {\n this.destroy(new Error(`Unknown error: ${String(error)}`))\n }\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["import_js_binding", "import_api", "import_api"]
|
|
7
7
|
}
|