1 module hunt.trace.Span;
2 
3 import hunt.trace.Endpoint;
4 import hunt.trace.Constrants;
5 import hunt.trace.Annotation;
6 import hunt.trace.Helpers;
7 
8 import hunt.logging.ConsoleLogger;
9 import hunt.util.Serialize;
10 
11 import std.json;
12 import std.range;
13 import std.socket;
14 import std.string;
15 
16 /**
17  * 
18  */
19 class Span {
20 
21     /// 16bytes
22     string traceId;
23     string name;
24     @IGNORE string parentId;
25     /// 8bytes
26     string id;
27     string kind;
28     long timestamp;
29     long duration;
30     @IGNORE bool debug_;
31     @IGNORE bool shared_;
32 
33     EndPoint localEndpoint;
34     EndPoint remoteEndpoint;
35     Annotation[] annotations;
36     string[string] tags;
37 
38     string samplingState = "1";
39 
40     string defaultId() {
41         // b3={TraceId}-{SpanId}-{SamplingState}-{ParentSpanId}
42         if(parentId.empty) {
43             return traceId ~ "-" ~ id ~ "-" ~ samplingState;
44         } else {
45             return traceId ~ "-" ~ id ~ "-" ~ samplingState ~ "-" ~ parentId;
46         }
47     }
48 
49     void addTag(string key, string value) {
50         tags[key] = value;
51     }
52 
53     void addAnnotation(string value, long timestamp = 0) {
54         auto anno = new Annotation();
55         anno.value = value;
56         if (timestamp == 0)
57             timestamp = usecs;
58         anno.timestamp = timestamp;
59         annotations ~= anno;
60     }
61 
62     void start(long timestamp = 0) {
63         if (timestamp != 0)
64             this.timestamp = timestamp;
65         else
66             this.timestamp = usecs;
67     }
68 
69     void finish(long timestamp = 0) {
70         if (timestamp != 0)
71             this.duration = timestamp - this.timestamp;
72         else
73             this.duration = usecs - this.timestamp;
74 
75     }
76 
77     static EndPoint buildLocalEndPoint(string name) {
78         EndPoint endpoint = new EndPoint();
79         endpoint.serviceName = name;
80 
81         try {
82             auto addresses = getAddress("localhost");
83             foreach (address; addresses) {
84                 // writefln("  IP: %s", address.toAddrString());
85                 string ip = address.toAddrString();
86                 if(ip.startsWith("::")) {
87                     // localEndpoint.ipv6 = ip; // todo
88                 } else {
89                     endpoint.ipv4 = ip;
90                 }
91             }
92         } catch(Exception ex) {
93             warning(ex.msg);
94         }
95 
96         return endpoint;
97     }
98 
99     override string toString() {
100         auto json = toJson(this);
101         json["debug"] = (debug_);
102         json["shared"] = (shared_);
103 
104         // import hunt.logging.ConsoleLogger;
105         // warning("parentId: ", parentId);
106         // warning("traceId: ", traceId);
107         if (parentId.length != 0)
108             json["parentId"] = parentId;
109         return json.toString;
110     }
111 }
112 
113 
114 
115 void traceSpanAfter(Span span, string[string] tags, string error = "") {
116     assert(span !is null);
117     
118     foreach (k, v; tags) {
119         span.addTag(k, v);
120     }
121 
122     if (error != "") {
123         span.addTag(SPAN_ERROR, error);
124     }
125     span.finish();
126 
127     // warning(span.toString());
128 }