New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add Azure SDK Patching Subscriber #562
Changes from 11 commits
71dab54
769ce1b
720d2a6
ef22ade
320f4fe
7db8a57
4bbda8c
ffd123b
92bef90
1d892ef
f7643fc
c6fb329
b74ded5
3bb57d1
233a9b4
c2b9900
52834e3
d54b600
4062b9a
f01a03e
a39ea0d
60cce8e
b1a4f57
22a0732
c1d913f
77e4d50
40b7e3c
0276be4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { CorrelationContextManager, CorrelationContext } from "./CorrelationContextManager" | ||
import { ISpanContext } from "diagnostic-channel"; | ||
import { EventEmitter } from "events"; | ||
|
||
export interface Span { | ||
_duration: [number, number]; | ||
name: string; | ||
parentSpanId?: string; | ||
status: { code: number, message?: string }, | ||
attributes: Record<string, string>, | ||
context: () => { | ||
traceId: string; | ||
spanId: string; | ||
traceFlags?: { toString: () => string }; | ||
tracestate?: string; | ||
} | ||
kind: number // 1: SERVER, 2: CLIENT | ||
} | ||
|
||
export class OpenTelemetryScopeManagerWrapper { | ||
public active() { | ||
return CorrelationContextManager.getCurrentContext(); | ||
} | ||
|
||
public with(span: Span, fn: () => any) { | ||
const parentSpanId = span.parentSpanId; | ||
const name = span.name; | ||
const correlationContext = OpenTelemetryScopeManagerWrapper._spanToContext(span, parentSpanId, name); | ||
return CorrelationContextManager.runWithContext(correlationContext, fn)(); | ||
} | ||
|
||
public bind<T>(target: T): T { | ||
if (typeof target === "function") { | ||
return CorrelationContextManager.wrapCallback(target); | ||
} else if (target instanceof EventEmitter) { | ||
CorrelationContextManager.wrapEmitter(target); | ||
} | ||
return target; | ||
} | ||
|
||
public enable(): this { | ||
CorrelationContextManager.enable(); | ||
return this; | ||
} | ||
|
||
public disable(): this { | ||
CorrelationContextManager.disable(); | ||
return this; | ||
} | ||
|
||
private static _spanToContext(span: Span, parentSpanId?: string, name?: string): CorrelationContext { | ||
const _parentId = parentSpanId ? `|${span.context().traceId}.${parentSpanId}.` : span.context().traceId; | ||
const context: ISpanContext = { | ||
...span.context(), | ||
traceFlags: span.context().traceFlags.toString() | ||
}; | ||
const correlationContext = CorrelationContextManager.spanToContextObject(context, _parentId, name) | ||
return correlationContext; | ||
} | ||
} | ||
|
||
export const AsyncScopeManager = new OpenTelemetryScopeManagerWrapper(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for details. | ||
import TelemetryClient = require("../../Library/TelemetryClient"); | ||
import { channel, IStandardEvent } from "diagnostic-channel"; | ||
|
||
import Traceparent = require("../../Library/Traceparent"); | ||
import * as Contracts from "../../Declarations/Contracts"; | ||
import { Span, AsyncScopeManager } from "../AsyncHooksScopeManager"; | ||
|
||
let clients: TelemetryClient[] = []; | ||
|
||
export const subscriber = (event: IStandardEvent<Span>) => { | ||
const span = event.data; | ||
const spanContext = span.context(); | ||
const duration = Math.round(span._duration[0] * 1e3 + span._duration[1] / 1e6); | ||
const id = `|${span.context().traceId}.${span.context().spanId}.`; | ||
|
||
const traceparent = new Traceparent(); | ||
traceparent.traceId = spanContext.traceId; | ||
traceparent.spanId = spanContext.spanId; | ||
traceparent.traceFlag = spanContext.traceFlags.toString(); | ||
traceparent.parentId = span.parentSpanId ? `|${spanContext.traceId}.${span.parentSpanId}.` : null; | ||
|
||
const properties = { | ||
...span.attributes, | ||
}; | ||
if (span.status.message) { | ||
properties["status.message"] = span.status.message; | ||
} | ||
AsyncScopeManager.with(span, () => { | ||
clients.forEach((client) => { | ||
if (span.kind === 1) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Enum for SpanKind would be good here |
||
// Server | ||
client.trackRequest({ | ||
id: id, | ||
name: span.name, | ||
duration: duration, | ||
resultCode: span.status.code, | ||
success: span.status.code === 0, | ||
url: span.attributes.component, | ||
properties: properties, | ||
} as Contracts.RequestTelemetry & Contracts.Identified); | ||
} else { | ||
// Client | ||
markwolff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
client.trackDependency({ | ||
id: id, | ||
name: span.name, | ||
duration: duration, | ||
data: span.attributes.component || span.name, | ||
dependencyTypeName: span.attributes.component || span.name, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The span attributes aren't guaranteed to provide meaningful information in a standardized way right now, so for now just populate them with current "standards" and iterate back on this in the future |
||
resultCode: span.status.code, | ||
success: span.status.code === 0, | ||
properties: properties | ||
} as Contracts.DependencyTelemetry & Contracts.Identified); | ||
} | ||
}); | ||
}); | ||
}; | ||
|
||
export function enable(enabled: boolean, client: TelemetryClient) { | ||
if (enabled) { | ||
if (clients.length === 0) { | ||
channel.subscribe<any>("azure-coretracing", subscriber); | ||
}; | ||
clients.push(client); | ||
} else { | ||
clients = clients.filter((c) => c != client); | ||
if (clients.length === 0) { | ||
channel.unsubscribe("azure-coretracing", subscriber); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A clone of Span interface so that we don't need to take a Typescript 3 dependency