@comprehend/telemetry-node 0.2.0 → 0.2.1

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.
@@ -2,8 +2,8 @@
2
2
  "permissions": {
3
3
  "allow": [
4
4
  "Bash(npm test:*)",
5
- "Bash(grep:*)"
5
+ "Bash(pnpm run test:*)"
6
6
  ],
7
7
  "deny": []
8
8
  }
9
- }
9
+ }
@@ -3,6 +3,7 @@
3
3
  <component name="NewModuleRootManager">
4
4
  <content url="file://$MODULE_DIR$">
5
5
  <excludeFolder url="file://$MODULE_DIR$/.tmp" />
6
+ <excludeFolder url="file://$MODULE_DIR$/dist" />
6
7
  <excludeFolder url="file://$MODULE_DIR$/temp" />
7
8
  <excludeFolder url="file://$MODULE_DIR$/tmp" />
8
9
  </content>
package/README.md CHANGED
@@ -119,6 +119,45 @@ hostMetrics.start();
119
119
 
120
120
  This collects `process.cpu.time`, `process.cpu.utilization`, and `process.memory.usage`. The `metricGroups` option limits collection to process-level metrics only, avoiding the overhead of system-wide CPU, memory, and network data gathering.
121
121
 
122
+ ### Kubernetes / container resources
123
+
124
+ When running in containers or Kubernetes, the `NodeSDK` default resource detectors (`env`, `process`, `host`) do not include container or pod attributes. To populate `container.id`, `k8s.pod.name`, `k8s.namespace.name`, and similar, add the container resource detector explicitly via `resourceDetectors`:
125
+
126
+ ```bash
127
+ npm install @opentelemetry/resource-detector-container
128
+ ```
129
+
130
+ ```typescript
131
+ import { NodeSDK } from '@opentelemetry/sdk-node';
132
+ import { envDetector, hostDetector, processDetector } from '@opentelemetry/resources';
133
+ import { containerDetector } from '@opentelemetry/resource-detector-container';
134
+
135
+ const sdk = new NodeSDK({
136
+ // ...
137
+ resourceDetectors: [envDetector, processDetector, hostDetector, containerDetector],
138
+ });
139
+ ```
140
+
141
+ Note that passing `resourceDetectors` replaces the defaults, so make sure to include the built-in detectors alongside `containerDetector`. The container detector reads `container.id` from `/proc/self/cgroup`. For other k8s attributes (pod name, namespace, node), use the Kubernetes Downward API to inject them as `OTEL_RESOURCE_ATTRIBUTES`:
142
+
143
+ ```yaml
144
+ env:
145
+ - name: OTEL_RESOURCE_ATTRIBUTES
146
+ value: k8s.pod.name=$(POD_NAME),k8s.namespace.name=$(POD_NAMESPACE),k8s.node.name=$(NODE_NAME)
147
+ - name: POD_NAME
148
+ valueFrom:
149
+ fieldRef:
150
+ fieldPath: metadata.name
151
+ - name: POD_NAMESPACE
152
+ valueFrom:
153
+ fieldRef:
154
+ fieldPath: metadata.namespace
155
+ - name: NODE_NAME
156
+ valueFrom:
157
+ fieldRef:
158
+ fieldPath: spec.nodeName
159
+ ```
160
+
122
161
  ## Configuration
123
162
 
124
163
  Set your comprehend.dev SDK token as an environment variable:
@@ -14,6 +14,7 @@ export declare class ComprehendDevSpanProcessor implements SpanProcessor {
14
14
  updateCustomMetrics(specs: CustomMetricSpecification[]): void;
15
15
  onStart(span: Span, parentContext: Context): void;
16
16
  onEnd(span: ReadableSpan): void;
17
+ private processSpan;
17
18
  private discoverService;
18
19
  private processHTTPRoute;
19
20
  private processDatabaseOperation;
@@ -25,6 +25,15 @@ class ComprehendDevSpanProcessor {
25
25
  onStart(span, parentContext) {
26
26
  }
27
27
  onEnd(span) {
28
+ const process = () => this.processSpan(span);
29
+ if (span.resource.asyncAttributesPending) {
30
+ span.resource.waitForAsyncAttributes?.().then(process);
31
+ }
32
+ else {
33
+ process();
34
+ }
35
+ }
36
+ processSpan(span) {
28
37
  const currentService = this.discoverService(span);
29
38
  if (!currentService)
30
39
  return;
@@ -23,6 +23,7 @@ function analyzeSQL(sql) {
23
23
  let skippingValues = false;
24
24
  let lookingForCommaOrEnd = false;
25
25
  let valuesDepth = 0;
26
+ let skippedWhitespace = [];
26
27
  for (let token of tokenizeSQL(sql)) {
27
28
  switch (token.type) {
28
29
  case "whitespace":
@@ -136,23 +137,31 @@ function analyzeSQL(sql) {
136
137
  switch (token.type) {
137
138
  case "comment":
138
139
  case "whitespace":
139
- // Skip whitespace/comments while looking for comma or end
140
+ // Collect whitespace/comments while looking for comma or end
141
+ skippedWhitespace.push(token);
140
142
  break;
141
143
  case "punct":
142
144
  if (token.value === ",") {
143
- // More tuples coming, continue skipping
145
+ // More tuples coming, clear skipped whitespace and continue skipping
146
+ skippedWhitespace = [];
144
147
  lookingForCommaOrEnd = false;
145
148
  skippingValues = true;
146
149
  }
147
150
  else {
148
151
  // Not a comma, so VALUES clause is done
152
+ // Add back the skipped whitespace, then the current token
153
+ presentableTokens.push(...skippedWhitespace);
149
154
  presentableTokens.push(token);
155
+ skippedWhitespace = [];
150
156
  lookingForCommaOrEnd = false;
151
157
  }
152
158
  break;
153
159
  default:
154
160
  // VALUES clause is done, resume normal processing
161
+ // Add back the skipped whitespace, then the current token
162
+ presentableTokens.push(...skippedWhitespace);
155
163
  presentableTokens.push(token);
164
+ skippedWhitespace = [];
156
165
  lookingForCommaOrEnd = false;
157
166
  break;
158
167
  }
@@ -482,4 +482,16 @@ describe('SQL Analyzer - bulk INSERT VALUES cardinality reduction', () => {
482
482
  expect(result.presentableQuery).toEqual(`INSERT INTO comments (text, author) VALUES
483
483
  (...)`);
484
484
  });
485
+ it('preserves whitespace before ON CONFLICT after VALUES clause', () => {
486
+ const sql = `INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com') ON CONFLICT (email) DO NOTHING`;
487
+ const result = (0, sql_analyzer_1.analyzeSQL)(sql);
488
+ expect(result.tableOperations).toEqual({ users: ['INSERT'] });
489
+ expect(result.presentableQuery).toEqual(`INSERT INTO users (name, email) VALUES (...) ON CONFLICT (email) DO NOTHING`);
490
+ });
491
+ it('preserves whitespace before ON CONFLICT with multiple VALUES tuples', () => {
492
+ const sql = `INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com'), ('Bob', 'bob@example.com') ON CONFLICT (email) DO UPDATE SET name = EXCLUDED.name`;
493
+ const result = (0, sql_analyzer_1.analyzeSQL)(sql);
494
+ expect(result.tableOperations).toEqual({ users: ['INSERT'] });
495
+ expect(result.presentableQuery).toEqual(`INSERT INTO users (name, email) VALUES (...) ON CONFLICT (email) DO UPDATE SET name = EXCLUDED.name`);
496
+ });
485
497
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comprehend/telemetry-node",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Integration of comprehend.dev with OpenTelemetry in Node.js and similar environemnts.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -93,6 +93,15 @@ export class ComprehendDevSpanProcessor implements SpanProcessor {
93
93
  }
94
94
 
95
95
  onEnd(span: ReadableSpan): void {
96
+ const process = () => this.processSpan(span);
97
+ if (span.resource.asyncAttributesPending) {
98
+ span.resource.waitForAsyncAttributes?.().then(process);
99
+ } else {
100
+ process();
101
+ }
102
+ }
103
+
104
+ private processSpan(span: ReadableSpan): void {
96
105
  const currentService = this.discoverService(span);
97
106
  if (!currentService)
98
107
  return;