@vfarcic/dot-ai 0.125.0 → 0.126.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/dist/core/capability-scan-workflow.d.ts +4 -9
- package/dist/core/capability-scan-workflow.d.ts.map +1 -1
- package/dist/core/capability-scan-workflow.js +203 -455
- package/dist/core/discovery.d.ts.map +1 -1
- package/dist/core/discovery.js +4 -3
- package/dist/core/embedding-service.d.ts +9 -36
- package/dist/core/embedding-service.d.ts.map +1 -1
- package/dist/core/embedding-service.js +137 -253
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +2 -2
- package/dist/core/kubernetes-utils.d.ts +1 -0
- package/dist/core/kubernetes-utils.d.ts.map +1 -1
- package/dist/core/kubernetes-utils.js +53 -48
- package/dist/core/providers/anthropic-provider.d.ts.map +1 -1
- package/dist/core/providers/anthropic-provider.js +352 -282
- package/dist/core/providers/vercel-provider.d.ts.map +1 -1
- package/dist/core/providers/vercel-provider.js +389 -351
- package/dist/core/tracing/ai-tracing.d.ts +80 -0
- package/dist/core/tracing/ai-tracing.d.ts.map +1 -0
- package/dist/core/tracing/ai-tracing.js +122 -0
- package/dist/core/tracing/config.d.ts +15 -0
- package/dist/core/tracing/config.d.ts.map +1 -0
- package/dist/core/tracing/config.js +133 -0
- package/dist/core/tracing/http-tracing.d.ts +28 -0
- package/dist/core/tracing/http-tracing.d.ts.map +1 -0
- package/dist/core/tracing/http-tracing.js +119 -0
- package/dist/core/tracing/index.d.ts +14 -0
- package/dist/core/tracing/index.d.ts.map +1 -0
- package/dist/core/tracing/index.js +40 -0
- package/dist/core/tracing/k8s-tracing.d.ts +57 -0
- package/dist/core/tracing/k8s-tracing.d.ts.map +1 -0
- package/dist/core/tracing/k8s-tracing.js +155 -0
- package/dist/core/tracing/qdrant-tracing.d.ts +68 -0
- package/dist/core/tracing/qdrant-tracing.d.ts.map +1 -0
- package/dist/core/tracing/qdrant-tracing.js +102 -0
- package/dist/core/tracing/tool-tracing.d.ts +31 -0
- package/dist/core/tracing/tool-tracing.d.ts.map +1 -0
- package/dist/core/tracing/tool-tracing.js +76 -0
- package/dist/core/tracing/tracer.d.ts +21 -0
- package/dist/core/tracing/tracer.d.ts.map +1 -0
- package/dist/core/tracing/tracer.js +215 -0
- package/dist/core/tracing/types.d.ts +86 -0
- package/dist/core/tracing/types.d.ts.map +1 -0
- package/dist/core/tracing/types.js +41 -0
- package/dist/core/vector-db-service.d.ts.map +1 -1
- package/dist/core/vector-db-service.js +238 -163
- package/dist/interfaces/mcp.d.ts.map +1 -1
- package/dist/interfaces/mcp.js +71 -43
- package/dist/mcp/server.js +12 -2
- package/dist/tools/organizational-data.d.ts.map +1 -1
- package/dist/tools/organizational-data.js +2 -4
- package/dist/tools/version.d.ts +12 -1
- package/dist/tools/version.d.ts.map +1 -1
- package/dist/tools/version.js +24 -4
- package/package.json +9 -1
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Kubernetes Client Tracing Utilities
|
|
4
|
+
*
|
|
5
|
+
* Generic tracing wrappers for Kubernetes operations:
|
|
6
|
+
* 1. Transparent proxy for @kubernetes/client-node API clients
|
|
7
|
+
* 2. Wrapper for kubectl CLI command execution
|
|
8
|
+
*
|
|
9
|
+
* Uses CLIENT span kind with k8s.* semantic conventions
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.createTracedK8sClient = createTracedK8sClient;
|
|
13
|
+
exports.withKubectlTracing = withKubectlTracing;
|
|
14
|
+
const api_1 = require("@opentelemetry/api");
|
|
15
|
+
/**
|
|
16
|
+
* Create traced Kubernetes API client using JavaScript Proxy
|
|
17
|
+
*
|
|
18
|
+
* Transparently wraps ANY Kubernetes API client method with tracing.
|
|
19
|
+
* No code changes needed in calling code - just wrap the client once.
|
|
20
|
+
*
|
|
21
|
+
* @param apiClient Original K8s API client instance
|
|
22
|
+
* @param apiType API client type (e.g., 'CoreV1Api', 'AppsV1Api')
|
|
23
|
+
* @returns Proxied client with automatic tracing for all methods
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const coreApi = createTracedK8sClient(
|
|
27
|
+
* kc.makeApiClient(k8s.CoreV1Api),
|
|
28
|
+
* 'CoreV1Api'
|
|
29
|
+
* );
|
|
30
|
+
* await coreApi.listNamespace(); // Automatically traced as "k8s.listNamespace"
|
|
31
|
+
*/
|
|
32
|
+
function createTracedK8sClient(apiClient, apiType) {
|
|
33
|
+
const tracer = api_1.trace.getTracer('dot-ai-mcp');
|
|
34
|
+
return new Proxy(apiClient, {
|
|
35
|
+
get(target, prop, receiver) {
|
|
36
|
+
const original = Reflect.get(target, prop, receiver);
|
|
37
|
+
// Only wrap functions (API methods), not properties
|
|
38
|
+
if (typeof original !== 'function') {
|
|
39
|
+
return original;
|
|
40
|
+
}
|
|
41
|
+
// Return wrapped function with tracing
|
|
42
|
+
return function (...args) {
|
|
43
|
+
const methodName = String(prop);
|
|
44
|
+
const spanName = `k8s.${methodName}`;
|
|
45
|
+
return tracer.startActiveSpan(spanName, {
|
|
46
|
+
kind: api_1.SpanKind.CLIENT,
|
|
47
|
+
attributes: {
|
|
48
|
+
'k8s.client': 'kubernetes-client-node',
|
|
49
|
+
'k8s.api': apiType,
|
|
50
|
+
'k8s.method': methodName,
|
|
51
|
+
},
|
|
52
|
+
}, async (span) => {
|
|
53
|
+
try {
|
|
54
|
+
// Execute the original K8s API method
|
|
55
|
+
const result = await original.apply(target, args);
|
|
56
|
+
// Add response metadata if available
|
|
57
|
+
if (result?.response?.statusCode) {
|
|
58
|
+
span.setAttribute('http.response.status_code', result.response.statusCode);
|
|
59
|
+
}
|
|
60
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
// Record K8s API error
|
|
65
|
+
span.recordException(error);
|
|
66
|
+
span.setStatus({
|
|
67
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
68
|
+
message: error instanceof Error ? error.message : String(error),
|
|
69
|
+
});
|
|
70
|
+
// Add K8s-specific error attributes
|
|
71
|
+
if (error instanceof Error && 'statusCode' in error) {
|
|
72
|
+
span.setAttribute('k8s.error.status_code', error.statusCode);
|
|
73
|
+
}
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
span.end();
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Tracing wrapper for kubectl CLI command execution
|
|
86
|
+
*
|
|
87
|
+
* Wraps kubectl command execution with OpenTelemetry tracing spans.
|
|
88
|
+
* Captures command details, operation type, and execution results.
|
|
89
|
+
*
|
|
90
|
+
* @param args kubectl command arguments (e.g., ['get', 'pods', '-n', 'default'])
|
|
91
|
+
* @param config kubectl execution configuration
|
|
92
|
+
* @param handler Function that executes the actual kubectl command
|
|
93
|
+
* @returns kubectl command output
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* const output = await withKubectlTracing(
|
|
97
|
+
* ['get', 'crd', '-o', 'json'],
|
|
98
|
+
* { kubeconfig: '/path/to/config' },
|
|
99
|
+
* async () => execAsync('kubectl get crd -o json')
|
|
100
|
+
* );
|
|
101
|
+
*/
|
|
102
|
+
async function withKubectlTracing(args, config, handler) {
|
|
103
|
+
const tracer = api_1.trace.getTracer('dot-ai-mcp');
|
|
104
|
+
// Parse operation and resource from args
|
|
105
|
+
const operation = args[0] || 'unknown'; // 'get', 'apply', 'delete', etc.
|
|
106
|
+
const resource = args[1] || 'unknown'; // 'pods', 'crd', 'deployments', etc.
|
|
107
|
+
const spanName = `kubectl ${operation} ${resource}`;
|
|
108
|
+
return await tracer.startActiveSpan(spanName, {
|
|
109
|
+
kind: api_1.SpanKind.CLIENT,
|
|
110
|
+
attributes: {
|
|
111
|
+
'k8s.client': 'kubectl',
|
|
112
|
+
'k8s.command': 'kubectl',
|
|
113
|
+
'k8s.operation': operation,
|
|
114
|
+
'k8s.resource': resource,
|
|
115
|
+
'k8s.args': args.join(' '),
|
|
116
|
+
...(config?.namespace && { 'k8s.namespace': config.namespace }),
|
|
117
|
+
...(config?.context && { 'k8s.context': config.context }),
|
|
118
|
+
...(config?.kubeconfig && { 'k8s.kubeconfig': config.kubeconfig }),
|
|
119
|
+
},
|
|
120
|
+
}, async (span) => {
|
|
121
|
+
const startTime = Date.now();
|
|
122
|
+
try {
|
|
123
|
+
// Execute the kubectl command
|
|
124
|
+
const result = await api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), handler);
|
|
125
|
+
// Add execution metrics
|
|
126
|
+
span.setAttribute('k8s.duration_ms', Date.now() - startTime);
|
|
127
|
+
span.setAttribute('k8s.output_size_bytes', result.length);
|
|
128
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
// Record kubectl error with details
|
|
133
|
+
span.recordException(error);
|
|
134
|
+
span.setStatus({
|
|
135
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
136
|
+
message: error instanceof Error ? error.message : String(error),
|
|
137
|
+
});
|
|
138
|
+
// Parse kubectl error for additional context
|
|
139
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
140
|
+
if (errorMessage.includes('not found')) {
|
|
141
|
+
span.setAttribute('k8s.error.type', 'NotFound');
|
|
142
|
+
}
|
|
143
|
+
else if (errorMessage.includes('forbidden')) {
|
|
144
|
+
span.setAttribute('k8s.error.type', 'Forbidden');
|
|
145
|
+
}
|
|
146
|
+
else if (errorMessage.includes('timeout')) {
|
|
147
|
+
span.setAttribute('k8s.error.type', 'Timeout');
|
|
148
|
+
}
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
span.end();
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qdrant Vector Database Tracing
|
|
3
|
+
*
|
|
4
|
+
* Provides distributed tracing instrumentation for Qdrant vector database operations.
|
|
5
|
+
* Creates CLIENT spans with database semantic conventions and vector-specific attributes.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Vector database operation types
|
|
9
|
+
*/
|
|
10
|
+
export type VectorDBOperation = 'collection.create' | 'collection.get' | 'collection.list' | 'collection.delete' | 'collection.initialize' | 'vector.upsert' | 'vector.search' | 'vector.search_keywords' | 'vector.retrieve' | 'vector.delete' | 'vector.delete_all' | 'vector.list' | 'health_check';
|
|
11
|
+
/**
|
|
12
|
+
* Qdrant operation metadata for tracing
|
|
13
|
+
*/
|
|
14
|
+
export interface QdrantOperationContext {
|
|
15
|
+
/** Operation type */
|
|
16
|
+
operation: VectorDBOperation;
|
|
17
|
+
/** Collection name */
|
|
18
|
+
collectionName: string;
|
|
19
|
+
/** Vector dimensions (for upsert, search operations) */
|
|
20
|
+
vectorSize?: number;
|
|
21
|
+
/** Search limit (for search operations) */
|
|
22
|
+
limit?: number;
|
|
23
|
+
/** Score threshold (for similarity search) */
|
|
24
|
+
scoreThreshold?: number;
|
|
25
|
+
/** Number of keywords (for keyword search) */
|
|
26
|
+
keywordCount?: number;
|
|
27
|
+
/** Document ID (for single document operations) */
|
|
28
|
+
documentId?: string;
|
|
29
|
+
/** Qdrant server URL */
|
|
30
|
+
serverUrl?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Generic Qdrant operation tracing wrapper
|
|
34
|
+
*
|
|
35
|
+
* @param operationContext - Qdrant operation metadata
|
|
36
|
+
* @param handler - Async operation to trace
|
|
37
|
+
* @returns Result from handler
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* // Trace vector search
|
|
42
|
+
* const results = await withQdrantTracing(
|
|
43
|
+
* {
|
|
44
|
+
* operation: 'vector.search',
|
|
45
|
+
* collectionName: 'capabilities',
|
|
46
|
+
* vectorSize: 1536,
|
|
47
|
+
* limit: 10,
|
|
48
|
+
* scoreThreshold: 0.5,
|
|
49
|
+
* serverUrl: 'http://localhost:6333'
|
|
50
|
+
* },
|
|
51
|
+
* async () => await this.client.search(...)
|
|
52
|
+
* );
|
|
53
|
+
*
|
|
54
|
+
* // Trace document upsert
|
|
55
|
+
* await withQdrantTracing(
|
|
56
|
+
* {
|
|
57
|
+
* operation: 'vector.upsert',
|
|
58
|
+
* collectionName: 'patterns',
|
|
59
|
+
* documentId: 'pattern-123',
|
|
60
|
+
* vectorSize: 384,
|
|
61
|
+
* serverUrl: 'http://localhost:6333'
|
|
62
|
+
* },
|
|
63
|
+
* async () => await this.client.upsert(...)
|
|
64
|
+
* );
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function withQdrantTracing<T>(operationContext: QdrantOperationContext, handler: () => Promise<T>): Promise<T>;
|
|
68
|
+
//# sourceMappingURL=qdrant-tracing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qdrant-tracing.d.ts","sourceRoot":"","sources":["../../../src/core/tracing/qdrant-tracing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;GAEG;AACH,MAAM,MAAM,iBAAiB,GACzB,mBAAmB,GACnB,gBAAgB,GAChB,iBAAiB,GACjB,mBAAmB,GACnB,uBAAuB,GACvB,eAAe,GACf,eAAe,GACf,wBAAwB,GACxB,iBAAiB,GACjB,eAAe,GACf,mBAAmB,GACnB,aAAa,GACb,cAAc,CAAC;AAEnB;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,qBAAqB;IACrB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,sBAAsB;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,EACvC,gBAAgB,EAAE,sBAAsB,EACxC,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,CAAC,CAAC,CAgEZ"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Qdrant Vector Database Tracing
|
|
4
|
+
*
|
|
5
|
+
* Provides distributed tracing instrumentation for Qdrant vector database operations.
|
|
6
|
+
* Creates CLIENT spans with database semantic conventions and vector-specific attributes.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.withQdrantTracing = withQdrantTracing;
|
|
10
|
+
const api_1 = require("@opentelemetry/api");
|
|
11
|
+
const tracer = api_1.trace.getTracer('dot-ai-mcp-qdrant');
|
|
12
|
+
/**
|
|
13
|
+
* Generic Qdrant operation tracing wrapper
|
|
14
|
+
*
|
|
15
|
+
* @param operationContext - Qdrant operation metadata
|
|
16
|
+
* @param handler - Async operation to trace
|
|
17
|
+
* @returns Result from handler
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // Trace vector search
|
|
22
|
+
* const results = await withQdrantTracing(
|
|
23
|
+
* {
|
|
24
|
+
* operation: 'vector.search',
|
|
25
|
+
* collectionName: 'capabilities',
|
|
26
|
+
* vectorSize: 1536,
|
|
27
|
+
* limit: 10,
|
|
28
|
+
* scoreThreshold: 0.5,
|
|
29
|
+
* serverUrl: 'http://localhost:6333'
|
|
30
|
+
* },
|
|
31
|
+
* async () => await this.client.search(...)
|
|
32
|
+
* );
|
|
33
|
+
*
|
|
34
|
+
* // Trace document upsert
|
|
35
|
+
* await withQdrantTracing(
|
|
36
|
+
* {
|
|
37
|
+
* operation: 'vector.upsert',
|
|
38
|
+
* collectionName: 'patterns',
|
|
39
|
+
* documentId: 'pattern-123',
|
|
40
|
+
* vectorSize: 384,
|
|
41
|
+
* serverUrl: 'http://localhost:6333'
|
|
42
|
+
* },
|
|
43
|
+
* async () => await this.client.upsert(...)
|
|
44
|
+
* );
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
async function withQdrantTracing(operationContext, handler) {
|
|
48
|
+
const { operation, collectionName, ...metadata } = operationContext;
|
|
49
|
+
// Create span name: "qdrant.{operation} {collection}"
|
|
50
|
+
// Examples: "qdrant.vector.search capabilities", "qdrant.vector.upsert patterns"
|
|
51
|
+
const spanName = `qdrant.${operation} ${collectionName}`;
|
|
52
|
+
return tracer.startActiveSpan(spanName, {
|
|
53
|
+
kind: 2, // CLIENT span
|
|
54
|
+
attributes: {
|
|
55
|
+
// Database semantic conventions
|
|
56
|
+
'db.system': 'qdrant',
|
|
57
|
+
'db.operation.name': operation,
|
|
58
|
+
'db.collection.name': collectionName,
|
|
59
|
+
// Vector-specific attributes
|
|
60
|
+
...(metadata.vectorSize && { 'db.vector.dimensions': metadata.vectorSize }),
|
|
61
|
+
...(metadata.limit && { 'db.query.limit': metadata.limit }),
|
|
62
|
+
...(metadata.scoreThreshold && { 'db.vector.score_threshold': metadata.scoreThreshold }),
|
|
63
|
+
...(metadata.keywordCount && { 'db.query.keyword_count': metadata.keywordCount }),
|
|
64
|
+
...(metadata.documentId && { 'db.document.id': metadata.documentId }),
|
|
65
|
+
...(metadata.serverUrl && { 'server.address': metadata.serverUrl })
|
|
66
|
+
}
|
|
67
|
+
}, async (span) => {
|
|
68
|
+
try {
|
|
69
|
+
// Execute operation
|
|
70
|
+
const result = await handler();
|
|
71
|
+
// Add result metadata for search operations
|
|
72
|
+
if (operation === 'vector.search' || operation === 'vector.search_keywords') {
|
|
73
|
+
if (Array.isArray(result)) {
|
|
74
|
+
span.setAttribute('db.query.result_count', result.length);
|
|
75
|
+
// For search results with scores, track top score
|
|
76
|
+
if (result.length > 0 && 'score' in result[0]) {
|
|
77
|
+
span.setAttribute('db.vector.top_score', result[0].score);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Add result metadata for list operations
|
|
82
|
+
if (operation === 'vector.list' && Array.isArray(result)) {
|
|
83
|
+
span.setAttribute('db.query.result_count', result.length);
|
|
84
|
+
}
|
|
85
|
+
// Mark span as successful
|
|
86
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
// Record error in span
|
|
91
|
+
span.setStatus({
|
|
92
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
93
|
+
message: error instanceof Error ? error.message : String(error)
|
|
94
|
+
});
|
|
95
|
+
span.recordException(error instanceof Error ? error : new Error(String(error)));
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
span.end();
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Execution Tracing for MCP Tools
|
|
3
|
+
*
|
|
4
|
+
* Provides generic tracing wrapper for all MCP tool executions,
|
|
5
|
+
* creating INTERNAL spans with GenAI semantic conventions.
|
|
6
|
+
*
|
|
7
|
+
* Supports both STDIO (MCP) and HTTP (REST) transports transparently.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Wraps a tool handler with OpenTelemetry tracing
|
|
11
|
+
*
|
|
12
|
+
* Creates an INTERNAL span for tool execution with:
|
|
13
|
+
* - Tool name and input arguments
|
|
14
|
+
* - Execution duration and success status
|
|
15
|
+
* - Exception tracking for errors
|
|
16
|
+
* - GenAI semantic conventions (gen_ai.tool.*)
|
|
17
|
+
*
|
|
18
|
+
* @param toolName - Name of the MCP tool being executed
|
|
19
|
+
* @param args - Tool input arguments (will be serialized to JSON)
|
|
20
|
+
* @param handler - Async function that implements the tool logic
|
|
21
|
+
* @returns Promise resolving to the tool handler result
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const result = await withToolTracing('recommend', { intent: 'deploy postgres' }, async (args) => {
|
|
26
|
+
* return await handleRecommendTool(args);
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function withToolTracing<T>(toolName: string, args: any, handler: (args: any) => Promise<T>): Promise<T>;
|
|
31
|
+
//# sourceMappingURL=tool-tracing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-tracing.d.ts","sourceRoot":"","sources":["../../../src/core/tracing/tool-tracing.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,GAAG,EACT,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,GACjC,OAAO,CAAC,CAAC,CAAC,CAgDZ"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tool Execution Tracing for MCP Tools
|
|
4
|
+
*
|
|
5
|
+
* Provides generic tracing wrapper for all MCP tool executions,
|
|
6
|
+
* creating INTERNAL spans with GenAI semantic conventions.
|
|
7
|
+
*
|
|
8
|
+
* Supports both STDIO (MCP) and HTTP (REST) transports transparently.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.withToolTracing = withToolTracing;
|
|
12
|
+
const api_1 = require("@opentelemetry/api");
|
|
13
|
+
/**
|
|
14
|
+
* Wraps a tool handler with OpenTelemetry tracing
|
|
15
|
+
*
|
|
16
|
+
* Creates an INTERNAL span for tool execution with:
|
|
17
|
+
* - Tool name and input arguments
|
|
18
|
+
* - Execution duration and success status
|
|
19
|
+
* - Exception tracking for errors
|
|
20
|
+
* - GenAI semantic conventions (gen_ai.tool.*)
|
|
21
|
+
*
|
|
22
|
+
* @param toolName - Name of the MCP tool being executed
|
|
23
|
+
* @param args - Tool input arguments (will be serialized to JSON)
|
|
24
|
+
* @param handler - Async function that implements the tool logic
|
|
25
|
+
* @returns Promise resolving to the tool handler result
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const result = await withToolTracing('recommend', { intent: 'deploy postgres' }, async (args) => {
|
|
30
|
+
* return await handleRecommendTool(args);
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
async function withToolTracing(toolName, args, handler) {
|
|
35
|
+
const tracer = api_1.trace.getTracer('dot-ai-mcp');
|
|
36
|
+
// Create INTERNAL span for tool execution
|
|
37
|
+
// Using INTERNAL kind since this is business logic within the server process
|
|
38
|
+
const span = tracer.startSpan(`execute_tool ${toolName}`, {
|
|
39
|
+
kind: api_1.SpanKind.INTERNAL,
|
|
40
|
+
attributes: {
|
|
41
|
+
// GenAI semantic conventions for tool execution
|
|
42
|
+
'gen_ai.tool.name': toolName,
|
|
43
|
+
'gen_ai.tool.input': JSON.stringify(args, null, 2),
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
// Execute handler within active span context
|
|
47
|
+
// This ensures any child spans (AI calls, K8s operations) become children of this span
|
|
48
|
+
return await api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), async () => {
|
|
49
|
+
try {
|
|
50
|
+
const startTime = Date.now();
|
|
51
|
+
const result = await handler(args);
|
|
52
|
+
const duration = Date.now() - startTime;
|
|
53
|
+
// Record success metrics
|
|
54
|
+
span.setAttributes({
|
|
55
|
+
'gen_ai.tool.duration_ms': duration,
|
|
56
|
+
'gen_ai.tool.success': true,
|
|
57
|
+
});
|
|
58
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
// Record error details without disrupting original error flow
|
|
63
|
+
span.recordException(error);
|
|
64
|
+
span.setStatus({
|
|
65
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
66
|
+
message: error.message,
|
|
67
|
+
});
|
|
68
|
+
// Re-throw to preserve original error handling behavior
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
// Always end span regardless of success/failure
|
|
73
|
+
span.end();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenTelemetry Tracer Service
|
|
3
|
+
*
|
|
4
|
+
* Provides lazy initialization and management of distributed tracing.
|
|
5
|
+
* Follows OpenTelemetry best practices with support for multiple exporters.
|
|
6
|
+
*/
|
|
7
|
+
import { SpanOptions } from '@opentelemetry/api';
|
|
8
|
+
import { TracedSpan, TracerService } from './types';
|
|
9
|
+
/**
|
|
10
|
+
* Get or create the global tracer instance
|
|
11
|
+
*/
|
|
12
|
+
export declare function getTracer(): TracerService;
|
|
13
|
+
/**
|
|
14
|
+
* Shutdown the global tracer instance
|
|
15
|
+
*/
|
|
16
|
+
export declare function shutdownTracer(): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Helper function to wrap async operations with tracing
|
|
19
|
+
*/
|
|
20
|
+
export declare function withSpan<T>(name: string, fn: (span: TracedSpan) => Promise<T>, options?: SpanOptions): Promise<T>;
|
|
21
|
+
//# sourceMappingURL=tracer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracer.d.ts","sourceRoot":"","sources":["../../../src/core/tracing/tracer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,OAAO,EAKL,WAAW,EAEZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAiB,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAiMnE;;GAEG;AACH,wBAAgB,SAAS,IAAI,aAAa,CAMzC;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAKpD;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,EACpC,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,CAAC,CAAC,CAYZ"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OpenTelemetry Tracer Service
|
|
4
|
+
*
|
|
5
|
+
* Provides lazy initialization and management of distributed tracing.
|
|
6
|
+
* Follows OpenTelemetry best practices with support for multiple exporters.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.getTracer = getTracer;
|
|
10
|
+
exports.shutdownTracer = shutdownTracer;
|
|
11
|
+
exports.withSpan = withSpan;
|
|
12
|
+
const sdk_node_1 = require("@opentelemetry/sdk-node");
|
|
13
|
+
const resources_1 = require("@opentelemetry/resources");
|
|
14
|
+
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
15
|
+
const sdk_trace_node_1 = require("@opentelemetry/sdk-trace-node");
|
|
16
|
+
const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
|
|
17
|
+
const api_1 = require("@opentelemetry/api");
|
|
18
|
+
const config_1 = require("./config");
|
|
19
|
+
/**
|
|
20
|
+
* Global tracer instance (singleton pattern with lazy initialization)
|
|
21
|
+
*/
|
|
22
|
+
let tracerInstance = null;
|
|
23
|
+
/**
|
|
24
|
+
* OpenTelemetry Tracer implementation
|
|
25
|
+
*/
|
|
26
|
+
class OpenTelemetryTracer {
|
|
27
|
+
sdk = null;
|
|
28
|
+
config;
|
|
29
|
+
initialized = false;
|
|
30
|
+
constructor(config) {
|
|
31
|
+
this.config = config;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Initialize the OpenTelemetry SDK (called lazily on first use)
|
|
35
|
+
*/
|
|
36
|
+
initialize() {
|
|
37
|
+
if (this.initialized) {
|
|
38
|
+
return; // Already initialized
|
|
39
|
+
}
|
|
40
|
+
if (!this.config.enabled) {
|
|
41
|
+
if (this.config.debug) {
|
|
42
|
+
console.log('[Tracing] Tracing is disabled, skipping initialization');
|
|
43
|
+
}
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
// Validate configuration
|
|
48
|
+
(0, config_1.validateTracingConfig)(this.config);
|
|
49
|
+
// Create resource with service identification
|
|
50
|
+
const serviceResource = (0, resources_1.resourceFromAttributes)({
|
|
51
|
+
[semantic_conventions_1.ATTR_SERVICE_NAME]: this.config.serviceName,
|
|
52
|
+
[semantic_conventions_1.ATTR_SERVICE_VERSION]: this.config.serviceVersion,
|
|
53
|
+
});
|
|
54
|
+
const resource = (0, resources_1.defaultResource)().merge(serviceResource);
|
|
55
|
+
// Create exporter based on configuration
|
|
56
|
+
const traceExporter = this.createExporter();
|
|
57
|
+
// Initialize Node SDK without auto-instrumentation
|
|
58
|
+
// All operations are manually instrumented with descriptive spans
|
|
59
|
+
this.sdk = new sdk_node_1.NodeSDK({
|
|
60
|
+
resource,
|
|
61
|
+
traceExporter,
|
|
62
|
+
instrumentations: [], // No auto-instrumentation needed
|
|
63
|
+
});
|
|
64
|
+
// Start the SDK
|
|
65
|
+
this.sdk.start();
|
|
66
|
+
this.initialized = true;
|
|
67
|
+
if (this.config.debug) {
|
|
68
|
+
console.log('[Tracing] OpenTelemetry initialized successfully', {
|
|
69
|
+
serviceName: this.config.serviceName,
|
|
70
|
+
serviceVersion: this.config.serviceVersion,
|
|
71
|
+
exporterType: this.config.exporterType,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
console.error('[Tracing] Failed to initialize OpenTelemetry:', error);
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Create exporter based on configuration
|
|
82
|
+
*/
|
|
83
|
+
createExporter() {
|
|
84
|
+
switch (this.config.exporterType) {
|
|
85
|
+
case 'console':
|
|
86
|
+
if (this.config.debug) {
|
|
87
|
+
console.log('[Tracing] Using console exporter (outputs to stderr)');
|
|
88
|
+
}
|
|
89
|
+
return new sdk_trace_node_1.ConsoleSpanExporter();
|
|
90
|
+
case 'otlp':
|
|
91
|
+
if (this.config.debug) {
|
|
92
|
+
console.log('[Tracing] Using OTLP exporter', {
|
|
93
|
+
endpoint: this.config.otlpEndpoint || 'http://localhost:4318/v1/traces'
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return new exporter_trace_otlp_http_1.OTLPTraceExporter({
|
|
97
|
+
url: this.config.otlpEndpoint || 'http://localhost:4318/v1/traces',
|
|
98
|
+
});
|
|
99
|
+
case 'jaeger':
|
|
100
|
+
// Jaeger exporter will be added in Phase 3
|
|
101
|
+
throw new Error('Jaeger exporter not yet implemented - coming in Phase 3');
|
|
102
|
+
case 'zipkin':
|
|
103
|
+
// Zipkin exporter will be added in Phase 3
|
|
104
|
+
throw new Error('Zipkin exporter not yet implemented - coming in Phase 3');
|
|
105
|
+
default:
|
|
106
|
+
throw new Error(`Unknown exporter type: ${this.config.exporterType}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Check if tracing is enabled
|
|
111
|
+
*/
|
|
112
|
+
isEnabled() {
|
|
113
|
+
return this.config.enabled;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Create a new span with utility methods
|
|
117
|
+
*/
|
|
118
|
+
startSpan(name, options, parentContext) {
|
|
119
|
+
if (!this.config.enabled) {
|
|
120
|
+
// Return a no-op span if tracing is disabled
|
|
121
|
+
return this.createNoOpSpan();
|
|
122
|
+
}
|
|
123
|
+
// Lazy initialization on first span creation
|
|
124
|
+
if (!this.initialized) {
|
|
125
|
+
this.initialize();
|
|
126
|
+
}
|
|
127
|
+
const tracer = api_1.trace.getTracer(this.config.serviceName, this.config.serviceVersion);
|
|
128
|
+
const ctx = parentContext || api_1.context.active();
|
|
129
|
+
const span = tracer.startSpan(name, options, ctx);
|
|
130
|
+
return this.wrapSpan(span);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Wrap an OpenTelemetry span with utility methods
|
|
134
|
+
*/
|
|
135
|
+
wrapSpan(span) {
|
|
136
|
+
return {
|
|
137
|
+
span,
|
|
138
|
+
end() {
|
|
139
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
140
|
+
span.end();
|
|
141
|
+
},
|
|
142
|
+
endWithError(error) {
|
|
143
|
+
span.recordException(error);
|
|
144
|
+
span.setStatus({
|
|
145
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
146
|
+
message: error.message,
|
|
147
|
+
});
|
|
148
|
+
span.end();
|
|
149
|
+
},
|
|
150
|
+
setAttributes(attributes) {
|
|
151
|
+
span.setAttributes(attributes);
|
|
152
|
+
},
|
|
153
|
+
addEvent(name, attributes) {
|
|
154
|
+
span.addEvent(name, attributes);
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Create a no-op span for when tracing is disabled
|
|
160
|
+
*/
|
|
161
|
+
createNoOpSpan() {
|
|
162
|
+
const noopSpan = api_1.trace.getTracer('noop').startSpan('noop');
|
|
163
|
+
return this.wrapSpan(noopSpan);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Shutdown the tracer gracefully
|
|
167
|
+
*/
|
|
168
|
+
async shutdown() {
|
|
169
|
+
if (this.sdk && this.initialized) {
|
|
170
|
+
if (this.config.debug) {
|
|
171
|
+
console.log('[Tracing] Shutting down OpenTelemetry SDK...');
|
|
172
|
+
}
|
|
173
|
+
await this.sdk.shutdown();
|
|
174
|
+
this.initialized = false;
|
|
175
|
+
if (this.config.debug) {
|
|
176
|
+
console.log('[Tracing] OpenTelemetry SDK shut down successfully');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get or create the global tracer instance
|
|
183
|
+
*/
|
|
184
|
+
function getTracer() {
|
|
185
|
+
if (!tracerInstance) {
|
|
186
|
+
const config = (0, config_1.loadTracingConfig)();
|
|
187
|
+
tracerInstance = new OpenTelemetryTracer(config);
|
|
188
|
+
}
|
|
189
|
+
return tracerInstance;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Shutdown the global tracer instance
|
|
193
|
+
*/
|
|
194
|
+
async function shutdownTracer() {
|
|
195
|
+
if (tracerInstance) {
|
|
196
|
+
await tracerInstance.shutdown();
|
|
197
|
+
tracerInstance = null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Helper function to wrap async operations with tracing
|
|
202
|
+
*/
|
|
203
|
+
async function withSpan(name, fn, options) {
|
|
204
|
+
const tracer = getTracer();
|
|
205
|
+
const span = tracer.startSpan(name, options);
|
|
206
|
+
try {
|
|
207
|
+
const result = await fn(span);
|
|
208
|
+
span.end();
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
span.endWithError(error);
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
}
|