Updated readme to match latest changes.
Not writes process/resource and additional attribute information
This commit is contained in:
@@ -1,57 +1,67 @@
|
||||
# Open Telemetery Example
|
||||
# Open Telemetry Example
|
||||
|
||||
Writes Telemetry Tracing information to the endpoint provided using the [OLTP JSON over HTTP specification](https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md#json-protobuf-encoding)
|
||||
|
||||
## Example Usage
|
||||
|
||||
Use the _code block_ widget to start and end spans. Spans can be nested to form a stack, ending a span will always end the last span added to the stack.
|
||||
Use the _code block_ widget to start and end spans.
|
||||
|
||||
### Visualization
|
||||
Spans can be nested to form a stack, with the parent span being the most recent
|
||||
active span added to the stack. You can have multiple spans using the same name,
|
||||
and ending a span by name will always end the most recent span.
|
||||
|
||||
Spans will only be written to the opentelemetry endpoint once the _endSpan_
|
||||
method is called.
|
||||
|
||||
## Visualization
|
||||
|
||||
For example, using Jaeger UI:
|
||||
|
||||

|
||||
|
||||
## Code Snippets
|
||||
|
||||
### Start Span
|
||||
|
||||
```javascript
|
||||
(async () => {
|
||||
opentelemetry.startSpan("Global Flow")
|
||||
opentelemetry.startSpan("Global Flow");
|
||||
})()
|
||||
.catch((error) => {
|
||||
console.error(error.message)
|
||||
recognizedObject.answers.push('')
|
||||
console.error(error.message);
|
||||
recognizedObject.answers.push("");
|
||||
recognizedObject.errorInfo = {
|
||||
...recognizedObject.errorInfo,
|
||||
label: {
|
||||
data: error.toJSON ? error.toJSON() : {},
|
||||
message: error.message,
|
||||
},
|
||||
}
|
||||
};
|
||||
})
|
||||
.finally(() => {
|
||||
next()
|
||||
})
|
||||
|
||||
next();
|
||||
});
|
||||
```
|
||||
|
||||
### End Span
|
||||
|
||||
```javascript
|
||||
(async () => {
|
||||
opentelemetry.endSpan("Global Flow")
|
||||
opentelemetry.endSpan("Global Flow");
|
||||
})()
|
||||
.catch((error) => {
|
||||
console.error(error.message)
|
||||
recognizedObject.answers.push('')
|
||||
console.error(error.message);
|
||||
recognizedObject.answers.push("");
|
||||
recognizedObject.errorInfo = {
|
||||
...recognizedObject.errorInfo,
|
||||
label: {
|
||||
data: error.toJSON ? error.toJSON() : {},
|
||||
message: error.message,
|
||||
},
|
||||
}
|
||||
};
|
||||
})
|
||||
.finally(() => {
|
||||
next()
|
||||
})
|
||||
next();
|
||||
});
|
||||
```
|
||||
|
||||
```
|
||||
@@ -1,152 +1,160 @@
|
||||
const {
|
||||
recognizedObject: r = {},
|
||||
traces = axios.create({
|
||||
baseURL: opentelemetry_settings.baseUrl,
|
||||
timeout: 16000,
|
||||
}),
|
||||
recognizedObject: r = {},
|
||||
traces = axios.create({
|
||||
baseURL: opentelemetry_settings.baseUrl,
|
||||
timeout: 16000,
|
||||
}),
|
||||
} = this;
|
||||
|
||||
function generateIdHex(numBytes = 8) {
|
||||
const bytes = crypto.getRandomValues(new Uint8Array(numBytes));
|
||||
return Array.from(bytes)
|
||||
.map(b => b.toString(16).padStart(2, '0'))
|
||||
.join('');
|
||||
const bytes = crypto.getRandomValues(new Uint8Array(numBytes));
|
||||
return Array.from(bytes)
|
||||
.map((b) => b.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
}
|
||||
|
||||
return {
|
||||
async startSpan(name) {
|
||||
if (name == null) {
|
||||
throw new Error("Span name is required");
|
||||
}
|
||||
async startSpan(name) {
|
||||
if (name == null) {
|
||||
throw new Error("Span name is required");
|
||||
}
|
||||
|
||||
// Initialize telemetry object if it doesn't exist
|
||||
if ("telemetry" in r == false) {
|
||||
r.telemetry = [];
|
||||
if (opentelemetry_settings.trace == "conversation") {
|
||||
r.telemetry.traceId = r.conversationId.replace(/-/gi, "");
|
||||
} else {
|
||||
r.telemetry.traceId = generateIdHex(16);
|
||||
}
|
||||
}
|
||||
// Initialize telemetry object if it doesn't exist
|
||||
if ("telemetry" in r == false) {
|
||||
r.telemetry = { spans: [] };
|
||||
if (opentelemetry_settings.trace == "conversation") {
|
||||
r.telemetry.traceId = r.conversationId.replace(/-/gi, "");
|
||||
} else {
|
||||
r.telemetry.traceId = generateIdHex(16);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const span = {
|
||||
name: name,
|
||||
resourceSpans: [
|
||||
{
|
||||
resource: {
|
||||
attributes: [
|
||||
{
|
||||
key: "service.name",
|
||||
value: {
|
||||
stringValue: "ivastudio.verint.live",
|
||||
},
|
||||
},
|
||||
],
|
||||
try {
|
||||
const span = {
|
||||
name: name,
|
||||
resourceSpans: [
|
||||
{
|
||||
resource: {
|
||||
attributes: [
|
||||
{
|
||||
key: "service.name",
|
||||
value: {
|
||||
stringValue: "ivastudio.verint.live",
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "conversationId",
|
||||
value: {
|
||||
stringValue: r.conversationId,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "workspaceId",
|
||||
value: {
|
||||
stringValue: r.workspaceId,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
scopeSpans: [
|
||||
{
|
||||
spans: [
|
||||
{
|
||||
traceId: r.telemetry.traceId,
|
||||
spanId: generateIdHex(),
|
||||
name: name,
|
||||
startTimeUnixNano: "" + Date.now() * 1000000,
|
||||
kind: 2,
|
||||
attributes: [
|
||||
{
|
||||
key: "input",
|
||||
value: {
|
||||
stringValue: r.input,
|
||||
},
|
||||
scopeSpans: [
|
||||
{
|
||||
scope: {
|
||||
name: r.conversationId,
|
||||
version: "1.0.0",
|
||||
attributes: [
|
||||
{
|
||||
key: "my.scope.attribute",
|
||||
value: {
|
||||
stringValue: "some scope attribute",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
spans: [
|
||||
{
|
||||
traceId: r.telemetry.traceId,
|
||||
spanId: generateIdHex(),
|
||||
name: name,
|
||||
startTimeUnixNano: "" + Date.now() * 1000000,
|
||||
kind: 2,
|
||||
attributes: [
|
||||
{
|
||||
key: "conversationId",
|
||||
value: {
|
||||
stringValue: r.conversationId,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "workspaceId",
|
||||
value: {
|
||||
stringValue: r.workspaceId,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "input",
|
||||
value: {
|
||||
stringValue: r.input,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "channel",
|
||||
value: {
|
||||
stringValue: (
|
||||
req.body?.metadata?.channel ??
|
||||
req.body?.channel ??
|
||||
"web"
|
||||
).toLowerCase(),
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "sessionId",
|
||||
value: {
|
||||
stringValue: (
|
||||
req.body?.metadata?.sessionId ?? "undefined"
|
||||
),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
r.telemetry.unshift(span);
|
||||
return span;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
async endSpan(name) {
|
||||
if (name == null) {
|
||||
throw new Error("Span name is required");
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
r.telemetry.spans.unshift(span);
|
||||
return span;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
async endSpan(name) {
|
||||
if (name == null) {
|
||||
throw new Error("Span name is required");
|
||||
}
|
||||
|
||||
if ("telemetry" in r == false) {
|
||||
// nothing to end
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const spanIndex = r.telemetry.spans.findIndex(
|
||||
(span) => span.name === name
|
||||
);
|
||||
|
||||
if (spanIndex == -1) {
|
||||
// nothing to end
|
||||
return;
|
||||
}
|
||||
|
||||
const span = r.telemetry.spans.splice(spanIndex, 1)[0];
|
||||
|
||||
if (r.telemetry.spans.length >= 1) {
|
||||
// Assume span now at index is the parent
|
||||
const parentSpan = r.telemetry.spans[spanIndex];
|
||||
if (parentSpan) {
|
||||
span.resourceSpans[0].scopeSpans[0].spans[0].parentSpanId =
|
||||
parentSpan.resourceSpans[0].scopeSpans[0].spans[0].spanId;
|
||||
} else {
|
||||
console.debug(name + " has no parentSpan");
|
||||
}
|
||||
}
|
||||
|
||||
if ("telemetry" in r == false) {
|
||||
// nothing to end
|
||||
return;
|
||||
}
|
||||
span.resourceSpans[0].scopeSpans[0].spans[0].endTimeUnixNano =
|
||||
"" + Date.now() * 1000000;
|
||||
|
||||
try {
|
||||
const spanIndex = r.telemetry.findIndex((span) => span.name === name);
|
||||
span.resourceSpans[0].scopeSpans[0].spans[0].attributes.push({
|
||||
key: "answers",
|
||||
value: {
|
||||
stringValue: JSON.stringify(r.answers),
|
||||
},
|
||||
});
|
||||
|
||||
if (spanIndex == -1) {
|
||||
// nothing to end
|
||||
return;
|
||||
}
|
||||
|
||||
const span = r.telemetry.splice(spanIndex, 1)[0];
|
||||
|
||||
if (r.telemetry.length >= 1) {
|
||||
// Assume span now at index is the parent
|
||||
const parentSpan = r.telemetry[spanIndex];
|
||||
if (parentSpan) {
|
||||
span.resourceSpans[0].scopeSpans[0].spans[0].parentSpanId =
|
||||
parentSpan.resourceSpans[0].scopeSpans[0].spans[0].spanId;
|
||||
} else {
|
||||
console.debug(name + " has no parentSpan");
|
||||
}
|
||||
}
|
||||
|
||||
span.resourceSpans[0].scopeSpans[0].spans[0].endTimeUnixNano =
|
||||
"" + Date.now() * 1000000;
|
||||
|
||||
span.resourceSpans[0].scopeSpans[0].spans[0].attributes.push({
|
||||
key: "answers",
|
||||
value: {
|
||||
stringValue: JSON.stringify(r.answers),
|
||||
},
|
||||
});
|
||||
|
||||
const response = await traces.post(`/v1/traces`, span, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
const response = await traces.post(`/v1/traces`, span, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user