Updated readme to match latest changes.

Not writes process/resource and additional attribute information
This commit is contained in:
2026-01-10 13:53:53 -06:00
parent ce23405757
commit 7371260442
2 changed files with 171 additions and 153 deletions

View File

@@ -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:
![Tracing Screenshot](screenshots/IVA%20Tracing.png)
## 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();
});
```
```

View File

@@ -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;
}
},
};