1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2017-2020 Couchbase, Inc.
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 
18 #include "internal.h"
19 #include "sllist-inl.h"
20 #ifdef HAVE__FTIME64_S
21 #include <sys/timeb.h>
22 #endif
23 
24 #include "n1ql/query_handle.hh"
25 
26 typedef enum { TAGVAL_STRING, TAGVAL_UINT64, TAGVAL_DOUBLE, TAGVAL_BOOL } tag_type;
27 typedef struct tag_value {
28     sllist_node slnode;
29     struct {
30         char *p;
31         int need_free;
32     } key;
33     tag_type t;
34     union {
35         struct {
36             char *p;
37             size_t l;
38             int need_free;
39         } s;
40         lcb_U64 u64;
41         double d;
42         int b;
43     } v;
44 } tag_value;
45 
46 LIBCOUCHBASE_API
lcbtrace_now()47 uint64_t lcbtrace_now()
48 {
49     uint64_t ret;
50 #ifdef HAVE__FTIME64_S
51     struct __timeb64 tb;
52     _ftime64_s(&tb);
53     ret = (uint64_t)tb.time * 1000000; /* sec */
54     ret += (uint64_t)tb.millitm * 1000;
55 #else
56     struct timeval tv {
57     };
58     if (gettimeofday(&tv, nullptr) == -1) {
59         return -1;
60     }
61     ret = (uint64_t)tv.tv_sec * 1000000;
62     ret += (uint64_t)tv.tv_usec;
63 #endif
64     return ret;
65 }
66 
67 LIBCOUCHBASE_API
lcbtrace_span_finish(lcbtrace_SPAN *span, uint64_t now)68 void lcbtrace_span_finish(lcbtrace_SPAN *span, uint64_t now)
69 {
70     if (!span) {
71         return;
72     }
73 
74     span->finish(now);
75     delete span;
76 }
77 
78 LIBCOUCHBASE_API
lcbtrace_span_should_finish(lcbtrace_SPAN *span)79 int lcbtrace_span_should_finish(lcbtrace_SPAN *span)
80 {
81     if (!span) {
82         return false;
83     }
84 
85     return span->should_finish();
86 }
87 
88 LIBCOUCHBASE_API
lcbtrace_span_add_tag_str_nocopy(lcbtrace_SPAN *span, const char *name, const char *value)89 void lcbtrace_span_add_tag_str_nocopy(lcbtrace_SPAN *span, const char *name, const char *value)
90 {
91     if (!span || name == nullptr || value == nullptr) {
92         return;
93     }
94     span->add_tag(name, 0, value, 0);
95 }
96 
97 LIBCOUCHBASE_API
lcbtrace_span_add_tag_str(lcbtrace_SPAN *span, const char *name, const char *value)98 void lcbtrace_span_add_tag_str(lcbtrace_SPAN *span, const char *name, const char *value)
99 {
100     if (!span || name == nullptr || value == nullptr) {
101         return;
102     }
103     span->add_tag(name, 1, value, 1);
104 }
105 
106 LIBCOUCHBASE_API
lcbtrace_span_add_tag_uint64(lcbtrace_SPAN *span, const char *name, uint64_t value)107 void lcbtrace_span_add_tag_uint64(lcbtrace_SPAN *span, const char *name, uint64_t value)
108 {
109     if (!span || name == nullptr) {
110         return;
111     }
112     span->add_tag(name, 1, value);
113 }
114 
115 LIBCOUCHBASE_API
lcbtrace_span_add_tag_double(lcbtrace_SPAN *span, const char *name, double value)116 void lcbtrace_span_add_tag_double(lcbtrace_SPAN *span, const char *name, double value)
117 {
118     if (!span || name == nullptr) {
119         return;
120     }
121     span->add_tag(name, 1, value);
122 }
123 
124 LIBCOUCHBASE_API
lcbtrace_span_add_tag_bool(lcbtrace_SPAN *span, const char *name, int value)125 void lcbtrace_span_add_tag_bool(lcbtrace_SPAN *span, const char *name, int value)
126 {
127     if (!span || name == nullptr) {
128         return;
129     }
130     span->add_tag(name, 1, (bool)value);
131 }
132 
133 LCB_INTERNAL_API
lcbtrace_span_add_system_tags(lcbtrace_SPAN *span, const lcb_settings *settings, lcbtrace_THRESHOLDOPTS svc)134 void lcbtrace_span_add_system_tags(lcbtrace_SPAN *span, const lcb_settings *settings, lcbtrace_THRESHOLDOPTS svc)
135 {
136     if (!span) {
137         return;
138     }
139     if (svc != LCBTRACE_THRESHOLD__MAX) {
140         span->service(svc);
141     }
142     span->add_tag(LCBTRACE_TAG_SYSTEM, 0, "couchbase", 0);
143     span->add_tag(LCBTRACE_TAG_TRANSPORT, 0, "IP.TCP", 0);
144     std::string client_string(LCB_CLIENT_ID);
145     if (settings->client_string) {
146         client_string += " ";
147         client_string += settings->client_string;
148     }
149     span->add_tag(LCBTRACE_TAG_COMPONENT, 0, client_string.c_str(), client_string.size(), 1);
150     if (settings->bucket) {
151         span->add_tag(LCBTRACE_TAG_DB_INSTANCE, 0, settings->bucket, 0);
152     }
153 }
154 
155 LIBCOUCHBASE_API
lcbtrace_span_get_parent(lcbtrace_SPAN *span)156 lcbtrace_SPAN *lcbtrace_span_get_parent(lcbtrace_SPAN *span)
157 {
158     if (!span) {
159         return nullptr;
160     }
161     return span->m_parent;
162 }
163 
164 LIBCOUCHBASE_API
lcbtrace_span_get_start_ts(lcbtrace_SPAN *span)165 uint64_t lcbtrace_span_get_start_ts(lcbtrace_SPAN *span)
166 {
167     if (!span) {
168         return 0;
169     }
170     return span->m_start;
171 }
172 
173 LIBCOUCHBASE_API
lcbtrace_span_get_finish_ts(lcbtrace_SPAN *span)174 uint64_t lcbtrace_span_get_finish_ts(lcbtrace_SPAN *span)
175 {
176     if (!span) {
177         return 0;
178     }
179     return span->m_finish;
180 }
181 
182 LIBCOUCHBASE_API
lcbtrace_span_is_orphaned(lcbtrace_SPAN *span)183 int lcbtrace_span_is_orphaned(lcbtrace_SPAN *span)
184 {
185     return span && span->m_orphaned;
186 }
187 
188 LCB_INTERNAL_API
lcbtrace_span_set_orphaned(lcbtrace_SPAN *span, int val)189 void lcbtrace_span_set_orphaned(lcbtrace_SPAN *span, int val)
190 {
191     if (!span) {
192         return;
193     }
194     span->m_orphaned = (val != 0);
195     if (val != 0 && span->m_parent && span->m_parent->is_outer()) {
196         span->m_parent->m_orphaned = true;
197     }
198 }
199 
200 LIBCOUCHBASE_API
lcbtrace_span_get_span_id(lcbtrace_SPAN *span)201 uint64_t lcbtrace_span_get_span_id(lcbtrace_SPAN *span)
202 {
203     if (!span) {
204         return 0;
205     }
206     return span->m_span_id;
207 }
208 
209 LIBCOUCHBASE_API
lcbtrace_span_get_operation(lcbtrace_SPAN *span)210 const char *lcbtrace_span_get_operation(lcbtrace_SPAN *span)
211 {
212     if (!span) {
213         return nullptr;
214     }
215     return span->m_opname.c_str();
216 }
217 
218 LIBCOUCHBASE_API
lcbtrace_span_get_trace_id(lcbtrace_SPAN *span)219 uint64_t lcbtrace_span_get_trace_id(lcbtrace_SPAN *span)
220 {
221     if (!span) {
222         return 0;
223     }
224     if (span->m_parent) {
225         return span->m_parent->m_span_id;
226     }
227     return span->m_span_id;
228 }
229 
230 LIBCOUCHBASE_API
lcbtrace_span_get_tag_str(lcbtrace_SPAN *span, const char *name, char **value, size_t *nvalue)231 lcb_STATUS lcbtrace_span_get_tag_str(lcbtrace_SPAN *span, const char *name, char **value, size_t *nvalue)
232 {
233     if (!span || name == nullptr || nvalue == nullptr || value == nullptr) {
234         return LCB_ERR_INVALID_ARGUMENT;
235     }
236 
237     sllist_iterator iter;
238     SLLIST_ITERFOR(&span->m_tags, &iter)
239     {
240         tag_value *val = SLLIST_ITEM(iter.cur, tag_value, slnode);
241         if (strcmp(name, val->key.p) == 0) {
242             if (val->t != TAGVAL_STRING) {
243                 return LCB_ERR_INVALID_ARGUMENT;
244             }
245             *value = val->v.s.p;
246             *nvalue = val->v.s.l;
247             return LCB_SUCCESS;
248         }
249     }
250 
251     return LCB_ERR_DOCUMENT_NOT_FOUND;
252 }
253 
lcbtrace_span_get_tag_uint64(lcbtrace_SPAN *span, const char *name, uint64_t *value)254 LIBCOUCHBASE_API lcb_STATUS lcbtrace_span_get_tag_uint64(lcbtrace_SPAN *span, const char *name, uint64_t *value)
255 {
256     if (!span || name == nullptr || value == nullptr) {
257         return LCB_ERR_INVALID_ARGUMENT;
258     }
259 
260     sllist_iterator iter;
261     SLLIST_ITERFOR(&span->m_tags, &iter)
262     {
263         tag_value *val = SLLIST_ITEM(iter.cur, tag_value, slnode);
264         if (strcmp(name, val->key.p) == 0) {
265             if (val->t != TAGVAL_UINT64) {
266                 return LCB_ERR_INVALID_ARGUMENT;
267             }
268             *value = val->v.u64;
269             return LCB_SUCCESS;
270         }
271     }
272 
273     return LCB_ERR_DOCUMENT_NOT_FOUND;
274 }
275 
lcbtrace_span_get_tag_double(lcbtrace_SPAN *span, const char *name, double *value)276 LIBCOUCHBASE_API lcb_STATUS lcbtrace_span_get_tag_double(lcbtrace_SPAN *span, const char *name, double *value)
277 {
278     if (!span || name == nullptr || value == nullptr) {
279         return LCB_ERR_INVALID_ARGUMENT;
280     }
281 
282     sllist_iterator iter;
283     SLLIST_ITERFOR(&span->m_tags, &iter)
284     {
285         tag_value *val = SLLIST_ITEM(iter.cur, tag_value, slnode);
286         if (strcmp(name, val->key.p) == 0) {
287             if (val->t != TAGVAL_DOUBLE) {
288                 return LCB_ERR_INVALID_ARGUMENT;
289             }
290             *value = val->v.d;
291             return LCB_SUCCESS;
292         }
293     }
294 
295     return LCB_ERR_DOCUMENT_NOT_FOUND;
296 }
297 
lcbtrace_span_get_tag_bool(lcbtrace_SPAN *span, const char *name, int *value)298 LIBCOUCHBASE_API lcb_STATUS lcbtrace_span_get_tag_bool(lcbtrace_SPAN *span, const char *name, int *value)
299 {
300     if (!span || name == nullptr || value == nullptr) {
301         return LCB_ERR_INVALID_ARGUMENT;
302     }
303 
304     sllist_iterator iter;
305     SLLIST_ITERFOR(&span->m_tags, &iter)
306     {
307         tag_value *val = SLLIST_ITEM(iter.cur, tag_value, slnode);
308         if (strcmp(name, val->key.p) == 0) {
309             if (val->t != TAGVAL_BOOL) {
310                 return LCB_ERR_INVALID_ARGUMENT;
311             }
312             *value = val->v.b;
313             return LCB_SUCCESS;
314         }
315     }
316 
317     return LCB_ERR_DOCUMENT_NOT_FOUND;
318 }
319 
lcbtrace_span_has_tag(lcbtrace_SPAN *span, const char *name)320 LIBCOUCHBASE_API int lcbtrace_span_has_tag(lcbtrace_SPAN *span, const char *name)
321 {
322     if (!span || name == nullptr) {
323         return 0;
324     }
325 
326     sllist_iterator iter;
327     SLLIST_ITERFOR(&span->m_tags, &iter)
328     {
329         tag_value *val = SLLIST_ITEM(iter.cur, tag_value, slnode);
330         if (strcmp(name, val->key.p) == 0) {
331             return 1;
332         }
333     }
334     return 0;
335 }
336 
lcbtrace_span_get_service(lcbtrace_SPAN *span, lcbtrace_SERVICE *svc)337 LIBCOUCHBASE_API lcb_STATUS lcbtrace_span_get_service(lcbtrace_SPAN *span, lcbtrace_SERVICE *svc)
338 {
339     if (nullptr == span) {
340         return LCB_ERR_INVALID_ARGUMENT;
341     }
342     *svc = static_cast<lcbtrace_SERVICE>(span->service());
343     return LCB_SUCCESS;
344 }
345 
lcbtrace_span_set_service(lcbtrace_SPAN *span, lcbtrace_SERVICE svc)346 LIBCOUCHBASE_API lcb_STATUS lcbtrace_span_set_service(lcbtrace_SPAN *span, lcbtrace_SERVICE svc)
347 {
348     if (nullptr == span) {
349         return LCB_ERR_INVALID_ARGUMENT;
350     }
351     span->service(static_cast<lcbtrace_THRESHOLDOPTS>(svc));
352     return LCB_SUCCESS;
353 }
354 
lcbtrace_span_set_is_dispatch(lcbtrace_SPAN *span, int dispatch)355 LIBCOUCHBASE_API lcb_STATUS lcbtrace_span_set_is_dispatch(lcbtrace_SPAN *span, int dispatch)
356 {
357     if (nullptr == span) {
358         return LCB_ERR_INVALID_ARGUMENT;
359     }
360     span->is_dispatch((bool)dispatch);
361     return LCB_SUCCESS;
362 }
363 
lcbtrace_span_set_is_outer(lcbtrace_SPAN *span, int outer)364 LIBCOUCHBASE_API lcb_STATUS lcbtrace_span_set_is_outer(lcbtrace_SPAN *span, int outer)
365 {
366     if (nullptr == span) {
367         return LCB_ERR_INVALID_ARGUMENT;
368     }
369     span->is_outer((bool)outer);
370     return LCB_SUCCESS;
371 }
372 
lcbtrace_span_set_is_encode(lcbtrace_SPAN *span, int encode)373 LIBCOUCHBASE_API lcb_STATUS lcbtrace_span_set_is_encode(lcbtrace_SPAN *span, int encode)
374 {
375     if (nullptr == span) {
376         return LCB_ERR_INVALID_ARGUMENT;
377     }
378     span->is_encode((bool)encode);
379     return LCB_SUCCESS;
380 }
381 
lcbtrace_span_get_is_dispatch(lcbtrace_SPAN *span, int *dispatch)382 LIBCOUCHBASE_API lcb_STATUS lcbtrace_span_get_is_dispatch(lcbtrace_SPAN *span, int *dispatch)
383 {
384     if (nullptr == span) {
385         return LCB_ERR_INVALID_ARGUMENT;
386     }
387     *dispatch = span->is_dispatch() ? 1 : 0;
388     return LCB_SUCCESS;
389 }
390 
lcbtrace_span_get_is_outer(lcbtrace_SPAN *span, int *outer)391 LIBCOUCHBASE_API lcb_STATUS lcbtrace_span_get_is_outer(lcbtrace_SPAN *span, int *outer)
392 {
393     if (nullptr == span) {
394         return LCB_ERR_INVALID_ARGUMENT;
395     }
396     *outer = span->is_outer() ? 1 : 0;
397     return LCB_SUCCESS;
398 }
399 
lcbtrace_span_get_is_encode(lcbtrace_SPAN *span, int *encode)400 LIBCOUCHBASE_API lcb_STATUS lcbtrace_span_get_is_encode(lcbtrace_SPAN *span, int *encode)
401 {
402     if (nullptr == span) {
403         return LCB_ERR_INVALID_ARGUMENT;
404     }
405     *encode = span->is_encode() ? 1 : 0;
406     return LCB_SUCCESS;
407 }
408 
409 namespace lcb
410 {
411 namespace trace
412 {
finish_kv_span(const mc_PIPELINE *pipeline, const mc_PACKET *request_pkt, const lcb::MemcachedResponse *response_pkt)413 void finish_kv_span(const mc_PIPELINE *pipeline, const mc_PACKET *request_pkt,
414                     const lcb::MemcachedResponse *response_pkt)
415 {
416     lcbtrace_SPAN *dispatch_span = MCREQ_PKT_RDATA(request_pkt)->span;
417     if (dispatch_span) {
418         if (response_pkt != nullptr) {
419             dispatch_span->increment_server(response_pkt->duration());
420         }
421         auto *server = static_cast<const lcb::Server *>(pipeline);
422         dispatch_span->find_outer_or_this()->add_tag(LCBTRACE_TAG_RETRIES, 0, (uint64_t)request_pkt->retries);
423         lcbtrace_span_add_tag_str_nocopy(dispatch_span, LCBTRACE_TAG_TRANSPORT, "IP.TCP");
424         lcbio_CTX *ctx = server->connctx;
425         if (ctx) {
426             char local_id[34] = {};
427             snprintf(local_id, sizeof(local_id), "%016" PRIx64 "/%016" PRIx64, (uint64_t)server->get_settings()->iid,
428                      (uint64_t)ctx->sock->id);
429             lcbtrace_span_add_tag_str(dispatch_span, LCBTRACE_TAG_LOCAL_ID, local_id);
430             lcbtrace_span_add_host_and_port(dispatch_span, ctx->sock->info);
431         }
432         if (dispatch_span->should_finish()) {
433             lcbtrace_span_finish(dispatch_span, LCBTRACE_NOW);
434         }
435     }
436 }
437 
438 } // namespace trace
439 } // namespace lcb
440 
441 using namespace lcb::trace;
442 
Span(lcbtrace_TRACER *tracer, const char *opname, uint64_t start, lcbtrace_REF_TYPE ref, lcbtrace_SPAN *other, void *external_span)443 Span::Span(lcbtrace_TRACER *tracer, const char *opname, uint64_t start, lcbtrace_REF_TYPE ref, lcbtrace_SPAN *other,
444            void *external_span)
445     : m_tracer(tracer), m_opname(opname), m_extspan(external_span)
446 {
447     if (other != nullptr && ref == LCBTRACE_REF_CHILD_OF) {
448         m_parent = other;
449     } else {
450         m_parent = nullptr;
451     }
452     if (nullptr == m_extspan && nullptr != tracer && tracer->version == 1 && nullptr != tracer->v.v1.start_span) {
453         void *parent = other == nullptr ? nullptr : other->external_span();
454         m_extspan = tracer->v.v1.start_span(tracer, opname, parent);
455     } else {
456         m_start = start ? start : lcbtrace_now();
457         m_span_id = lcb_next_rand64();
458         m_orphaned = false;
459         memset(&m_tags, 0, sizeof(m_tags));
460         if (nullptr == m_extspan) {
461             add_tag(LCBTRACE_TAG_SYSTEM, 0, "couchbase", 0);
462             add_tag(LCBTRACE_TAG_SPAN_KIND, 0, "client", 0);
463         }
464     }
465 }
466 
~Span()467 Span::~Span()
468 {
469     if (nullptr != m_extspan) {
470         // call external span destructor fn
471         if (nullptr != m_tracer && m_tracer->version == 1 && nullptr != m_tracer->v.v1.destroy_span) {
472             m_tracer->v.v1.destroy_span(m_extspan);
473             m_extspan = nullptr;
474         }
475     } else {
476         sllist_iterator iter;
477         SLLIST_ITERFOR(&m_tags, &iter)
478         {
479             tag_value *val = SLLIST_ITEM(iter.cur, tag_value, slnode);
480             sllist_iter_remove(&m_tags, &iter);
481             if (val->key.need_free) {
482                 free(val->key.p);
483             }
484             if (val->t == TAGVAL_STRING && val->v.s.need_free) {
485                 free(val->v.s.p);
486             }
487             free(val);
488         }
489     }
490 }
491 
service(lcbtrace_THRESHOLDOPTS svc)492 void Span::service(lcbtrace_THRESHOLDOPTS svc)
493 {
494     m_svc = svc;
495     switch (svc) {
496         case LCBTRACE_THRESHOLD_KV:
497             m_svc_string = LCBTRACE_TAG_SERVICE_KV;
498             break;
499         case LCBTRACE_THRESHOLD_QUERY:
500             m_svc_string = LCBTRACE_TAG_SERVICE_N1QL;
501             break;
502         case LCBTRACE_THRESHOLD_VIEW:
503             m_svc_string = LCBTRACE_TAG_SERVICE_VIEW;
504             break;
505         case LCBTRACE_THRESHOLD_SEARCH:
506             m_svc_string = LCBTRACE_TAG_SERVICE_SEARCH;
507             break;
508         case LCBTRACE_THRESHOLD_ANALYTICS:
509             m_svc_string = LCBTRACE_TAG_SERVICE_ANALYTICS;
510             break;
511         default:
512             m_svc_string = nullptr;
513     }
514     if (m_tracer && m_tracer->version != 0 && m_svc_string) {
515         add_tag(LCBTRACE_TAG_SERVICE, 0, m_svc_string, 0);
516     }
517 }
518 
service() const519 lcbtrace_THRESHOLDOPTS Span::service() const
520 {
521     return m_svc;
522 }
523 
service_str() const524 const char *Span::service_str() const
525 {
526     return m_svc_string;
527 }
528 
external_span() const529 void *Span::external_span() const
530 {
531     return m_extspan;
532 }
533 
increment_dispatch(uint64_t dispatch)534 void Span::increment_dispatch(uint64_t dispatch)
535 {
536     // outer span needs this for threshold logging only
537     Span *outer = find_outer_or_this();
538     outer->m_total_dispatch += dispatch;
539     outer->m_last_dispatch = dispatch;
540 }
541 
increment_server(uint64_t server)542 void Span::increment_server(uint64_t server)
543 {
544     // outer span needs this for threshold logging only
545     Span *outer = find_outer_or_this();
546     outer->m_total_server += server;
547     outer->m_last_server = server;
548     // but this span needs the tag always
549     add_tag(LCBTRACE_TAG_PEER_LATENCY, 0, server);
550 }
551 
find_outer_or_this()552 lcbtrace_SPAN *Span::find_outer_or_this()
553 {
554     lcbtrace_SPAN *outer = this;
555     while (outer->m_parent != nullptr && !outer->is_outer()) {
556         outer = outer->m_parent;
557     }
558     return outer;
559 }
560 
external_span(void *extspan)561 void Span::external_span(void *extspan)
562 {
563     m_extspan = extspan;
564 }
565 
is_dispatch() const566 bool Span::is_dispatch() const
567 {
568     return m_is_dispatch;
569 }
570 
is_dispatch(bool dispatch)571 void Span::is_dispatch(bool dispatch)
572 {
573     m_is_dispatch = dispatch;
574 }
575 
is_encode() const576 bool Span::is_encode() const
577 {
578     return m_is_encode;
579 }
580 
is_encode(bool encode)581 void Span::is_encode(bool encode)
582 {
583     m_is_encode = encode;
584 }
585 
is_outer() const586 bool Span::is_outer() const
587 {
588     return m_is_outer;
589 }
590 
is_outer(bool outer)591 void Span::is_outer(bool outer)
592 {
593     m_is_outer = outer;
594 }
595 
should_finish(bool finish)596 void Span::should_finish(bool finish)
597 {
598     m_should_finish = finish;
599 }
600 
should_finish() const601 bool Span::should_finish() const
602 {
603     // don't call finish on outer spans if external tracer is being used.
604     return m_should_finish;
605 }
606 
finish(uint64_t now)607 void Span::finish(uint64_t now)
608 {
609     if (m_tracer && m_tracer->version == 1) {
610         if (m_extspan != nullptr && m_tracer->v.v1.end_span != nullptr) {
611             m_tracer->v.v1.end_span(m_extspan);
612             return;
613         }
614     }
615     m_finish = now ? now : lcbtrace_now();
616     if (m_tracer && m_tracer->version == 0) {
617         if (m_tracer->v.v0.report) {
618             m_tracer->v.v0.report(m_tracer, this);
619         }
620     }
621 }
622 
add_tag(const char *name, int copy_key, const char *value, int copy_value)623 void Span::add_tag(const char *name, int copy_key, const char *value, int copy_value)
624 {
625     if (name && value) {
626         add_tag(name, copy_key, value, strlen(value), copy_value);
627     }
628 }
629 
add_tag(const char *name, const std::string &value)630 void Span::add_tag(const char *name, const std::string &value)
631 {
632     if (name != nullptr && !value.empty()) {
633         add_tag(name, 0, value.c_str(), value.size(), 1);
634     }
635 }
636 
add_tag(const char *name, int copy_key, const char *value, size_t value_len, int copy_value)637 void Span::add_tag(const char *name, int copy_key, const char *value, size_t value_len, int copy_value)
638 {
639     if (nullptr != m_extspan && nullptr != m_tracer) {
640         if (1 == m_tracer->version && m_tracer->v.v1.add_tag_string) {
641             // this always copies the key and value
642             m_tracer->v.v1.add_tag_string(m_extspan, name, value, value_len);
643         }
644         return;
645     }
646     if (m_is_dispatch && m_parent && m_parent->is_outer()) {
647         m_parent->add_tag(name, copy_key, value, value_len, copy_value);
648         return;
649     }
650     auto *val = (tag_value *)calloc(1, sizeof(tag_value));
651     val->t = TAGVAL_STRING;
652     val->key.need_free = copy_key;
653     if (copy_key) {
654         val->key.p = lcb_strdup(name);
655     } else {
656         val->key.p = (char *)name;
657     }
658     val->v.s.need_free = copy_value;
659     val->v.s.l = value_len;
660     if (copy_value) {
661         val->v.s.p = (char *)calloc(value_len, sizeof(char));
662         memcpy(val->v.s.p, value, value_len);
663     } else {
664         val->v.s.p = (char *)value;
665     }
666     sllist_append(&m_tags, &val->slnode);
667 }
668 
add_tag(const char *name, int copy, uint64_t value)669 void Span::add_tag(const char *name, int copy, uint64_t value)
670 {
671     if (nullptr != m_extspan && nullptr != m_tracer) {
672         if (1 == m_tracer->version && m_tracer->v.v1.add_tag_string) {
673             m_tracer->v.v1.add_tag_uint64(m_extspan, name, value);
674         }
675         return;
676     }
677     if (m_is_dispatch && m_parent && m_parent->is_outer()) {
678         m_parent->add_tag(name, copy, value);
679         return;
680     }
681     auto *val = (tag_value *)calloc(1, sizeof(tag_value));
682     val->t = TAGVAL_UINT64;
683     val->key.need_free = copy;
684     if (copy) {
685         val->key.p = lcb_strdup(name);
686     } else {
687         val->key.p = (char *)name;
688     }
689     val->v.u64 = value;
690     sllist_append(&m_tags, &val->slnode);
691 }
692 
add_tag(const char *name, int copy, double value)693 void Span::add_tag(const char *name, int copy, double value)
694 {
695     if (m_is_dispatch && m_parent && m_parent->is_outer()) {
696         m_parent->add_tag(name, copy, value);
697         return;
698     }
699     auto *val = (tag_value *)calloc(1, sizeof(tag_value));
700     val->t = TAGVAL_DOUBLE;
701     val->key.need_free = copy;
702     if (copy) {
703         val->key.p = lcb_strdup(name);
704     } else {
705         val->key.p = (char *)name;
706     }
707     val->v.d = value;
708     sllist_append(&m_tags, &val->slnode);
709 }
710 
add_tag(const char *name, int copy, bool value)711 void Span::add_tag(const char *name, int copy, bool value)
712 {
713     if (m_is_dispatch && m_parent && m_parent->is_outer()) {
714         m_parent->add_tag(name, copy, value);
715         return;
716     }
717     auto *val = (tag_value *)calloc(1, sizeof(tag_value));
718     val->t = TAGVAL_BOOL;
719     val->key.need_free = copy;
720     if (copy) {
721         val->key.p = lcb_strdup(name);
722     } else {
723         val->key.p = (char *)name;
724     }
725     val->v.b = value;
726     sllist_append(&m_tags, &val->slnode);
727 }
728