blob: b1bcb61d243496cf4b9770840ca87735c1c9921b [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "core/conf.h"
#include "core/htrace.h"
#include "core/htracer.h"
#include "core/scope.h"
#include "core/span.h"
#include "receiver/receiver.h"
#include "util/log.h"
#include "util/rand.h"
#include "util/string.h"
#include "util/tracer_id.h"
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/**
* @file htracer.c
*
* Implementation of the Tracer object.
*/
struct htracer *htracer_create(const char *tname,
const struct htrace_conf *cnf)
{
struct htracer *tracer;
int ret;
tracer = calloc(1, sizeof(*tracer));
if (!tracer) {
return NULL;
}
tracer->lg = htrace_log_alloc(cnf);
if (!tracer->lg) {
free(tracer);
return NULL;
}
ret = pthread_key_create(&tracer->tls, NULL);
if (ret) {
htrace_log(tracer->lg, "htracer_create: pthread_key_create "
"failed: %s.\n", terror(ret));
htrace_log_free(tracer->lg);
return NULL;
}
tracer->tname = strdup(tname);
if (!tracer->tname) {
htrace_log(tracer->lg, "htracer_create: failed to "
"duplicate name string.\n");
htracer_free(tracer);
return NULL;
}
tracer->trid = calculate_tracer_id(tracer->lg,
htrace_conf_get(cnf, HTRACE_TRACER_ID), tname);
if (!tracer->trid) {
htrace_log(tracer->lg, "htracer_create: failed to "
"create process id string.\n");
htracer_free(tracer);
return NULL;
}
if (!validate_json_string(tracer->lg, tracer->trid)) {
htrace_log(tracer->lg, "htracer_create: process ID string '%s' is "
"problematic.\n", tracer->trid);
htracer_free(tracer);
return NULL;
}
tracer->rnd = random_src_alloc(tracer->lg);
if (!tracer->rnd) {
htrace_log(tracer->lg, "htracer_create: failed to "
"allocate a random source.\n");
htracer_free(tracer);
return NULL;
}
tracer->rcv = htrace_rcv_create(tracer, cnf);
if (!tracer->rcv) {
htrace_log(tracer->lg, "htracer_create: failed to "
"create a receiver.\n");
htracer_free(tracer);
return NULL;
}
return tracer;
}
const char *htracer_tname(const struct htracer *tracer)
{
return tracer->tname;
}
void htracer_free(struct htracer *tracer)
{
struct htrace_rcv *rcv;
if (!tracer) {
return;
}
pthread_key_delete(tracer->tls);
rcv = tracer->rcv;
if (rcv) {
rcv->ty->free(rcv);
}
random_src_free(tracer->rnd);
free(tracer->tname);
free(tracer->trid);
htrace_log_free(tracer->lg);
free(tracer);
}
struct htrace_scope *htracer_cur_scope(struct htracer *tracer)
{
return pthread_getspecific(tracer->tls);
}
int htracer_push_scope(struct htracer *tracer, struct htrace_scope *cur,
struct htrace_scope *next)
{
int ret;
next->parent = cur;
ret = pthread_setspecific(tracer->tls, next);
if (ret) {
htrace_log(tracer->lg, "htracer_push_scope: pthread_setspecific "
"failed: %s\n", terror(ret));
return EIO;
}
return 0;
}
int htracer_pop_scope(struct htracer *tracer, struct htrace_scope *scope)
{
struct htrace_scope *cur_scope;
int ret;
cur_scope = pthread_getspecific(tracer->tls);
if (cur_scope != scope) {
htrace_log(tracer->lg, "htracer_pop_scope: attempted to pop a scope "
"that wasn't the top of the stack. Current top of stack: "
"%s. Attempted to pop: %s.\n",
(cur_scope->span ? cur_scope->span->desc : "(detached)"),
(scope->span ? scope->span->desc : "(detached)"));
return EIO;
}
ret = pthread_setspecific(tracer->tls, scope->parent);
if (ret) {
htrace_log(tracer->lg, "htracer_pop_scope: pthread_setspecific "
"failed: %s\n", terror(ret));
return EIO;
}
return 0;
}
// vim:ts=4:sw=4:et