HTRACE-106: htrace: add C / C++ native client (cmccabe)
Project: http://git-wip-us.apache.org/repos/asf/incubator-htrace/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-htrace/commit/a9d85254 Tree: http://git-wip-us.apache.org/repos/asf/incubator-htrace/tree/a9d85254 Diff: http://git-wip-us.apache.org/repos/asf/incubator-htrace/diff/a9d85254 Branch: refs/heads/master Commit: a9d85254b42380ba09332be6c25d08939b6d794f Parents: 20f00f9 Author: Colin P. Mccabe <[email protected]> Authored: Sun Apr 19 17:15:19 2015 -0700 Committer: Colin P. Mccabe <[email protected]> Committed: Sun Apr 19 17:48:35 2015 -0700 ---------------------------------------------------------------------- htrace-c/BUILDING.txt | 32 + htrace-c/README.md | 31 + htrace-c/pom.xml | 108 +++ htrace-c/src/CMakeLists.txt | 215 ++++++ htrace-c/src/core/conf.c | 260 ++++++++ htrace-c/src/core/conf.h | 110 ++++ htrace-c/src/core/htrace.h | 346 ++++++++++ htrace-c/src/core/htrace.hpp | 239 +++++++ htrace-c/src/core/htracer.c | 167 +++++ htrace-c/src/core/htracer.h | 101 +++ htrace-c/src/core/scope.c | 166 +++++ htrace-c/src/core/scope.h | 58 ++ htrace-c/src/core/span.c | 187 ++++++ htrace-c/src/core/span.h | 138 ++++ htrace-c/src/receiver/curl.c | 124 ++++ htrace-c/src/receiver/curl.h | 60 ++ htrace-c/src/receiver/htraced.c | 649 +++++++++++++++++++ htrace-c/src/receiver/local_file.c | 184 ++++++ htrace-c/src/receiver/noop.c | 65 ++ htrace-c/src/receiver/receiver.c | 75 +++ htrace-c/src/receiver/receiver.h | 114 ++++ htrace-c/src/sampler/always.c | 71 ++ htrace-c/src/sampler/never.c | 71 ++ htrace-c/src/sampler/prob.c | 137 ++++ htrace-c/src/sampler/sampler.c | 88 +++ htrace-c/src/sampler/sampler.h | 121 ++++ htrace-c/src/test/conf-unit.c | 95 +++ htrace-c/src/test/htable-unit.c | 92 +++ htrace-c/src/test/htraced_rcv-unit.c | 110 ++++ htrace-c/src/test/linkage-unit.c | 105 +++ htrace-c/src/test/local_file_rcv-unit.c | 74 +++ htrace-c/src/test/log-unit.c | 97 +++ htrace-c/src/test/mini_htraced-unit.c | 48 ++ htrace-c/src/test/mini_htraced.c | 599 +++++++++++++++++ htrace-c/src/test/mini_htraced.h | 154 +++++ htrace-c/src/test/process_id-unit.c | 80 +++ htrace-c/src/test/rand-unit.c | 93 +++ htrace-c/src/test/rtest.c | 155 +++++ htrace-c/src/test/rtest.h | 76 +++ htrace-c/src/test/rtestpp.cc | 154 +++++ htrace-c/src/test/sampler-unit.c | 138 ++++ htrace-c/src/test/span-unit.c | 173 +++++ htrace-c/src/test/span_table.c | 139 ++++ htrace-c/src/test/span_table.h | 95 +++ htrace-c/src/test/span_util-unit.c | 74 +++ htrace-c/src/test/span_util.c | 294 +++++++++ htrace-c/src/test/span_util.h | 66 ++ htrace-c/src/test/string-unit.c | 73 +++ htrace-c/src/test/temp_dir-unit.c | 89 +++ htrace-c/src/test/temp_dir.c | 204 ++++++ htrace-c/src/test/temp_dir.h | 67 ++ htrace-c/src/test/test.c | 158 +++++ htrace-c/src/test/test.h | 211 ++++++ htrace-c/src/test/test_config.h.cmake | 28 + htrace-c/src/test/time-unit.c | 84 +++ htrace-c/src/util/build.h.cmake | 23 + htrace-c/src/util/htable.c | 290 +++++++++ htrace-c/src/util/htable.h | 169 +++++ htrace-c/src/util/log.c | 104 +++ htrace-c/src/util/log.h | 69 ++ htrace-c/src/util/process_id.c | 304 +++++++++ htrace-c/src/util/process_id.h | 58 ++ htrace-c/src/util/rand.h | 63 ++ htrace-c/src/util/rand_linux.c | 143 ++++ htrace-c/src/util/rand_posix.c | 120 ++++ htrace-c/src/util/string.c | 107 +++ htrace-c/src/util/string.h | 64 ++ htrace-c/src/util/terror.c | 65 ++ htrace-c/src/util/time.c | 96 +++ htrace-c/src/util/time.h | 79 +++ htrace-c/style.txt | 219 +++++++ .../go/src/org/apache/htrace/htraced/rest.go | 2 +- pom.xml | 1 + 73 files changed, 9717 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/BUILDING.txt ---------------------------------------------------------------------- diff --git a/htrace-c/BUILDING.txt b/htrace-c/BUILDING.txt new file mode 100644 index 0000000..f6728a0 --- /dev/null +++ b/htrace-c/BUILDING.txt @@ -0,0 +1,32 @@ +Building the htrace-c client +=============================================================================== +To build the htrace-c client, activate the native profile. Example: + + mvn package -DskipTests -Dmaven.javadoc.skip=true -Pnative + +BUILD DEPENDENCIES + C compiler + To compile the sources. + + CMake + The CMake build system. Needed to run the native build. See + www.cmake.org. This should be available via "yum install cmake" or + similar. + + libcurl-devel + A library to transfer data over HTTP. See http://curl.haxx.se/dev/. + Should be available via "yum install libcurl-devel" or similar. + +TEST DEPENDENCIES + C++ compiler + To compile some of the unit tests. + + libjson-c + A library to parse JSON. This is only used for unit tests. See + https://github.com/json-c/json-c/wiki. Should be available via "yum + install json-c-devel" or similar. + + htraced binary + You must compile the htraced binaries before running the unit tests. + You can do this by running "mvn compile" on the top-level project, or + in the htrace-htraced directory. http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/README.md ---------------------------------------------------------------------- diff --git a/htrace-c/README.md b/htrace-c/README.md new file mode 100644 index 0000000..0347e83 --- /dev/null +++ b/htrace-c/README.md @@ -0,0 +1,31 @@ +The HTrace C client +=============================================================================== +The HTrace C client is useful for distributed systems in C and C++ that need +tracing. + +To use the HTrace C client, you must link against the libhtrace.so library. +On a UNIX-based platform, you would link against the version of the library +containing only the major version number. For example, you might link against +libhtrace.so.3, which would then link against the appropriate minor version of +the library, such as libhtrace.so.3.2.0. The libhtrace API will not change in +backwards-incompatible ways within a major version. + +Some APIs in the library take htrace_conf objects. You can create these +objects via htrace_conf_from_str. A string of the form "KEY1=VAL1;KEY2=VAL2" +will create a configuration object with KEY1 set to VAL1, KEY2 set to VAL2, +etc. htrace.h defines the configuration keys you can set, such as +HTRACE_LOG_PATH_KEY. + +In general, you will want to create a single global htrace_ctx object, +representing an htrace context object, for your program. The all threads can +use this htrace_ctx object. The htrace_ctx contains all the per-process +htrace state, such as the process name, the thread-local data, and the htrace +receiver object that the process is using. + +If your process supports orderly shutdown, you can call htrace_ctx_free to +accomplish this. However, you should be sure that there are no references to +the htrace context before freeing it. Most daemons do not support orderly +shutdown, so this is not usually a problem. It is likely to come up in the +context of a library which uses the native htrace client. + +For a quick reference to the basics of trace spans and scopes, see htrace.h. http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/pom.xml ---------------------------------------------------------------------- diff --git a/htrace-c/pom.xml b/htrace-c/pom.xml new file mode 100644 index 0000000..51e3478 --- /dev/null +++ b/htrace-c/pom.xml @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed 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. See accompanying LICENSE file. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <artifactId>htrace-c</artifactId> + <packaging>jar</packaging> + + <parent> + <artifactId>htrace</artifactId> + <groupId>org.apache.htrace</groupId> + <version>3.2.0-incubating-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + + <name>htrace-c</name> + <url>http://incubator.apache.org/projects/htrace.html</url> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <profiles> + <profile> + <id>native</id> + <activation> + <activeByDefault>false</activeByDefault> + </activation> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + <executions> + <execution> + <id>enforce-os</id> + <goals> + <goal>enforce</goal> + </goals> + <configuration> + <rules> + <requireOS> + <family>mac</family> + <family>unix</family> + <message>The native build is only supported on Mac and other UNIX systems.</message> + </requireOS> + </rules> + <fail>true</fail> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-antrun-plugin</artifactId> + <executions> + <execution> + <id>make</id> + <phase>compile</phase> + <goals><goal>run</goal></goals> + <configuration> + <target> + <mkdir dir="${project.build.directory}/build"/> + <exec executable="cmake" dir="${project.build.directory}/build" failonerror="true"> + <arg line="${basedir}/src -DCMAKE_INSTALL_PREFIX=${project.build.directory}/install"/> + </exec> + <exec executable="make" dir="${project.build.directory}/build" failonerror="true"> + <arg line="install VERBOSE=1"/> + </exec> + </target> + </configuration> + </execution> + <execution> + <id>native_tests</id> + <phase>test</phase> + <goals><goal>run</goal></goals> + <configuration> + <target> + <exec executable="sh" dir="${project.build.directory}/build" failonerror="true"> + <arg value="-c"/> + <arg value="[ x$SKIPTESTS = xtrue ] || make test"/> + <env key="SKIPTESTS" value="${skipTests}"/> + </exec> + </target> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> +</project> http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/src/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/htrace-c/src/CMakeLists.txt b/htrace-c/src/CMakeLists.txt new file mode 100644 index 0000000..c9b124d --- /dev/null +++ b/htrace-c/src/CMakeLists.txt @@ -0,0 +1,215 @@ +# +# 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. +# + +# +# Build the C client for the HTrace distributed tracing system. +# + +cmake_minimum_required(VERSION 2.8 FATAL_ERROR) +set(CMAKE_BUILD_TYPE, Release) # Default to release builds + +# Define "make check" as an alias for "make test." +add_custom_target(check COMMAND ctest) +enable_testing() + +if (WIN32) + MESSAGE(FATAL_ERROR "Windows support is not yet available.") +else() # UNIX + set(CMAKE_C_FLAGS "-g ${CMAKE_C_FLAGS} -Wall -O2 -fno-strict-aliasing") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_REENTRANT") # Enable pthreads. + if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + # _GNU_SOURCE is needed to see all the glibc definitions. + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE") + # Use the 64-bit forms of off_t, etc. + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64") + endif() +endif() + +INCLUDE(CheckCSourceCompiles) +CHECK_C_SOURCE_COMPILES("int main(void) { static __thread int i = 0; return 0; }" HAVE_IMPROVED_TLS) +CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/util/build.h.cmake ${CMAKE_BINARY_DIR}/util/build.h) + +get_filename_component(HTRACE_ABSPATH "../../htrace-core/src/go/build/htrace" ABSOLUTE) +get_filename_component(HTRACED_ABSPATH "../../htrace-core/src/go/build/htraced" ABSOLUTE) +CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/test/test_config.h.cmake ${CMAKE_BINARY_DIR}/test/test_config.h) + +find_package(CURL REQUIRED) + +find_package(PkgConfig) +pkg_check_modules(PC_JSON-C QUIET json-c) +find_path(JSON_C_INCLUDE_DIR "json.h" + HINTS ${PC_JSON-C_INCLUDEDIR} ${PC_JSON-C_INCLUDE_DIRS} PATH_SUFFIXES json-c json) +find_library(JSON_C_LIBRARY NAMES json-c json libjson + HINTS ${PC_JSON-C_LIBDIR} ${PC_JSON-C_LIBRARY_DIRS}) +IF(JSON_C_INCLUDE_DIR AND JSON_C_LIBRARY) +ELSE(JSON_C_INCLUDE_DIR AND JSON_C_LIBRARY) + MESSAGE(FATAL_ERROR "Failed to find libjson-c. Try installing libjson-c with apt-get or yum, or install it manually from http://oss.metaparadigm.com/json-c/") +ENDIF(JSON_C_INCLUDE_DIR AND JSON_C_LIBRARY) + +include_directories(${CURL_INCLUDE_DIR} + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}) + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + set(RAND_SRC "util/rand_linux.c") +else() + set(RAND_SRC "util/rand_posix.c") +endif() + +set(SRC_ALL + ${RAND_SRC} + core/conf.c + core/htracer.c + core/scope.c + core/span.c + receiver/curl.c + receiver/htraced.c + receiver/local_file.c + receiver/noop.c + receiver/receiver.c + sampler/always.c + sampler/never.c + sampler/prob.c + sampler/sampler.c + util/htable.c + util/log.c + util/process_id.c + util/string.c + util/terror.c + util/time.c +) + +set(DEPS_ALL + ${CURL_LIBRARY} + pthread) + +# The unit test version of the library, which exposes all symbols. +add_library(htrace_test STATIC + ${SRC_ALL} + test/mini_htraced.c + test/span_table.c + test/span_util.c + test/temp_dir.c + test/test.c +) +target_link_libraries(htrace_test ${DEPS_ALL} ${JSON_C_LIBRARY}) + +# Hide all symbols by default. Only the symbols we specifically mark as +# visible should be accessable by the library user. This should avoid +# conflicts between our function and global variable names and those of +# the host program. +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") + +# The production version of the library, which exposes only the public API. +add_library(htrace SHARED ${SRC_ALL}) +target_link_libraries(htrace ${DEPS_ALL}) +set(HTRACE_VERSION_MAJOR "3") +set(HTRACE_VERSION_MINOR "2") +set(HTRACE_VERSION_PATCH "0") +set(HTRACE_VERSION_STRING + "${HTRACE_VERSION_MAJOR}.${HTRACE_VERSION_MINOR}.${HTRACE_VERSION_PATCH}") +set_target_properties(htrace PROPERTIES + VERSION ${HTRACE_VERSION_STRING} + SOVERSION ${HTRACE_VERSION_MAJOR}) + +macro(add_utest utest) + add_executable(${utest} + ${ARGN} + ) + target_link_libraries(${utest} htrace_test) + add_test(${utest} ${CMAKE_CURRENT_BINARY_DIR}/${utest} ${utest}) +endmacro(add_utest) + +add_utest(conf-unit + test/conf-unit.c +) + +add_utest(htable-unit + test/htable-unit.c +) + +add_utest(htraced_rcv-unit + test/htraced_rcv-unit.c + test/rtest.c +) + +add_executable(linkage-unit test/linkage-unit.c) +target_link_libraries(linkage-unit htrace dl) +add_test(linkage-unit ${CMAKE_CURRENT_BINARY_DIR}/linkage-unit linkage-unit) + +add_utest(local_file_rcv-unit + test/local_file_rcv-unit.c + test/rtest.c +) + +add_utest(local_file_rcvpp-unit + test/local_file_rcv-unit.c + test/rtestpp.cc +) + +add_utest(log-unit + test/log-unit.c +) + +add_utest(mini_htraced-unit + test/mini_htraced-unit.c +) + +add_utest(process_id-unit + test/process_id-unit.c +) + +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + add_utest(rand_linux-unit + test/rand-unit.c + util/rand_linux.c + ) +endif() +add_utest(rand_posix-unit + test/rand-unit.c + util/rand_posix.c +) + +add_utest(sampler-unit + test/sampler-unit.c +) + +add_utest(span-unit + test/span-unit.c +) + +add_utest(span_util-unit + test/span_util-unit.c +) + +add_utest(string-unit + test/string-unit.c +) + +add_utest(temp_dir-unit + test/temp_dir-unit.c +) + +add_utest(time-unit + test/time-unit.c +) + +# Install libhtrace.so and htrace.h. +# These are the only build products that external users can consume. +install(TARGETS htrace DESTINATION lib) +install(FILES ${CMAKE_SOURCE_DIR}/core/htrace.h DESTINATION include) http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/src/core/conf.c ---------------------------------------------------------------------- diff --git a/htrace-c/src/core/conf.c b/htrace-c/src/core/conf.c new file mode 100644 index 0000000..936e224 --- /dev/null +++ b/htrace-c/src/core/conf.c @@ -0,0 +1,260 @@ +/** + * 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 "util/htable.h" +#include "util/log.h" + +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#define HTRACE_DEFAULT_CONF_KEYS (\ + HTRACE_PROB_SAMPLER_FRACTION_KEY "=0.01"\ + ";" HTRACED_BUFFER_SIZE_KEY "=67108864"\ + ";" HTRACED_SEND_TIMEOUT_MS_KEY "=120000"\ + ";" HTRACE_PROCESS_ID "=%{tname}/%{ip}"\ + ";" HTRACED_ADDRESS_KEY "=localhost:9095"\ + ) + +static int parse_key_value(char *str, char **key, char **val) +{ + char *eq = strchr(str, '='); + if (eq) { + *eq = '\0'; + *val = strdup(eq + 1); + } else { + *val = strdup("true"); + } + if (!*val) { + return ENOMEM; + } + *key = strdup(str); + if (!*key) { + free(*val); + return ENOMEM; + } + return 0; +} + +static struct htable *htable_from_str(const char *str) +{ + struct htable *ht; + char *cstr = NULL, *saveptr = NULL, *tok; + int ret = ENOMEM; + + ht = htable_alloc(8, ht_hash_string, ht_compare_string); + if (!ht) { + goto done; + } + if (!str) { + ret = 0; + goto done; + } + cstr = strdup(str); + if (!cstr) { + goto done; + } + + for (tok = strtok_r(cstr, ";", &saveptr); tok; + tok = strtok_r(NULL, ";", &saveptr)) { + char *key = NULL, *val = NULL; + ret = parse_key_value(tok, &key, &val); + if (ret) { + goto done; + } + ret = htable_put(ht, key, val); + if (ret) { + goto done; + } + } + ret = 0; +done: + if (ret) { + htable_free(ht); + ht = NULL; + } + free(cstr); + return ht; +} + +struct htrace_conf *htrace_conf_from_strs(const char *values, + const char *defaults) +{ + struct htrace_conf *cnf; + + cnf = calloc(1, sizeof(*cnf)); + if (!cnf) { + return NULL; + } + cnf->values = htable_from_str(values); + if (!cnf->values) { + htrace_conf_free(cnf); + return NULL; + } + cnf->defaults = htable_from_str(defaults); + if (!cnf->defaults) { + htrace_conf_free(cnf); + return NULL; + } + return cnf; +} + +struct htrace_conf *htrace_conf_from_str(const char *values) +{ + return htrace_conf_from_strs(values, HTRACE_DEFAULT_CONF_KEYS); +} + +static void htrace_tuple_free(void *ctx, void *key, void *val) +{ + free(key); + free(val); +} + +void htrace_conf_free(struct htrace_conf *cnf) +{ + if (!cnf) { + return; + } + if (cnf->values) { + htable_visit(cnf->values, htrace_tuple_free, NULL); + htable_free(cnf->values); + } + if (cnf->defaults) { + htable_visit(cnf->defaults, htrace_tuple_free, NULL); + htable_free(cnf->defaults); + } + free(cnf); +} + +const char *htrace_conf_get(const struct htrace_conf *cnf, const char *key) +{ + const char *val; + + val = htable_get(cnf->values, key); + if (val) + return val; + val = htable_get(cnf->defaults, key); + return val; +} + +static int convert_double(struct htrace_log *log, const char *key, + const char *in, double *out) +{ + char *endptr = NULL; + int err; + double ret; + + errno = 0; + ret = strtod(in, &endptr); + if (errno) { + err = errno; + htrace_log(log, "error parsing %s for %s: %d (%s)\n", + in, key, err, terror(err)); + return 0; + } + while (1) { + char c = *endptr; + if (c == '\0') { + break; + } + if ((c != ' ') || (c != '\t')) { + htrace_log(log, "error parsing %s for %s: garbage at end " + "of string.\n", in, key); + return 0; + } + } + *out = ret; + return 1; +} + +double htrace_conf_get_double(struct htrace_log *log, + const struct htrace_conf *cnf, const char *key) +{ + const char *val; + double out = 0; + + val = htable_get(cnf->values, key); + if (val) { + if (convert_double(log, key, val, &out)) { + return out; + } + } + val = htable_get(cnf->defaults, key); + if (val) { + if (convert_double(log, key, val, &out)) { + return out; + } + } + return 0; +} + +static int convert_u64(struct htrace_log *log, const char *key, + const char *in, uint64_t *out) +{ + char *endptr = NULL; + int err; + uint64_t ret; + + errno = 0; + ret = strtoull(in, &endptr, 10); + if (errno) { + err = errno; + htrace_log(log, "error parsing %s for %s: %d (%s)\n", + in, key, err, terror(err)); + return 0; + } + while (1) { + char c = *endptr; + if (c == '\0') { + break; + } + if ((c != ' ') || (c != '\t')) { + htrace_log(log, "error parsing %s for %s: garbage at end " + "of string.\n", in, key); + return 0; + } + } + *out = ret; + return 1; +} + +uint64_t htrace_conf_get_u64(struct htrace_log *log, + const struct htrace_conf *cnf, const char *key) +{ + const char *val; + uint64_t out = 0; + + val = htable_get(cnf->values, key); + if (val) { + if (convert_u64(log, key, val, &out)) { + return out; + } + } + val = htable_get(cnf->defaults, key); + if (val) { + if (convert_u64(log, key, val, &out)) { + return out; + } + } + return 0; +} + +// vim:ts=4:sw=4:et http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/src/core/conf.h ---------------------------------------------------------------------- diff --git a/htrace-c/src/core/conf.h b/htrace-c/src/core/conf.h new file mode 100644 index 0000000..aa0bb0b --- /dev/null +++ b/htrace-c/src/core/conf.h @@ -0,0 +1,110 @@ +/** + * 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. + */ + +#ifndef APACHE_HTRACE_CORE_CONF_H +#define APACHE_HTRACE_CORE_CONF_H + +#include <stdint.h> + +/** + * @file conf.h + * + * Functions to manipulate HTrace configuration objects. + * + * This is an internal header, not intended for external use. + */ + +struct htable; +struct htrace_log; + +struct htrace_conf { + /** + * A hash table mapping keys to the values that were set. + */ + struct htable *values; + + /** + * A hash table mapping keys to the default values that were set for those + * keys. + */ + struct htable *defaults; +}; + +/** + * Create an HTrace conf object from a values string and a defaults string. + * + * See {@ref htrace_conf_from_str} for the format. + * + * The configuration object must be later freed with htrace_conf_free. + * + * @param str The configuration string. + * + * @return NULL on OOM; the htrace configuration otherwise. + */ +struct htrace_conf *htrace_conf_from_strs(const char *values, + const char *defaults); + +/** + * Free an HTrace configuration object. + * + * @param cnf The HTrace configuration object. + */ +void htrace_conf_free(struct htrace_conf *cnf); + +/** + * Get the value of a key in a configuration. + * + * @param cnf The configuration. + * @param key The key. + * + * @return NULL if the key was not found in the values or the + * defaults; the value otherwise. + */ +const char *htrace_conf_get(const struct htrace_conf *cnf, const char *key); + +/** + * Get the value of a key in a configuration as a floating point double. + * + * @param log Log to send parse error messages to. + * @param cnf The configuration. + * @param key The key. + * + * @return The value if it was found. + * The default value if it was not found. + * 0.0 if there was no default value. + */ +double htrace_conf_get_double(struct htrace_log *log, + const struct htrace_conf *cnf, const char *key); + +/** + * Get the value of a key in a configuration as a uint64_t. + * + * @param log Log to send parse error messages to. + * @param cnf The configuration. + * @param key The key. + * + * @return The value if it was found. + * The default value if it was not found. + * 0 if there was no default value. + */ +uint64_t htrace_conf_get_u64(struct htrace_log *log, + const struct htrace_conf *cnf, const char *key); + +#endif + +// vim: ts=4: sw=4: et http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/src/core/htrace.h ---------------------------------------------------------------------- diff --git a/htrace-c/src/core/htrace.h b/htrace-c/src/core/htrace.h new file mode 100644 index 0000000..cdebd31 --- /dev/null +++ b/htrace-c/src/core/htrace.h @@ -0,0 +1,346 @@ +/** + * 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. + */ + +#ifndef APACHE_HTRACE_HTRACE_H +#define APACHE_HTRACE_HTRACE_H + +#include <stdint.h> /* for uint64_t, etc. */ + +/** + * The public API for the HTrace C client. + * + * SPANS AND SCOPES + * HTrace is a tracing framework for distributed systems. The smallest unit of + * tracing in HTrace is the trace span. Trace spans represent intervals during + * which a thread is performing some work. Trace spans are identified by a + * 64-bit ID called the trace span ID. Trace spans can have one or more + * parents. The parent of a trace span is the operation or operations that + * caused it to happen. + * + * Trace spans are managed by htrace_scope objects. Creating an htrace_scope + * (potentially) starts a trace span. The trace span will be closed once the + * htrace_scope is closed and freed. + * + * SPAN RECEIVERS + * When a span is closed, it is sent to the current "span receiver." Span + * receivers decide what to do with the span data. For example, the "local + * file" span receiver saves the span data to a local file. The "htraced" span + * receiver sends the span data to the htraced daemon. + * + * Most interesting span receivers will start a background thread to handle + * their workload. This background thread will last until the associated + * htracer is shut down. + * + * SAMPLING + * HTrace is based around the concept of sampling. That means that only some + * trace scopes are managing spans-- the rest do nothing. Sampling is managed + * by htrace_sampler objects. The two most important samplers are the + * probability based sampler, and the "always" and "never" samplers. + * + * TRACERS + * The HTrace C client eschews globals. Instead, you are invited to create your + * own htracer (HTrace context) object and use it throughout your program or + * library. The htracer object contains the logging settings and the currently + * configured span receiver. Tracers are thread-safe, so you can use the same + * tracer for all of your threads if you like. + * + * As already mentioned, the Tracer may contain threads, so please do not call + * htracer_create until you are ready to start threads in your program. For + * example, do not call it prior to daemonizing. + * + * COMPATIBILITY + * When modifying this code, please try to avoid breaking binary compatibility. + * Applications compiled against older versions of libhtrace.so should continue + * to work when new versions of the library are dropped in. + * + * Adding new functions is always OK. Modifying the type signature of existing + * functions is not OK. When adding structures, try to avoid including the + * structure definition in this header, so that we can change it later on with + * no harmful effects. Perhaps we may need to break compatibility at some + * point, but let's try to avoid that if we can. + * + * PORTABILITY + * We aim for POSIX compatibility, although we have not done a lot of testing on + * non-Linux systems. Eventually, we will want to support Windows. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma GCC visibility push(default) // Begin publicly visible symbols + +// Configuration keys. + +/** + * The path to use for the htrace client log. + * If this is unset, we will log to stderr. + */ +#define HTRACE_LOG_PATH_KEY "log.path" + +/** + * The span receiver implementation to use. + * + * Possible values: + * noop The "no op" span receiver, which discards all spans. + * local.file A receiver which writes spans to local files. + * htraced The htraced span receiver, which sends spans to htraced. + */ +#define HTRACE_SPAN_RECEIVER_KEY "span.receiver" + +/** + * The path which the local file span receiver should write spans to. + */ +#define HTRACE_LOCAL_FILE_RCV_PATH_KEY "local.file.path" + +/** + * The hostname and port which the htraced span receiver should send its spans + * to. This is in the format "hostname:port". + */ +#define HTRACED_ADDRESS_KEY "htraced.address" + +/** + * The timeout to use when sending spans to the htraced server. + */ +#define HTRACED_SEND_TIMEOUT_MS_KEY "htraced.send.timeout.ms" + +/** + * The size of the circular buffer to use in the htraced receiver. + */ +#define HTRACED_BUFFER_SIZE_KEY "htraced.buffer.size" + +/** + * The process ID string to use. + * + * %{ip} will be replaced by an IP address; + * %{pid} will be replaced by the operating system process ID; + * %{tname} will be replaced by the Tracer name. + * + * Defaults to %{tname}/%{ip} + */ +#define HTRACE_PROCESS_ID "process.id" + +/** + * The sampler to use. + * + * Possible values: + * never A sampler which never fires. + * always A sampler which always fires. + * prob A sampler which fires with some probability. + */ +#define HTRACE_SAMPLER_KEY "sampler" + +/** + * For the probability sampler, the fraction of the time that we should create a + * new span. This is a floating point number which is between 0.0 and 1.1, + * inclusive. It is _not_ a percentage. + */ +#define HTRACE_PROB_SAMPLER_FRACTION_KEY "prob.sampler.fraction" + + // Forward declarations + struct htrace_conf; + struct htracer; + struct htrace_scope; + + /** + * Create an HTrace conf object from a string. + * + * The string should be in the form: + * key1=val1;key2=val2;... + * Entries without an equals sign will set the key to 'true'. + * + * The configuration object must be later freed with htrace_conf_free. + * + * @param values The configuration string to parse. + * You may free this string after this function + * returns. + * + * @return NULL on out-of-memory error; the configuration + * object otherwise. + */ + struct htrace_conf *htrace_conf_from_str(const char *values); + + /** + * Free an htrace configuration. + * + * @param conf The configuration object to free. + */ + void htrace_conf_free(struct htrace_conf *cnf); + + /** + * Create a Tracer. + * + * This function does a few things: + * - Initialize logging (if there are configuration tuples related to + * logging) + * - Initialize trace span receivers, if any are configured. + * + * This function may start background threads. + * + * @param tname The name of the tracer to create. Will be + * deep-copied. Must not be null. + * @param conf The configuration to use. You may free this + * configuration object after calling this + * function. + * + * @return NULL on OOM; the tracer otherwise. + */ + struct htracer *htracer_create(const char *tname, + const struct htrace_conf *cnf); + + /** + * Get the Tracer name. + * + * @param tracer The tracer. + * + * @return The tracer name. This string is managed by the + * tracer itself and will remain valid until the + * tracer is freed. + */ + const char *htracer_tname(const struct htracer *tracer); + + /** + * Free an HTracer. + * + * Frees the memory and other resources associated with a Tracer. + * Closes the log file if there is one open. Shuts down the span receiver + * if there is one active. Attempt to flush all buffered spans. + * + * Do not call this function until all the samplers which hold a reference + * to this htracer have been freed. Do not call this function if there is + * currently an active htrace_scope object which holds a reference to this + * tracer. + * + * @param tracer The tracer to free. + */ + void htracer_free(struct htracer *tracer); + + /** + * Create an htrace configuration sample from a configuration. + * + * Samplers are thread-safe; you may use the same sampler simultaneously + * from multiple threads. + * + * @param tracer The HTracer to use. The sampler will hold a + * reference to this tracer. Do not free the + * tracer until after the sampler has been freed. + * @param conf The configuration to use. You may free this + * configuration object after calling this + * function. + * + * @return NULL if we are out of memory. + * NULL if the configuration was invalid. + * NULL if no sampler is configured. + * The sampler otherwise. + * Error conditions will be logged to the htracer log. + */ + struct htrace_sampler *htrace_sampler_create(struct htracer *tracer, + struct htrace_conf *cnf); + + /** + * Get the name of an HTrace sampler. + * + * @param smp The sampler. + * + * @return The sampler name. This string is managed by the + * sampler itself and will remain valid until the + * sampler is freed. + */ + const char *htrace_sampler_to_str(struct htrace_sampler *smp); + + /** + * Free an htrace sampler. + * + * @param sampler The sampler to free. + */ + void htrace_sampler_free(struct htrace_sampler *smp); + + /** + * Start a new trace span if necessary. + * + * You must call htrace_close_span on the scope object returned by this + * function. + * + * @param tracer The htracer to use. Must remain valid for the + * duration of the scope. + * @param sampler The sampler to use, or NULL for no sampler. + * If no sampler is used, we will create a new span + * only if there is a current active span. + * @param desc The description of the trace span. Will be deep-copied. + * + * @return The trace scope. NULL if we ran out of memory, or if we + * are not tracing. + */ + struct htrace_scope* htrace_start_span(struct htracer *tracer, + struct htrace_sampler *sampler, const char *desc); + + /** + * Detach the trace span from the given trace scope. + * + * @param scope The trace scope, or NULL. + * + * @return NULL if there was no attached trace scope; + * the trace scope otherwise. + */ + struct htrace_span *htrace_scope_detach(struct htrace_scope *scope); + + /** + * Create a new scope object with the given span. + * + * @param tracer The htracer to use. + * @param span The trace span, or NULL. + * + * @return NULL if there was no trace span; + * the trace scope otherwise. + */ + struct htrace_scope* htrace_restart_span(struct htracer *tracer, + struct htrace_span *span); + + /** + * Get the span id of an HTrace scope. + * + * @param scope The trace scope, or NULL. + * + * @return The span ID of the trace span, or 0 if there is no trace + * span inside the scope, or if NULL was passed. + */ + uint64_t htrace_scope_get_span_id(const struct htrace_scope *scope); + + /** + * Close a trace scope. + * + * This must be called from the same thread that the trace scope was created + * in. + * + * @param scope The trace scope to close. You may pass NULL here + * with no harmful effects-- it will be ignored. + * If there is a span associated with the trace scope, + * it will be sent to the relevant span receiver. + * Then the scope and the span will be freed. + */ + void htrace_scope_close(struct htrace_scope *scope); + +#pragma GCC visibility pop // End publicly visible symbols + +#ifdef __cplusplus +} +#endif + +#endif + +// vim: ts=4:sw=4:et http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/src/core/htrace.hpp ---------------------------------------------------------------------- diff --git a/htrace-c/src/core/htrace.hpp b/htrace-c/src/core/htrace.hpp new file mode 100644 index 0000000..e4a87cb --- /dev/null +++ b/htrace-c/src/core/htrace.hpp @@ -0,0 +1,239 @@ +/** + * 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. + */ + +#ifndef APACHE_HTRACE_HTRACE_HPP +#define APACHE_HTRACE_HTRACE_HPP + +#include "htrace.h" + +#include <string> + +/** + * The public C++ API for the HTrace native client. + * + * The C++ API is a wrapper around the C API. The advantage of this is that we + * can change the C++ API in this file without breaking binary compatibility. + * + * EXCEPTIONS + * We do not use exceptions in this API. This code should be usable by + * libraries and applications that are using the Google C++ coding style. + * The one case where we do use exceptions is to translate NULL pointer returns + * on OOM into std::bad_alloc exceptions. In general, it is extremely unlikely + * that the size of memory allocations we are doing will produce OOM. Most + * C++ programs do not attempt to handle OOM anyway because of the extra code + * complexity that would be required. So translating this into an exception is + * fine. + * + * C++11 + * This code should not require C++11. We might add #ifdefs later to take + * advantage of certain C++11 or later features if they are available. + */ + +namespace htrace { + class Sampler; + class Scope; + class Tracer; + + /** + * An HTrace Configuration object. + * + * Configurations are thread-safe. They can be used by multiple threads + * simultaneously. + */ + class Conf { + public: + /** + * Create a new HTrace Conf. + * + * @param values A configuration string containing a series of + * semicolon-separated key=value entries. + * We do not hold on to a reference to this string. + * @param defaults Another semicolon-separated set of key=value entries. + * The defaults to be used when there is no corresponding + * value in 'values.' We do not hold on to a reference to + * this string. + */ + Conf(const char *values) + : conf_(htrace_conf_from_str(values)) + { + if (!conf_) { + throw std::bad_alloc(); + } + } + + Conf(const std::string &values) + : conf_(htrace_conf_from_str(values.c_str())) + { + if (!conf_) { + throw std::bad_alloc(); + } + } + + ~Conf() { + htrace_conf_free(conf_); + conf_ = NULL; + } + + private: + friend class Tracer; + friend class Sampler; + Conf &operator=(Conf &other); // Can't copy + Conf(Conf &other); + struct htrace_conf *conf_; + }; + + /** + * An HTrace context object. + * + * Contexts are thread-safe. They can be used by multiple threads simultaneoy + * Most applications will not need more than one HTrace context, which is + * often global (or at least widely used.) + */ + class Tracer { + public: + /** + * Create a new Tracer. + * + * @param name The name of the tracer to create. We do not hold on to a + * reference to this string. + * @param conf The configuration to use for the new tracer. We do not + * hold on to a reference to this configuration. + */ + Tracer(const std::string &name, const Conf &conf) + : tracer_(htracer_create(name.c_str(), conf.conf_)) + { + if (!tracer_) { + throw std::bad_alloc(); + } + } + + std::string Name() { + return std::string(htracer_tname(tracer_)); + } + + /** + * Free the Tracer. + * + * This destructor must not be called until all the other objects which hold + * a reference (such as samplers and trace scopes) are freed. It is often + * not necessary to destroy this object at all unless you are writing a + * library and want to support unloading your library, or you are writing an + * application and want to support some kind of graceful shutdown. + * + * We could make this friendlier with some kind of reference counting via + * atomic variables, but only at the cost of reduced performance. + */ + ~Tracer() { + htracer_free(tracer_); + tracer_ = NULL; + } + + private: + friend class Sampler; + friend class Scope; + Tracer(const Tracer &other); // Can't copy + const Tracer &operator=(const Tracer &other); + struct htracer *tracer_; + }; + + /** + * An HTrace sampler. + * + * Samplers determine when new spans are created. + * See htrace.h for more information. + * + * Samplers are thread-safe. They can be used by multiple threads + * simultaneously. + */ + class Sampler { + public: + /** + * Create a new Sampler. + * + * @param tracer The tracer to use. You must not free this tracer until + * after this sampler is freed. + * @param conf The configuration to use for the new sampler. We do not + * hold on to a reference to this configuration. + */ + Sampler(Tracer *tracer, const Conf &conf) + : smp_(htrace_sampler_create(tracer->tracer_, conf.conf_)) { + if (!smp_) { + throw std::bad_alloc(); + } + } + + /** + * Get a description of this Sampler. + */ + std::string ToString() { + return std::string(htrace_sampler_to_str(smp_)); + } + + ~Sampler() { + htrace_sampler_free(smp_); + smp_ = NULL; + } + + private: + friend class Tracer; + friend class Scope; + Sampler(const Sampler &other); // Can't copy + const Sampler &operator=(const Sampler &other); + + struct htrace_sampler *smp_; + }; + + class Scope { + public: + Scope(Tracer &tracer, const char *name) + : scope_(htrace_start_span(tracer.tracer_, NULL, name)) { + } + + Scope(Tracer &tracer, const std::string &name) + : scope_(htrace_start_span(tracer.tracer_, NULL, name.c_str())) { + } + + Scope(Tracer &tracer, Sampler &smp, const char *name) + : scope_(htrace_start_span(tracer.tracer_, smp.smp_, name)) { + } + + Scope(Tracer &tracer, Sampler &smp, const std::string &name) + : scope_(htrace_start_span(tracer.tracer_, smp.smp_, name.c_str())) { + } + + ~Scope() { + htrace_scope_close(scope_); + scope_ = NULL; + } + + uint64_t GetSpanId() { + return htrace_scope_get_span_id(scope_); + } + + private: + friend class Tracer; + Scope(htrace::Scope &other); // Can't copy + Scope& operator=(Scope &scope); // Can't assign + + struct htrace_scope *scope_; + }; +} + +#endif + +// vim: ts=2:sw=2:et http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/src/core/htracer.c ---------------------------------------------------------------------- diff --git a/htrace-c/src/core/htracer.c b/htrace-c/src/core/htracer.c new file mode 100644 index 0000000..3305beb --- /dev/null +++ b/htrace-c/src/core/htracer.c @@ -0,0 +1,167 @@ +/** + * 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/process_id.h" +#include "util/rand.h" +#include "util/string.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->prid = calculate_process_id(tracer->lg, + htrace_conf_get(cnf, HTRACE_PROCESS_ID), tname); + if (!tracer->prid) { + 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->prid)) { + htrace_log(tracer->lg, "htracer_create: process ID string '%s' is " + "problematic.\n", tracer->prid); + 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->prid); + 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 http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/src/core/htracer.h ---------------------------------------------------------------------- diff --git a/htrace-c/src/core/htracer.h b/htrace-c/src/core/htracer.h new file mode 100644 index 0000000..2acdf70 --- /dev/null +++ b/htrace-c/src/core/htracer.h @@ -0,0 +1,101 @@ +/** + * 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. + */ + +#ifndef APACHE_HTRACE_CORE_TRACER_H +#define APACHE_HTRACE_CORE_TRACER_H + +#include <pthread.h> /* for pthread_key_t */ + +/** + * @file tracer.h + * + * The HTracer object. + * + * This is an internal header, not intended for external use. + */ + +struct htrace_log; +struct htrace_rcv; +struct random_src; + +struct htracer { + /** + * Key for thread-local data. + */ + pthread_key_t tls; + + /** + * The htrace log to use. + */ + struct htrace_log *lg; + + /** + * The name of this tracer. + */ + char *tname; + + /** + * The process id of this context. + */ + char *prid; + + /** + * The random source to use in this context. + */ + struct random_src *rnd; + + /** + * The span receiver to use. + */ + struct htrace_rcv *rcv; +}; + +/** + * Get the current scope in a given context. + * + * @param tracer The context. + * + * @return The current scope, or NULL if there is none. + */ +struct htrace_scope *htracer_cur_scope(struct htracer *tracer); + +/** + * Push another scope on to the current context. + * + * @param tracer The context. + * @param cur The current scope on the context. + * @param next The scope to push. + * + * @return 0 on success; nonzero otherwise. + */ +int htracer_push_scope(struct htracer *tracer, struct htrace_scope *cur, + struct htrace_scope *next); + +/** + * Pop a scope from the current context. + * + * @param tracer The context. + * @param scope The scope which should be the top of the stack. + * + * @return 0 on success; nonzero otherwise. + */ +int htracer_pop_scope(struct htracer *tracer, struct htrace_scope *scope); + +#endif + +// vim: ts=4: sw=4: et http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/src/core/scope.c ---------------------------------------------------------------------- diff --git a/htrace-c/src/core/scope.c b/htrace-c/src/core/scope.c new file mode 100644 index 0000000..93008cb --- /dev/null +++ b/htrace-c/src/core/scope.c @@ -0,0 +1,166 @@ +/** + * 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/htrace.h" +#include "core/htracer.h" +#include "core/scope.h" +#include "core/span.h" +#include "receiver/receiver.h" +#include "sampler/sampler.h" +#include "util/log.h" +#include "util/rand.h" +#include "util/string.h" +#include "util/time.h" + +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +/** + * @file scope.c + * + * Implementation of HTrace scopes. + */ + +struct htrace_scope* htrace_start_span(struct htracer *tracer, + struct htrace_sampler *sampler, const char *desc) +{ + struct htrace_scope *cur_scope, *scope = NULL, *pscope; + struct htrace_span *span = NULL; + uint64_t span_id; + + // Validate the description string. This ensures that it doesn't have + // anything silly in it like embedded double quotes, backslashes, or control + // characters. + if (!validate_json_string(tracer->lg, desc)) { + htrace_log(tracer->lg, "htrace_span_alloc(desc=%s): invalid " + "description string.\n", desc); + return NULL; + } + cur_scope = htracer_cur_scope(tracer); + if (!cur_scope) { + if (!sampler->ty->next(sampler)) { + return NULL; + } + } + do { + span_id = random_u64(tracer->rnd); + } while (span_id == 0); + span = htrace_span_alloc(desc, now_ms(tracer->lg), span_id); + if (!span) { + htrace_log(tracer->lg, "htrace_span_alloc(desc=%s): OOM\n", desc); + return NULL; + } + scope = malloc(sizeof(*scope)); + if (!scope) { + htrace_span_free(span); + htrace_log(tracer->lg, "htrace_start_span(desc=%s): OOM\n", desc); + return NULL; + } + scope->tracer = tracer; + scope->span = span; + + // Search enclosing trace scopes for the first one that hasn't disowned + // its trace span. + for (pscope = cur_scope; pscope; pscope = pscope->parent) { + struct htrace_span *pspan = pscope->span; + if (pspan) { + span->parent.single = pspan->span_id; + span->num_parents = 1; + break; + } + pscope = pscope->parent; + } + if (htracer_push_scope(tracer, cur_scope, scope) != 0) { + htrace_span_free(span); + free(scope); + return NULL; + } + return scope; +} + +struct htrace_span *htrace_scope_detach(struct htrace_scope *scope) +{ + struct htrace_span *span = scope->span; + + if (span == NULL) { + htrace_log(scope->tracer->lg, "htrace_scope_detach: attempted to " + "detach a scope which was already detached.\n"); + return NULL; + } + scope->span = NULL; + return span; +} + +struct htrace_scope* htrace_restart_span(struct htracer *tracer, + struct htrace_span *span) +{ + struct htrace_scope *cur_scope, *scope = NULL; + + scope = malloc(sizeof(*scope)); + if (!scope) { + htrace_span_free(span); + htrace_log(tracer->lg, "htrace_start_span(desc=%s, parent_id=%016"PRIx64 + "): OOM\n", span->desc, span->span_id); + return NULL; + } + scope->tracer = tracer; + scope->parent = NULL; + scope->span = span; + cur_scope = htracer_cur_scope(tracer); + if (htracer_push_scope(tracer, cur_scope, scope) != 0) { + htrace_span_free(span); + free(scope); + return NULL; + } + return scope; +} + +uint64_t htrace_scope_get_span_id(const struct htrace_scope *scope) +{ + struct htrace_span *span; + + if (!scope) { + return 0; + } + span = scope->span; + return span ? span->span_id : 0; +} + +void htrace_scope_close(struct htrace_scope *scope) +{ + struct htracer *tracer; + + if (!scope) { + return; + } + tracer = scope->tracer; + if (htracer_pop_scope(tracer, scope) == 0) { + struct htrace_span *span = scope->span; + if (span) { + struct htrace_rcv *rcv = tracer->rcv; + span->end_ms = now_ms(tracer->lg); + rcv->ty->add_span(rcv, span); + htrace_span_free(span); + } + free(scope); + } +} + +// vim:ts=4:sw=4:et http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/src/core/scope.h ---------------------------------------------------------------------- diff --git a/htrace-c/src/core/scope.h b/htrace-c/src/core/scope.h new file mode 100644 index 0000000..f76cd42 --- /dev/null +++ b/htrace-c/src/core/scope.h @@ -0,0 +1,58 @@ +/** + * 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. + */ + +#ifndef APACHE_HTRACE_SCOPE_H +#define APACHE_HTRACE_SCOPE_H + +/** + * @file scope.h + * + * Functions related to trace scopes. + * + * This is an internal header, not intended for external use. + */ + +#include <stdint.h> + +/** + * A trace scope. + * + * Currently, trace scopes contain span data (there is no separate object for + * the span data.) + */ +struct htrace_scope { + /** + * The HTracer object associated with this scope. Cannot be NULL. + * This memory is managed externally from the htrace_scope object. + */ + struct htracer *tracer; + + /** + * The parent scope, or NULL if this is a top-level scope. + */ + struct htrace_scope *parent; + + /** + * The span object associated with this scope, or NULL if there is none. + */ + struct htrace_span *span; +}; + +#endif + +// vim: ts=4:sw=4:et http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/src/core/span.c ---------------------------------------------------------------------- diff --git a/htrace-c/src/core/span.c b/htrace-c/src/core/span.c new file mode 100644 index 0000000..13ba3cf --- /dev/null +++ b/htrace-c/src/core/span.c @@ -0,0 +1,187 @@ +/** + * 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/span.h" +#include "receiver/receiver.h" +#include "sampler/sampler.h" +#include "util/log.h" +#include "util/rand.h" +#include "util/string.h" +#include "util/time.h" + +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +/** + * @file span.c + * + * Implementation of HTrace spans. + */ + +struct htrace_span *htrace_span_alloc(const char *desc, + uint64_t begin_ms, uint64_t span_id) +{ + struct htrace_span *span; + + span = malloc(sizeof(*span)); + if (!span) { + return NULL; + } + span->desc = strdup(desc); + if (!span->desc) { + free(span); + return NULL; + } + span->begin_ms = begin_ms; + span->end_ms = 0; + span->span_id = span_id; + span->prid = NULL; + span->num_parents = 0; + span->parent.single = 0; + span->parent.list = NULL; + return span; +} + +void htrace_span_free(struct htrace_span *span) +{ + if (!span) { + return; + } + free(span->desc); + free(span->prid); + if (span->num_parents > 1) { + free(span->parent.list); + } + free(span); +} + +static int compare_spanids(const void *va, const void *vb) +{ + uint64_t a = *((uint64_t*)va); + uint64_t b = *((uint64_t*)vb); + if (a < b) { + return -1; + } else if (a > b) { + return 1; + } else { + return 0; + } +} + +void htrace_span_sort_and_dedupe_parents(struct htrace_span *span) +{ + int i, j, num_parents = span->num_parents; + uint64_t prev; + + if (num_parents <= 1) { + return; + } + qsort(span->parent.list, num_parents, sizeof(uint64_t), compare_spanids); + prev = span->parent.list[0]; + j = 1; + for (i = 1; i < num_parents; i++) { + uint64_t id = span->parent.list[i]; + if (id != prev) { + span->parent.list[j++] = span->parent.list[i]; + prev = id; + } + } + span->num_parents = j; + if (j == 1) { + // After deduplication, there is now only one entry. Switch to the + // optimized no-malloc representation for 1 entry. + free(span->parent.list); + span->parent.single = prev; + } else if (j != num_parents) { + // After deduplication, there are now fewer entries. Use realloc to + // shrink the size of our dynamic allocation if possible. + uint64_t *nlist = realloc(span->parent.list, sizeof(uint64_t) * j); + if (nlist) { + span->parent.list = nlist; + } + } +} + +/** + * Translate the span to a JSON string. + * + * This function can be called in two ways. With buf == NULL, we will determine + * the size of the buffer that would be required to hold a JSON string + * containing the span contents. With buf non-NULL, we will write the span + * contents to the provided buffer. + * + * @param scope The scope + * @param max The maximum number of bytes to write to buf. + * @param buf If non-NULL, where the string will be written. + * + * @return The number of bytes that the span json would take + * up if it were written out. + */ +static int span_json_sprintf_impl(const struct htrace_span *span, + int max, char *buf) +{ + int num_parents, i, ret = 0; + const char *prefix = ""; + + // Note that we have validated the description and process ID strings to + // make sure they don't contain anything evil. So we don't need to escape + // them here. + + ret += fwdprintf(&buf, &max, "{\"s\":\"%016" PRIx64 "\",\"b\":%" PRId64 + ",\"e\":%" PRId64",", span->span_id, span->begin_ms, + span->end_ms); + if (span->desc) { + ret += fwdprintf(&buf, &max, "\"d\":\"%s\",", span->desc); + } + if (span->prid) { + ret += fwdprintf(&buf, &max, "\"r\":\"%s\",", span->prid); + } + num_parents = span->num_parents; + if (num_parents == 0) { + ret += fwdprintf(&buf, &max, "\"p\":[]"); + } else if (num_parents == 1) { + ret += fwdprintf(&buf, &max, "\"p\":[\"%016"PRIx64"\"]", + span->parent.single); + } else if (num_parents > 1) { + ret += fwdprintf(&buf, &max, "\"p\":["); + for (i = 0; i < num_parents; i++) { + ret += fwdprintf(&buf, &max, "%s\"%016" PRIx64 "\"", prefix, + span->parent.list[i]); + prefix = ","; + } + ret += fwdprintf(&buf, &max, "]"); + } + ret += fwdprintf(&buf, &max, "}"); + // Add one to 'ret' to take into account the terminating null that we + // need to write. + return ret + 1; +} + +int span_json_size(const struct htrace_span *scope) +{ + return span_json_sprintf_impl(scope, 0, NULL); +} + +void span_json_sprintf(const struct htrace_span *scope, int max, void *buf) +{ + span_json_sprintf_impl(scope, max, buf); +} + +// vim:ts=4:sw=4:et http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/src/core/span.h ---------------------------------------------------------------------- diff --git a/htrace-c/src/core/span.h b/htrace-c/src/core/span.h new file mode 100644 index 0000000..b19bd94 --- /dev/null +++ b/htrace-c/src/core/span.h @@ -0,0 +1,138 @@ +/** + * 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. + */ + +#ifndef APACHE_HTRACE_SPAN_H +#define APACHE_HTRACE_SPAN_H + +/** + * @file span.h + * + * Functions related to HTrace spans and trace scopes. + * + * This is an internal header, not intended for external use. + */ + +#include <stdint.h> + +struct htracer; + +struct htrace_span { + /** + * The name of this trace scope. + * Dynamically allocated. Will never be NULL. + */ + char *desc; + + /** + * The beginning time in wall-clock milliseconds. + */ + uint64_t begin_ms; + + /** + * The end time in wall-clock milliseconds. + */ + uint64_t end_ms; + + /** + * The span id. + */ + uint64_t span_id; + + /** + * The process ID of this trace scope. + * Dynamically allocated. May be null. + */ + char *prid; + + /** + * The number of parents. + */ + int num_parents; + + union { + /** + * If there is 1 parent, this is the parent ID. + */ + uint64_t single; + + /** + * If there are multiple parents, this is a pointer to a dynamically + * allocated array of parent IDs. + */ + uint64_t *list; + } parent; +}; + +/** + * Allocate an htrace span. + * + * @param desc The span name to use. Will be deep-copied. + * @param begin_ms The value to use for begin_ms. + * @param span_id The span ID to use. + * + * @return NULL on OOM; the span otherwise. + */ +struct htrace_span *htrace_span_alloc(const char *desc, + uint64_t begin_ms, uint64_t span_id); + +/** + * Free the memory associated with an htrace span. + * + * @param span The span to free. + */ +void htrace_span_free(struct htrace_span *span); + +/** + * Sort and deduplicate the parents array within the span. + * + * @param span The span to process. + */ +void htrace_span_sort_and_dedupe_parents(struct htrace_span *span); + +/** + * Escape a JSON string. Specifically, put backslashes before double quotes and + * other backslashes. + * + * @param in The string to escape. + * + * @param out The escaped string. Malloced. NULL on OOM. + */ +char *json_escape(const char *in); + +/** + * Get the buffer size that would be needed to serialize this span to a buffer. + * + * @param span The span. + * + * @return The buffer size in bytes. This will never be less + * than 1. + */ +int span_json_size(const struct htrace_span *span); + +/** + * Get the buffer size that would be needed to serialize this span to a buffer. + * + * @param span The span. + * + * @return The buffer size in bytes. + */ +void span_json_sprintf(const struct htrace_span *span, int max, void *buf); + +#endif + +// vim: ts=4:sw=4:et http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/src/receiver/curl.c ---------------------------------------------------------------------- diff --git a/htrace-c/src/receiver/curl.c b/htrace-c/src/receiver/curl.c new file mode 100644 index 0000000..0905dd4 --- /dev/null +++ b/htrace-c/src/receiver/curl.c @@ -0,0 +1,124 @@ +/** + * 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 "util/log.h" + +#include <curl/curl.h> +#include <pthread.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/** + * Unfortunately, libcurl requires a non-threadsafe initialization function to + * be called before it is usable. This is unfortunate for a library like + * libhtrace, which is designed to be used in a multi-threaded context. + * + * This mutex protects us against an application creating two htraced receivers + * at around the same time, and calling that non-threadsafe initialization + * function. + * + * Of course, this doesn't protect us against the application also initializing + * libcurl. We can protect against that by statically linking a private copy of + * libcurl into libhtrace, so that we will be initializing and using our own + * private copy of libcurl rather than the application's. + */ +static pthread_mutex_t g_curl_refcnt_lock = PTHREAD_MUTEX_INITIALIZER; + +/** + * The current number of CURL handles that are open. + */ +static int64_t g_curl_refcnt; + +static int curl_addref(struct htrace_log *lg) +{ + int success = 0; + CURLcode curl_err = 0; + + pthread_mutex_lock(&g_curl_refcnt_lock); + if (g_curl_refcnt >= 1) { + g_curl_refcnt++; + success = 1; + goto done; + } + curl_err = curl_global_init(CURL_GLOBAL_ALL); + if (curl_err) { + htrace_log(lg, "curl_global_init failed: error %d (%s)\n", + curl_err, curl_easy_strerror(curl_err)); + goto done; + } + htrace_log(lg, "successfully initialized libcurl...\n"); + g_curl_refcnt = 1; + success = 1; + +done: + pthread_mutex_unlock(&g_curl_refcnt_lock); + return success; +} + +static void curl_unref(struct htrace_log *lg) +{ + pthread_mutex_lock(&g_curl_refcnt_lock); + g_curl_refcnt--; + if (g_curl_refcnt > 0) { + goto done; + } + curl_global_cleanup(); + htrace_log(lg, "shut down libcurl...\n"); +done: + pthread_mutex_unlock(&g_curl_refcnt_lock); +} + +CURL* htrace_curl_init(struct htrace_log *lg, const struct htrace_conf *conf) +{ + CURL *curl = NULL; + int success = 0; + + if (!curl_addref(lg)) { + return NULL; + } + curl = curl_easy_init(); + if (!curl) { + htrace_log(lg, "curl_easy_init failed.\n"); + goto done; + } + success = 1; + +done: + if (!success) { + if (curl) { + curl_easy_cleanup(curl); + } + curl_unref(lg); + return NULL; + } + return curl; +} + +void htrace_curl_free(struct htrace_log *lg, CURL *curl) +{ + if (!curl) { + return; + } + curl_easy_cleanup(curl); + curl_unref(lg); +} + +// vim:ts=4:sw=4:et http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/a9d85254/htrace-c/src/receiver/curl.h ---------------------------------------------------------------------- diff --git a/htrace-c/src/receiver/curl.h b/htrace-c/src/receiver/curl.h new file mode 100644 index 0000000..9249cd3 --- /dev/null +++ b/htrace-c/src/receiver/curl.h @@ -0,0 +1,60 @@ +/** + * 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. + */ + +#ifndef APACHE_HTRACE_RECEIVER_CURL_H +#define APACHE_HTRACE_RECEIVER_CURL_H + +/** + * @file curl.h + * + * Utility functions wrapping libcurl. + * + * This is an internal header, not intended for external use. + */ + +#include <curl/curl.h> // for the CURL type + +struct htrace_conf; +struct htrace_log; + +/** + * Initialize a libcurl handle. + * + * This function also takes care of calling curl_global_init if necessary. + * + * @param lg The HTrace log to use for error messages. + * @param conf The HTrace configuration to use. + * + * @return A libcurl handle, or NULL on failure. + */ +CURL* htrace_curl_init(struct htrace_log *lg, const struct htrace_conf *conf); + +/** + * Free a libcurl handle. + * + * This function also takes care of calling curl_global_cleanup if necessary. + * + * @param lg The HTrace log to use for error messages. + * + * @param curl The libcurl handle. + */ +void htrace_curl_free(struct htrace_log *lg, CURL *curl); + +#endif + +// vim: ts=4: sw=4: et
