-
Notifications
You must be signed in to change notification settings - Fork 173
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
add propagation interface #510
base: master
Are you sure you want to change the base?
Changes from all commits
5fa6f38
7e85153
b5472eb
4ce6942
a9f4c83
5349ef7
fcf3d23
d34a721
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 |
---|---|---|
|
@@ -29,6 +29,14 @@ declare namespace zipkin { | |
const alwaysSample: (traceId: TraceId) => boolean; | ||
} | ||
|
||
interface Injector<R> { | ||
inject(context: Context<TraceId>, request: R): void; | ||
} | ||
|
||
interface Extractor<R> { | ||
extract(request: R): TraceId; | ||
} | ||
|
||
class Tracer { | ||
constructor(args: { | ||
ctxImpl: Context<TraceId>, | ||
|
@@ -39,7 +47,8 @@ declare namespace zipkin { | |
localServiceName?: string, | ||
localEndpoint?: model.Endpoint, | ||
log?: Console, | ||
defaultTags?: {} | ||
defaultTags?: {}, | ||
propagation?: propagation.Propagation | ||
}); | ||
|
||
/** Returns the current trace ID or a sentinel value indicating its absence. */ | ||
|
@@ -61,6 +70,11 @@ declare namespace zipkin { | |
recordLocalAddr(inetAddress: InetAddress): void; | ||
recordBinary(key: string, value: boolean | string | number): void; | ||
writeIdToConsole(message: any): void; | ||
/** Extract propagation ctx from request */ | ||
extractId(readHeader: <T> (header: string) => option.IOption<T>): void; | ||
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. I think I'd prefer to have the extractId to be actually an extractor like the injector. Also, maybe read header can be an abstract |
||
/** Injector propagation ctx from request */ | ||
injector(request: any): object; | ||
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. injector can be for messaging too so I think it is better that we pass something like |
||
|
||
} | ||
|
||
class TraceId { | ||
|
@@ -271,14 +285,6 @@ declare namespace zipkin { | |
toInt(): number; | ||
} | ||
|
||
namespace HttpHeaders { | ||
const TraceId: string; | ||
const SpanId: string; | ||
const ParentSpanId: string; | ||
const Sampled: string; | ||
const Flags: string; | ||
} | ||
|
||
interface Record { | ||
traceId: TraceId; | ||
timestamp: number; | ||
|
@@ -339,6 +345,7 @@ declare namespace zipkin { | |
} | ||
|
||
namespace Instrumentation { | ||
|
||
class HttpServer { | ||
constructor(args: { | ||
tracer: Tracer, | ||
|
@@ -357,7 +364,7 @@ declare namespace zipkin { | |
} | ||
|
||
class HttpClient { | ||
constructor(args: { tracer: Tracer, serviceName?: string, remoteServiceName?: string }); | ||
constructor(args: { tracer: Tracer, serviceName?: string, remoteServiceName?: string}); | ||
|
||
recordRequest<T>( | ||
request: T, | ||
|
@@ -368,6 +375,24 @@ declare namespace zipkin { | |
recordError(traceId: TraceId, error: Error): void; | ||
} | ||
} | ||
namespace propagation { | ||
interface Setter { | ||
put<R, K>(request: R, key: K, value: string): void; | ||
} | ||
interface Getter { | ||
get<R, K>(request: R, key: K): string; | ||
} | ||
interface Propagation { | ||
keys(): []; | ||
extractor<R>(getter: Getter): Extractor<R>; | ||
injector<R, K>(setter: Setter): Injector<R>; | ||
} | ||
class B3Propagation implements Propagation { | ||
keys(): []; | ||
extractor<R>(getter: Getter): Extractor<R>; | ||
injector<R, K>(setter: Setter): Injector<R>; | ||
} | ||
} | ||
} | ||
|
||
export = zipkin; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,6 @@ export { default as randomTraceId } from './tracer/randomTraceId'; | |
export { default as sampler } from './tracer/sampler'; | ||
export { default as TraceId } from './tracer/TraceId'; | ||
|
||
export { default as HttpHeaders } from './httpHeaders'; | ||
export { default as InetAddress } from './InetAddress'; | ||
|
||
export { default as BatchRecorder } from './batch-recorder'; | ||
|
@@ -16,7 +15,7 @@ export { default as ConsoleRecorder } from './console-recorder'; | |
export { default as ExplicitContext } from './explicit-context'; | ||
|
||
export { default as Instrumentation } from './instrumentation'; | ||
export { default as Request } from './request'; | ||
export { default as B3Propagation } from './propagation/b3propagation'; | ||
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. <3 |
||
|
||
export { default as jsonEncoder } from './jsonEncoder'; | ||
export { default as model } from './model'; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,6 @@ | ||
const Annotation = require('../annotation'); | ||
const Header = require('../httpHeaders'); | ||
const InetAddress = require('../InetAddress'); | ||
const TraceId = require('../tracer/TraceId'); | ||
const parseRequestUrl = require('../parseUrl'); | ||
const {Some, None} = require('../option'); | ||
|
||
function stringToBoolean(str) { | ||
return str === '1' || str === 'true'; | ||
} | ||
|
||
function stringToIntOption(str) { | ||
try { | ||
return new Some(parseInt(str)); | ||
} catch (err) { | ||
return None; | ||
} | ||
} | ||
|
||
function containsRequiredHeaders(readHeader) { | ||
return readHeader(Header.TraceId) !== None && readHeader(Header.SpanId) !== None; | ||
} | ||
|
||
function requiredArg(name) { | ||
throw new Error(`HttpServerInstrumentation: Missing required argument ${name}.`); | ||
|
@@ -38,34 +19,6 @@ class HttpServerInstrumentation { | |
this.port = port; | ||
} | ||
|
||
_createIdFromHeaders(readHeader) { | ||
if (containsRequiredHeaders(readHeader)) { | ||
const spanId = readHeader(Header.SpanId); | ||
const parentId = spanId.map((sid) => { | ||
const traceId = readHeader(Header.TraceId); | ||
const parentSpanId = readHeader(Header.ParentSpanId); | ||
const sampled = readHeader(Header.Sampled); | ||
const flags = readHeader(Header.Flags).flatMap(stringToIntOption).getOrElse(0); | ||
return new TraceId({ | ||
traceId: traceId.getOrElse(), | ||
parentId: parentSpanId, | ||
spanId: sid, | ||
debug: flags === 1, | ||
sampled: sampled.map(stringToBoolean), | ||
}); | ||
}); | ||
|
||
return new Some(this.tracer.join(parentId.getOrElse())); | ||
} else if (readHeader(Header.Flags) !== None || readHeader(Header.Sampled) !== None) { | ||
const sampled = readHeader(Header.Sampled) === None | ||
? None : readHeader(Header.Sampled).map(stringToBoolean); | ||
const flags = readHeader(Header.Flags).flatMap(stringToIntOption).getOrElse(0); | ||
return new Some(this.tracer.createRootId(sampled, flags === 1)); | ||
} else { | ||
return new Some(this.tracer.createRootId()); | ||
} | ||
} | ||
|
||
spanNameFromRoute(method, route, code) { // eslint-disable-line class-methods-use-this | ||
if (code > 299 && code < 400) return `${method} redirected`; | ||
if (code === 404) return `${method} not_found`; | ||
|
@@ -74,7 +27,7 @@ class HttpServerInstrumentation { | |
} | ||
|
||
recordRequest(method, requestUrl, readHeader) { | ||
this._createIdFromHeaders(readHeader).ifPresent(id => this.tracer.setId(id)); | ||
this.tracer.extractId(readHeader); | ||
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. I am really happy this becomes so simple now. |
||
const {id} = this.tracer; | ||
const {path} = parseRequestUrl(requestUrl); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
const {Some, None} = require('../option'); | ||
const TraceId = require('../tracer/TraceId'); | ||
const Tracer = require('../tracer'); | ||
|
||
function stringToBoolean(str) { | ||
return str === '1' || str === 'true'; | ||
} | ||
|
||
function stringToIntOption(str) { | ||
try { | ||
return new Some(parseInt(str)); | ||
} catch (err) { | ||
return None; | ||
} | ||
} | ||
|
||
class B3Extractor { | ||
|
||
constructor(b3Propagation, getter) { | ||
this._propagation = b3Propagation | ||
this._getter = getter | ||
} | ||
|
||
extract(request) { | ||
const traceId = this._getter.get(request, this._propagation._TRACE_ID); | ||
const spanId = this._getter.get(request, this._propagation._SPAN_ID); | ||
const flags = this._getter.get(request, this._propagation._FLAGS); | ||
const sampled = this._getter.get(request, this._propagation._SAMPLED); | ||
if(traceId !== None && spanId !== None){ | ||
return spanId.map((sid) => { | ||
const parentSpanId = this._getter.get(request, this._propagation._PARENT_SPAN_ID); | ||
return new TraceId({ | ||
traceId: traceId.getOrElse(), | ||
parentId: parentSpanId, | ||
spanId: sid, | ||
debug: flags.flatMap(stringToIntOption).getOrElse(0) === 1, | ||
sampled: sampled.map(stringToBoolean), | ||
}); | ||
}); | ||
} else if(flags !== None || sampled !== None){ | ||
// TODO Change ?? | ||
return Tracer.createRootId(sampled === None ? None : sampled.map(stringToBoolean), | ||
flags.flatMap(stringToIntOption).getOrElse(0) === 1) | ||
} | ||
return Tracer.createRootId(); | ||
} | ||
} | ||
|
||
class B3Injector { | ||
|
||
constructor(b3Propagation, setter) { | ||
this._propagation = b3Propagation | ||
this._setter = setter | ||
} | ||
|
||
inject(context, request) { | ||
this._setter.put(request, this._propagation._TRACE_ID, context.traceId); | ||
this._setter.put(request, this._propagation._SPAN_ID, context.spanId); | ||
context.sampled.ifPresent((psid) => { this._setter.put(request, this._propagation._PARENT_SPAN_ID, psid) }); | ||
context.sampled.ifPresent((sampled) => { this._setter.put(request, this._propagation._SAMPLED, sampled? '1' : '0') }); | ||
if(context.isDebug()){ | ||
this._setter.put(request, this._propagation._FLAGS, '1'); | ||
} | ||
} | ||
|
||
} | ||
|
||
class B3Propagation { | ||
|
||
_TRACE_ID = 'X-B3-TraceId' | ||
_SPAN_ID = 'X-B3-SpanId' | ||
_PARENT_SPAN_ID = 'X-B3-ParentSpanId' | ||
_SAMPLED = 'X-B3-Sampled' | ||
_FLAGS = 'X-B3-Flags' | ||
|
||
get keys() { | ||
return [ | ||
this._TRACE_ID, | ||
this._SPAN_ID, | ||
this._PARENT_SPAN_ID, | ||
this._SAMPLED, | ||
this._FLAGS | ||
]; | ||
} | ||
|
||
extractor(getter) { | ||
return new B3Extractor(this, getter); | ||
} | ||
|
||
injector(setter) { | ||
return new B3Injector(this, setter); | ||
} | ||
} | ||
|
||
module.exports = B3Propagation; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
const B3Propagation = require('./b3propagation'); | ||
|
||
module.exports = { | ||
B3Propagation | ||
}; |
This file was deleted.
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.
I'd rather pass the clientTraceId explicitly instead of having the injector to know about the scope.