// jaeger client
import { initTracer as initJaegerTracer } from 'jaeger-client';
// OpenTracing
import * as opentracing from 'opentracing';
function initTracer(serviceName: string) {
const config = {
serviceName: serviceName,
sampler: {
type: 'const',
param: 1
},
reporter: {
logSpans: true
}
};
const options = {
logger: {
info(msg) {
console.log('INFO ', msg);
},
error(msg) {
console.log('ERROR', msg);
}
}
};
return initJaegerTracer(config, options);
}
export class Tracing {
private static _instance: Tracing;
public tracer: opentracing.Tracer;
constructor() {
const serviceName = 'BotConnector';
this.tracer = initTracer(serviceName);
}
/** Get Logger */
public static getInstance(): Tracing {
this._instance = this._instance || (this._instance = new this());
return this._instance;
}
}
//OpenTracing
import * as opentracing from 'opentracing';
import { Tracing } from './../opentracing/tracing';
const tracer = Tracing.getInstance().tracer;
/** 回覆訊息 (ReplyToActivity) */
public static async replyToActivity(req: express.Request, res: express.Response) {
// 其他的程式碼 ...
// 1.建立 Span (檢查是否有 Parent Span)
const operationName = 'replyToActivity';
// 取得是否有傳進來的 tracer id (parentSpanContext)
const parentSpanContext = tracer.extract(opentracing.FORMAT_HTTP_HEADERS, req.headers)
const span = tracer.startSpan(operationName, { childOf: parentSpanContext });
const ctx = {span};
// 2.記錄一些 Tags
span.setTag('channelId',`activity.channelId`);
span.setTag('botId', `botId`);
span.setTag('convId',`convId`);
span.setTag('userId',`activity.recipient.id`);
try{
// 將目前的 span 傳給被呼叫的 Method
await ConversationController.sendActivityToChannel(activity, convId, ctx);
// 3.Log 一些相關資料
// span.log({
// botId,
// activity
// });
}catch(ex){
// 4.設定為錯誤
span.setTag(opentracing.Tags.ERROR, true);
span.log({'errMsg':ex});
// 其他要做的事
// ...
}
finally{
// 5.最後一定要呼叫 span.finish()
span.finish();
}
// 其他的程式碼 ...
}
/** 將訊息送給各個Channel */
protected static async sendActivityToChannel(activity: IActivity, convId: string, ctx?:any) {
// 其他的程式碼 ...
// 1.建立 Span (檢查是否有 Parent Span)
const operationName = 'sendActivityToChannel';
// 取得是否有傳進來的 tracer id (parentSpanContext)
let parentSpanContext = null;
if(ctx && ctx.span){
parentSpanContext = ctx.span;
}
const span = tracer.startSpan(operationName, { childOf: parentSpanContext });
// 要傳給 call 的 method
ctx = {span};
// 如果要 call http 的話,要給目前的 tracer id
// Send span context via request headers (parent id etc.)
const headers = {};
tracer.inject(span, opentracing.FORMAT_HTTP_HEADERS, headers);
try{
// 2.記錄一些 Tags
span.setTag('channelId',`activity.channelId`);
span.setTag('botId', `botId`);
span.setTag('convId',`convId`);
span.setTag('userId',`activity.recipient.id`);
// call http api ...
// 3.Log 一些相關資料
// span.log({
// botId,
// activity
// });
}catch(ex){
// 4.設定為錯誤
span.setTag(opentracing.Tags.ERROR, true);
span.log({'errMsg':ex});
}
finally{
// 5.最後一定要呼叫 span.finish()
span.finish();
}
// 其他的程式碼 ...
}
private async Task<Activity> HandleMessage(Activity activity)
{
var tracer = GlobalTracer.Instance;
// 1. 建立 span
var headers = Request.Headers.ToDictionary(k => k.Key, v => v.Value.First());
ISpanBuilder spanBuilder;
const string operationName = "MessageController-HandleMessage";
try
{
ISpanContext parentSpanCtx = tracer.Extract(BuiltinFormats.HttpHeaders, new TextMapExtractAdapter(headers));
spanBuilder = tracer.BuildSpan(operationName);
if (parentSpanCtx != null)
{
spanBuilder = spanBuilder.AsChildOf(parentSpanCtx);
}
}
catch (Exception)
{
spanBuilder = tracer.BuildSpan(operationName);
}
using (var scope = spanBuilder.StartActive(true))
{
try
{
// 其他的程式碼 ...
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
// 2.記錄一些 Tags
scope.Span.SetTag("channelId", activity.ChannelId);
scope.Span.SetTag("botId", activity.Recipient.Id);
scope.Span.SetTag("userId", activity.From.Id);
// 3.Log 一些相關資料
scope.Span.Log(new Dictionary<string, object>
{
["botId"] = activity.From.Id,
["activity"] = JsonConvert.SerializeObject(activity)
});
}
catch(Exception ex)
{
// 4.設定為錯誤
Tags.Error.Set(scope.Span, true);
scope.Span.Log(new Dictionary<string, object>
{
["errMsg"] = ex.ToString()
});
}
}
return activity;
}
var tracer = GlobalTracer.Instance;
const string operationName = "RootDialog-MessageReceivedAsync";
var spanBuilder = tracer.BuildSpan(operationName);
if (tracer.ActiveSpan != null)
spanBuilder.AsChildOf(tracer.ActiveSpan);
using (var scope = spanBuilder.StartActive(true))
{
// 其他的程式碼 ...
}
//add opentracing
var tracer = GlobalTracer.Instance;
var dictionary = new Dictionary<string, string>();
var span = tracer.ActiveSpan;
if (span != null)
{
tracer.Inject(span.Context, BuiltinFormats.HttpHeaders, new TextMapInjectAdapter(dictionary));
foreach (var entry in dictionary)
HttpClient.DefaultRequestHeaders.Add(entry.Key, entry.Value);
}