Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 37 additions & 24 deletions src/datadog/curl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ CURLcode CurlLibrary::easy_setopt_writefunction(CURL *handle,
return curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, on_write);
}

CURLcode CurlLibrary::easy_setopt_timeout(CURL *handle, long timeout_ms) {
CURLcode CurlLibrary::easy_setopt_timeout_ms(CURL *handle, long timeout_ms) {
return curl_easy_setopt(handle, CURLOPT_TIMEOUT_MS, timeout_ms);
}

Expand Down Expand Up @@ -167,14 +167,14 @@ class CurlImpl {
std::mutex mutex_;
CurlLibrary &curl_;
const std::shared_ptr<Logger> logger_;
Clock clock_;
CURLM *multi_handle_;
std::unordered_set<CURL *> request_handles_;
std::list<CURL *> new_handles_;
bool shutting_down_;
int num_active_handles_;
std::condition_variable no_requests_;
std::thread event_loop_;
Clock clock_;

struct Request {
CurlLibrary *curl = nullptr;
Expand All @@ -185,7 +185,7 @@ class CurlImpl {
char error_buffer[CURL_ERROR_SIZE] = "";
std::unordered_map<std::string, std::string> response_headers_lower;
std::string response_body;
HTTPClient::Deadline deadline;
std::chrono::steady_clock::time_point deadline;

~Request();
};
Expand Down Expand Up @@ -228,13 +228,14 @@ class CurlImpl {
static StringView trim(StringView);

public:
explicit CurlImpl(const std::shared_ptr<Logger> &, CurlLibrary &,
const Curl::ThreadGenerator &);
explicit CurlImpl(const std::shared_ptr<Logger> &, const Clock &,
CurlLibrary &, const Curl::ThreadGenerator &);
~CurlImpl();

Expected<void> post(const URL &url, HeadersSetter set_headers,
std::string body, ResponseHandler on_response,
ErrorHandler on_error, HTTPClient::Deadline deadline);
ErrorHandler on_error,
std::chrono::steady_clock::time_point deadline);

void drain(std::chrono::steady_clock::time_point deadline);
};
Expand All @@ -249,21 +250,24 @@ void throw_on_error(CURLcode result) {

} // namespace

Curl::Curl(const std::shared_ptr<Logger> &logger) : Curl(logger, libcurl) {}
Curl::Curl(const std::shared_ptr<Logger> &logger, const Clock &clock)
: Curl(logger, clock, libcurl) {}

Curl::Curl(const std::shared_ptr<Logger> &logger, CurlLibrary &curl)
: Curl(logger, curl,
Curl::Curl(const std::shared_ptr<Logger> &logger, const Clock &clock,
CurlLibrary &curl)
: Curl(logger, clock, curl,
[](auto &&func) { return std::thread(std::move(func)); }) {}

Curl::Curl(const std::shared_ptr<Logger> &logger, CurlLibrary &curl,
const Curl::ThreadGenerator &make_thread)
: impl_(new CurlImpl{logger, curl, make_thread}) {}
Curl::Curl(const std::shared_ptr<Logger> &logger, const Clock &clock,
CurlLibrary &curl, const Curl::ThreadGenerator &make_thread)
: impl_(new CurlImpl{logger, clock, curl, make_thread}) {}

Curl::~Curl() { delete impl_; }

Expected<void> Curl::post(const URL &url, HeadersSetter set_headers,
std::string body, ResponseHandler on_response,
ErrorHandler on_error, Deadline deadline) {
ErrorHandler on_error,
std::chrono::steady_clock::time_point deadline) {
return impl_->post(url, set_headers, body, on_response, on_error, deadline);
}

Expand All @@ -275,10 +279,11 @@ nlohmann::json Curl::config_json() const {
return nlohmann::json::object({{"type", "datadog::tracing::Curl"}});
}

CurlImpl::CurlImpl(const std::shared_ptr<Logger> &logger, CurlLibrary &curl,
const Curl::ThreadGenerator &make_thread)
CurlImpl::CurlImpl(const std::shared_ptr<Logger> &logger, const Clock &clock,
CurlLibrary &curl, const Curl::ThreadGenerator &make_thread)
: curl_(curl),
logger_(logger),
clock_(clock),
shutting_down_(false),
num_active_handles_(0) {
curl_.global_init(CURL_GLOBAL_ALL);
Expand Down Expand Up @@ -323,11 +328,10 @@ CurlImpl::~CurlImpl() {
curl_.global_cleanup();
}

Expected<void> CurlImpl::post(const HTTPClient::URL &url,
HeadersSetter set_headers, std::string body,
ResponseHandler on_response,
ErrorHandler on_error,
HTTPClient::Deadline deadline) try {
Expected<void> CurlImpl::post(
const HTTPClient::URL &url, HeadersSetter set_headers, std::string body,
ResponseHandler on_response, ErrorHandler on_error,
std::chrono::steady_clock::time_point deadline) try {
if (multi_handle_ == nullptr) {
return Error{Error::CURL_HTTP_CLIENT_NOT_RUNNING,
"Unable to send request via libcurl because the HTTP client "
Expand Down Expand Up @@ -509,18 +513,27 @@ void CurlImpl::run() {

auto *request = reinterpret_cast<Request *>(user_data);
const auto timeout = request->deadline - clock_().tick;
if (timeout <= HTTPClient::Deadline::duration::zero()) {
if (timeout <= std::chrono::steady_clock::time_point::duration::zero()) {
std::string message;
message +=
"Request deadline exceeded before request was even added to "
"libcurl "
"event loop. Deadline was ";
message += std::to_string(
-std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
.count());
message += " nanoseconds ago.";
Comment on lines +517 to +525
Copy link
Copy Markdown
Contributor

@dmehala dmehala Nov 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

evangelist hat May I suggest libfmt? It is header-only 😀
The fmt version would like look:

std::string message = fmt::format("Request deadline exceeded before request was even added to libcurl event loop. Deadline was {} nanoseconds ago.", std::chrono::duration_cast<std::chrono::nanoseconds>(timeout));

Much much easier to read and less error-prone right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not header-only:

david@ein:~/src/fmt$ cat scratch.cpp 
#include <fmt/core.h>
#include <fmt/chrono.h>

#include <chrono>

int main() {
  const auto delay = std::chrono::microseconds(4);
  fmt::print("The delay was {}.", delay);
}

david@ein:~/src/fmt$ g++ -I include scratch.cpp
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `main':
scratch.cpp:(.text+0x8e): undefined reference to `fmt::v10::vprint(fmt::v10::basic_string_view<char>, fmt::v10::basic_format_args<fmt::v10::basic_format_context<fmt::v10::appender, char> >)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `fmt::v10::detail::error_handler::on_error(char const*)':
scratch.cpp:(.text._ZN3fmt3v106detail13error_handler8on_errorEPKc[_ZN3fmt3v106detail13error_handler8on_errorEPKc]+0xe): undefined reference to `fmt::v10::detail::throw_format_error(char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `std::make_unsigned<int>::type fmt::v10::detail::to_unsigned<int>(int)':
scratch.cpp:(.text._ZN3fmt3v106detail11to_unsignedIiEENSt13make_unsignedIT_E4typeES4_[_ZN3fmt3v106detail11to_unsignedIiEENSt13make_unsignedIT_E4typeES4_]+0x23): undefined reference to `fmt::v10::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `fmt::v10::detail::needs_escape(unsigned int)':
scratch.cpp:(.text._ZN3fmt3v106detail12needs_escapeEj[_ZN3fmt3v106detail12needs_escapeEj]+0x2d): undefined reference to `fmt::v10::detail::is_printable(unsigned int)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `fmt::v10::detail::get_locale::get_locale(bool, fmt::v10::detail::locale_ref)':
scratch.cpp:(.text._ZN3fmt3v106detail10get_localeC2EbNS1_10locale_refE[_ZN3fmt3v106detail10get_localeC5EbNS1_10locale_refE]+0x5d): undefined reference to `std::locale fmt::v10::detail::locale_ref::get<std::locale>() const'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `std::make_unsigned<long>::type fmt::v10::detail::to_unsigned<long>(long)':
scratch.cpp:(.text._ZN3fmt3v106detail11to_unsignedIlEENSt13make_unsignedIT_E4typeES4_[_ZN3fmt3v106detail11to_unsignedIlEENSt13make_unsignedIT_E4typeES4_]+0x25): undefined reference to `fmt::v10::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `fmt::v10::detail::format_decimal_result<char*> fmt::v10::detail::format_decimal<char, unsigned int>(char*, unsigned int, int)':
scratch.cpp:(.text._ZN3fmt3v106detail14format_decimalIcjEENS1_21format_decimal_resultIPT_EES5_T0_i[_ZN3fmt3v106detail14format_decimalIcjEENS1_21format_decimal_resultIPT_EES5_T0_i]+0x43): undefined reference to `fmt::v10::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `fmt::v10::detail::format_decimal_result<char*> fmt::v10::detail::format_decimal<char, unsigned long>(char*, unsigned long, int)':
scratch.cpp:(.text._ZN3fmt3v106detail14format_decimalIcmEENS1_21format_decimal_resultIPT_EES5_T0_i[_ZN3fmt3v106detail14format_decimalIcmEENS1_21format_decimal_resultIPT_EES5_T0_i]+0x46): undefined reference to `fmt::v10::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `char const* fmt::v10::detail::parse_align<char>(char const*, char const*, fmt::v10::format_specs<char>&)':
scratch.cpp:(.text._ZN3fmt3v106detail11parse_alignIcEEPKT_S5_S5_RNS0_12format_specsIS3_EE[_ZN3fmt3v106detail11parse_alignIcEEPKT_S5_S5_RNS0_12format_specsIS3_EE]+0x4c): undefined reference to `fmt::v10::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: scratch.cpp:(.text._ZN3fmt3v106detail11parse_alignIcEEPKT_S5_S5_RNS0_12format_specsIS3_EE[_ZN3fmt3v106detail11parse_alignIcEEPKT_S5_S5_RNS0_12format_specsIS3_EE]+0x100): undefined reference to `fmt::v10::detail::throw_format_error(char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `char const* fmt::v10::detail::parse_dynamic_spec<char>(char const*, char const*, int&, fmt::v10::detail::arg_ref<char>&, fmt::v10::basic_format_parse_context<char>&)':
scratch.cpp:(.text._ZN3fmt3v106detail18parse_dynamic_specIcEEPKT_S5_S5_RiRNS1_7arg_refIS3_EERNS0_26basic_format_parse_contextIS3_EE[_ZN3fmt3v106detail18parse_dynamic_specIcEEPKT_S5_S5_RiRNS1_7arg_refIS3_EERNS0_26basic_format_parse_contextIS3_EE]+0x71): undefined reference to `fmt::v10::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: scratch.cpp:(.text._ZN3fmt3v106detail18parse_dynamic_specIcEEPKT_S5_S5_RiRNS1_7arg_refIS3_EERNS0_26basic_format_parse_contextIS3_EE[_ZN3fmt3v106detail18parse_dynamic_specIcEEPKT_S5_S5_RiRNS1_7arg_refIS3_EERNS0_26basic_format_parse_contextIS3_EE]+0x9a): undefined reference to `fmt::v10::detail::throw_format_error(char const*)'
/usr/bin/ld: scratch.cpp:(.text._ZN3fmt3v106detail18parse_dynamic_specIcEEPKT_S5_S5_RiRNS1_7arg_refIS3_EERNS0_26basic_format_parse_contextIS3_EE[_ZN3fmt3v106detail18parse_dynamic_specIcEEPKT_S5_S5_RiRNS1_7arg_refIS3_EERNS0_26basic_format_parse_contextIS3_EE]+0x111): undefined reference to `fmt::v10::detail::throw_format_error(char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `char const* fmt::v10::detail::parse_precision<char>(char const*, char const*, int&, fmt::v10::detail::arg_ref<char>&, fmt::v10::basic_format_parse_context<char>&)':
scratch.cpp:(.text._ZN3fmt3v106detail15parse_precisionIcEEPKT_S5_S5_RiRNS1_7arg_refIS3_EERNS0_26basic_format_parse_contextIS3_EE[_ZN3fmt3v106detail15parse_precisionIcEEPKT_S5_S5_RiRNS1_7arg_refIS3_EERNS0_26basic_format_parse_contextIS3_EE]+0x2c): undefined reference to `fmt::v10::detail::throw_format_error(char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `fmt::v10::detail::fill_t<char>::operator=(fmt::v10::basic_string_view<char>)':
scratch.cpp:(.text._ZN3fmt3v106detail6fill_tIcEaSENS0_17basic_string_viewIcEE[_ZN3fmt3v106detail6fill_tIcEaSENS0_17basic_string_viewIcEE]+0x45): undefined reference to `fmt::v10::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `int fmt::v10::detail::parse_nonnegative_int<char>(char const*&, char const*, int)':
scratch.cpp:(.text._ZN3fmt3v106detail21parse_nonnegative_intIcEEiRPKT_S5_i[_ZN3fmt3v106detail21parse_nonnegative_intIcEEiRPKT_S5_i]+0x7a): undefined reference to `fmt::v10::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `int fmt::v10::detail::to_nonnegative_int<long, int, 0>(long, int)':
scratch.cpp:(.text._ZN3fmt3v106detail18to_nonnegative_intIliLi0EEET0_T_S3_[_ZN3fmt3v106detail18to_nonnegative_intIliLi0EEET0_T_S3_]+0x55): undefined reference to `fmt::v10::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `char const* fmt::v10::detail::do_parse_arg_id<char, fmt::v10::detail::dynamic_spec_id_handler<char>&>(char const*, char const*, fmt::v10::detail::dynamic_spec_id_handler<char>&)':
scratch.cpp:(.text._ZN3fmt3v106detail15do_parse_arg_idIcRNS1_23dynamic_spec_id_handlerIcEEEEPKT_S8_S8_OT0_[_ZN3fmt3v106detail15do_parse_arg_idIcRNS1_23dynamic_spec_id_handlerIcEEEEPKT_S8_S8_OT0_]+0x8f): undefined reference to `fmt::v10::detail::throw_format_error(char const*)'
/usr/bin/ld: scratch.cpp:(.text._ZN3fmt3v106detail15do_parse_arg_idIcRNS1_23dynamic_spec_id_handlerIcEEEEPKT_S8_S8_OT0_[_ZN3fmt3v106detail15do_parse_arg_idIcRNS1_23dynamic_spec_id_handlerIcEEEEPKT_S8_S8_OT0_]+0x11d): undefined reference to `fmt::v10::detail::throw_format_error(char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `fmt::v10::detail::tm_writer<std::back_insert_iterator<fmt::v10::basic_memory_buffer<char, 500ul, std::allocator<char> > >, char, std::chrono::duration<long, std::ratio<1l, 1l> > >::tm_hour() const':
scratch.cpp:(.text._ZNK3fmt3v106detail9tm_writerISt20back_insert_iteratorINS0_19basic_memory_bufferIcLm500ESaIcEEEEcNSt6chrono8durationIlSt5ratioILl1ELl1EEEEE7tm_hourEv[_ZNK3fmt3v106detail9tm_writerISt20back_insert_iteratorINS0_19basic_memory_bufferIcLm500ESaIcEEEEcNSt6chrono8durationIlSt5ratioILl1ELl1EEEEE7tm_hourEv]+0x49): undefined reference to `fmt::v10::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `fmt::v10::detail::tm_writer<std::back_insert_iterator<fmt::v10::basic_memory_buffer<char, 500ul, std::allocator<char> > >, char, std::chrono::duration<long, std::ratio<1l, 1l> > >::tm_min() const':
scratch.cpp:(.text._ZNK3fmt3v106detail9tm_writerISt20back_insert_iteratorINS0_19basic_memory_bufferIcLm500ESaIcEEEEcNSt6chrono8durationIlSt5ratioILl1ELl1EEEEE6tm_minEv[_ZNK3fmt3v106detail9tm_writerISt20back_insert_iteratorINS0_19basic_memory_bufferIcLm500ESaIcEEEEcNSt6chrono8durationIlSt5ratioILl1ELl1EEEEE6tm_minEv]+0x49): undefined reference to `fmt::v10::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `std::make_unsigned<long long>::type fmt::v10::detail::to_unsigned<long long>(long long)':
scratch.cpp:(.text._ZN3fmt3v106detail11to_unsignedIxEENSt13make_unsignedIT_E4typeES4_[_ZN3fmt3v106detail11to_unsignedIxEENSt13make_unsignedIT_E4typeES4_]+0x25): undefined reference to `fmt::v10::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `fmt::v10::detail::tm_writer<std::back_insert_iterator<fmt::v10::basic_memory_buffer<char, 500ul, std::allocator<char> > >, char, std::chrono::duration<long, std::ratio<1l, 1l> > >::tm_sec() const':
scratch.cpp:(.text._ZNK3fmt3v106detail9tm_writerISt20back_insert_iteratorINS0_19basic_memory_bufferIcLm500ESaIcEEEEcNSt6chrono8durationIlSt5ratioILl1ELl1EEEEE6tm_secEv[_ZNK3fmt3v106detail9tm_writerISt20back_insert_iteratorINS0_19basic_memory_bufferIcLm500ESaIcEEEEcNSt6chrono8durationIlSt5ratioILl1ELl1EEEEE6tm_secEv]+0x47): undefined reference to `fmt::v10::detail::assert_fail(char const*, int, char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `fmt::v10::basic_format_parse_context<char>::next_arg_id()':
scratch.cpp:(.text._ZN3fmt3v1026basic_format_parse_contextIcE11next_arg_idEv[_ZN3fmt3v1026basic_format_parse_contextIcE11next_arg_idEv]+0x1e): undefined reference to `fmt::v10::detail::throw_format_error(char const*)'
/usr/bin/ld: /tmp/ccdUMaH7.o: in function `fmt::v10::basic_format_parse_context<char>::check_arg_id(int)':
scratch.cpp:(.text._ZN3fmt3v1026basic_format_parse_contextIcE12check_arg_idEi[_ZN3fmt3v1026basic_format_parse_contextIcE12check_arg_idEi]+0x1e): undefined reference to `fmt::v10::detail::throw_format_error(char const*)'
collect2: error: ld returned 1 exit status

And, not that this matters much, it's a lot more code:

david@ein:~/src/fmt$ g++ -I include -E scratch.cpp | wc -l
82663
david@ein:~/src/fmt$ cat nofmt.cpp 
#include <chrono>
#include <string>

extern "C" int puts(const char*);

int main() {
  const auto delay = std::chrono::microseconds(4);
  std::string message;
  message += "The delay was ";
  message += std::to_string(std::chrono::duration_cast<std::chrono::nanoseconds>(delay).count());
  message += " nanoseconds.";
  puts(message.c_str());
}

david@ein:~/src/fmt$ g++ -I include -E nofmt.cpp | wc -l
26112

std::format is in C++20, so we could use that in the next tracing library. :)

request->on_error(
Error{Error::CURL_REQUEST_FAILURE,
"Request not processed as the deadline has been reached."});
Error{Error::CURL_DEADLINE_EXCEEDED_BEFORE_REQUEST_START,
std::move(message)});

curl_.easy_cleanup(handle);
delete request;

continue;
}

throw_on_error(curl_.easy_setopt_timeout(
log_on_error(curl_.easy_setopt_timeout_ms(
handle, std::chrono::duration_cast<std::chrono::milliseconds>(timeout)
.count()));
log_on_error(curl_.multi_add_handle(multi_handle_, handle));
Expand Down
13 changes: 8 additions & 5 deletions src/datadog/curl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <string>
#include <thread>

#include "clock.h"
#include "http_client.h"
#include "json_fwd.hpp"

Expand Down Expand Up @@ -59,7 +60,7 @@ class CurlLibrary {
virtual CURLcode easy_setopt_url(CURL *handle, const char *url);
virtual CURLcode easy_setopt_writedata(CURL *handle, void *data);
virtual CURLcode easy_setopt_writefunction(CURL *handle, WriteCallback);
virtual CURLcode easy_setopt_timeout(CURL *handle, long timeout_ms);
virtual CURLcode easy_setopt_timeout_ms(CURL *handle, long timeout_ms);
virtual const char *easy_strerror(CURLcode error);
virtual void global_cleanup();
virtual CURLcode global_init(long flags);
Expand Down Expand Up @@ -87,16 +88,18 @@ class Curl : public HTTPClient {
public:
using ThreadGenerator = std::function<std::thread(std::function<void()> &&)>;

explicit Curl(const std::shared_ptr<Logger> &);
Curl(const std::shared_ptr<Logger> &, CurlLibrary &);
Curl(const std::shared_ptr<Logger> &, CurlLibrary &, const ThreadGenerator &);
explicit Curl(const std::shared_ptr<Logger> &, const Clock &);
Curl(const std::shared_ptr<Logger> &, const Clock &, CurlLibrary &);
Curl(const std::shared_ptr<Logger> &, const Clock &, CurlLibrary &,
const ThreadGenerator &);
~Curl();

Curl(const Curl &) = delete;

Expected<void> post(const URL &url, HeadersSetter set_headers,
std::string body, ResponseHandler on_response,
ErrorHandler on_error, Deadline deadline) override;
ErrorHandler on_error,
std::chrono::steady_clock::time_point deadline) override;

void drain(std::chrono::steady_clock::time_point deadline) override;

Expand Down
3 changes: 1 addition & 2 deletions src/datadog/datadog_agent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,8 @@ std::variant<CollectorResponse, std::string> parse_agent_traces_response(
} // namespace

DatadogAgent::DatadogAgent(const FinalizedDatadogAgentConfig& config,
const Clock& clock,
const std::shared_ptr<Logger>& logger)
: clock_(clock),
: clock_(config.clock),
logger_(logger),
traces_endpoint_(traces_endpoint(config.url)),
http_client_(config.http_client),
Expand Down
2 changes: 1 addition & 1 deletion src/datadog/datadog_agent.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class DatadogAgent : public Collector {
void flush();

public:
DatadogAgent(const FinalizedDatadogAgentConfig&, const Clock& clock,
DatadogAgent(const FinalizedDatadogAgentConfig&,
const std::shared_ptr<Logger>&);
~DatadogAgent();

Expand Down
7 changes: 5 additions & 2 deletions src/datadog/datadog_agent_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,14 @@ Expected<HTTPClient::URL> DatadogAgentConfig::parse(StringView input) {
}

Expected<FinalizedDatadogAgentConfig> finalize_config(
const DatadogAgentConfig& config, const std::shared_ptr<Logger>& logger) {
const DatadogAgentConfig& config, const std::shared_ptr<Logger>& logger,
const Clock& clock) {
FinalizedDatadogAgentConfig result;

result.clock = clock;

if (!config.http_client) {
result.http_client = default_http_client(logger);
result.http_client = default_http_client(logger, clock);
// `default_http_client` might return a `Curl` instance depending on how
// this library was built. If it returns `nullptr`, then there's no
// built-in default, and so the user must provide a value.
Expand Down
7 changes: 5 additions & 2 deletions src/datadog/datadog_agent_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <string>
#include <variant>

#include "clock.h"
#include "expected.h"
#include "http_client.h"
#include "string_view.h"
Expand Down Expand Up @@ -59,7 +60,7 @@ struct DatadogAgentConfig {

class FinalizedDatadogAgentConfig {
friend Expected<FinalizedDatadogAgentConfig> finalize_config(
const DatadogAgentConfig& config, const std::shared_ptr<Logger>& logger);
const DatadogAgentConfig&, const std::shared_ptr<Logger>&, const Clock&);

FinalizedDatadogAgentConfig() = default;

Expand All @@ -70,10 +71,12 @@ class FinalizedDatadogAgentConfig {
std::chrono::steady_clock::duration flush_interval;
std::chrono::steady_clock::duration request_timeout;
std::chrono::steady_clock::duration shutdown_timeout;
Clock clock;
};

Expected<FinalizedDatadogAgentConfig> finalize_config(
const DatadogAgentConfig& config, const std::shared_ptr<Logger>& logger);
const DatadogAgentConfig& config, const std::shared_ptr<Logger>& logger,
const Clock& clock);

} // namespace tracing
} // namespace datadog
4 changes: 3 additions & 1 deletion src/datadog/default_http_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@

#include <memory>

#include "clock.h"

namespace datadog {
namespace tracing {

class HTTPClient;
class Logger;

std::shared_ptr<HTTPClient> default_http_client(
const std::shared_ptr<Logger>& logger);
const std::shared_ptr<Logger>& logger, const Clock& clock);

} // namespace tracing
} // namespace datadog
4 changes: 2 additions & 2 deletions src/datadog/default_http_client_curl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ namespace datadog {
namespace tracing {

std::shared_ptr<HTTPClient> default_http_client(
const std::shared_ptr<Logger>& logger) {
return std::make_shared<Curl>(logger);
const std::shared_ptr<Logger>& logger, const Clock& clock) {
return std::make_shared<Curl>(logger, clock);
}

} // namespace tracing
Expand Down
4 changes: 2 additions & 2 deletions src/datadog/default_http_client_null.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
namespace datadog {
namespace tracing {

std::shared_ptr<HTTPClient> default_http_client(
const std::shared_ptr<Logger>&) {
std::shared_ptr<HTTPClient> default_http_client(const std::shared_ptr<Logger> &,
const Clock &) {
return nullptr;
}

Expand Down
1 change: 1 addition & 0 deletions src/datadog/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ struct Error {
MULTIPLE_PROPAGATION_STYLE_ENVIRONMENT_VARIABLES = 45,
DUPLICATE_PROPAGATION_STYLE = 46,
ZERO_TRACE_ID = 47,
CURL_DEADLINE_EXCEEDED_BEFORE_REQUEST_START = 48,
};

Code code;
Expand Down
10 changes: 5 additions & 5 deletions src/datadog/http_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class HTTPClient {
// `ErrorHandler` is for errors encountered by `HTTPClient`, not for
// error-indicating HTTP responses.
using ErrorHandler = std::function<void(Error)>;
using Deadline = std::chrono::steady_clock::time_point;

// Send a POST request to the specified `url`. Set request headers by calling
// the specified `set_headers` callback. Include the specified `body` at the
Expand All @@ -45,13 +44,14 @@ class HTTPClient {
// response status). Invoke the specified `on_error` if an error occurs
// outside of HTTP, such as a connection failure. If an error occurs while
// preparing the request, return an `Error`.
virtual Expected<void> post(const URL& url, HeadersSetter set_headers,
std::string body, ResponseHandler on_response,
ErrorHandler on_error, Deadline deadline) = 0;
virtual Expected<void> post(
const URL& url, HeadersSetter set_headers, std::string body,
ResponseHandler on_response, ErrorHandler on_error,
std::chrono::steady_clock::time_point deadline) = 0;

// Wait until there are no more outstanding requests, or until the specified
// `deadline`.
virtual void drain(Deadline deadline) = 0;
virtual void drain(std::chrono::steady_clock::time_point deadline) = 0;

// Return a JSON representation of this object's configuration. The JSON
// representation is an object with the following properties:
Expand Down
21 changes: 6 additions & 15 deletions src/datadog/tracer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,26 +200,18 @@ Expected<ExtractedData> extract_b3(
} // namespace

Tracer::Tracer(const FinalizedTracerConfig& config)
: Tracer(config, default_id_generator(config.trace_id_128_bit),
default_clock) {}
: Tracer(config, default_id_generator(config.trace_id_128_bit)) {}

Tracer::Tracer(const FinalizedTracerConfig& config,
const std::shared_ptr<const IDGenerator>& generator)
: Tracer(config, generator, default_clock) {}

Tracer::Tracer(const FinalizedTracerConfig& config, const Clock& clock)
: Tracer(config, default_id_generator(config.trace_id_128_bit), clock) {}

Tracer::Tracer(const FinalizedTracerConfig& config,
const std::shared_ptr<const IDGenerator>& generator,
const Clock& clock)
: logger_(config.logger),
collector_(/* see constructor body */),
trace_sampler_(
std::make_shared<TraceSampler>(config.trace_sampler, clock)),
span_sampler_(std::make_shared<SpanSampler>(config.span_sampler, clock)),
std::make_shared<TraceSampler>(config.trace_sampler, config.clock)),
span_sampler_(
std::make_shared<SpanSampler>(config.span_sampler, config.clock)),
generator_(generator),
clock_(clock),
clock_(config.clock),
defaults_(std::make_shared<SpanDefaults>(config.defaults)),
injection_styles_(config.injection_styles),
extraction_styles_(config.extraction_styles),
Expand All @@ -231,8 +223,7 @@ Tracer::Tracer(const FinalizedTracerConfig& config,
} else {
auto& agent_config =
std::get<FinalizedDatadogAgentConfig>(config.collector);
collector_ =
std::make_shared<DatadogAgent>(agent_config, clock, config.logger);
collector_ = std::make_shared<DatadogAgent>(agent_config, config.logger);
}

if (config.log_on_startup) {
Expand Down
4 changes: 0 additions & 4 deletions src/datadog/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ class Tracer {
explicit Tracer(const FinalizedTracerConfig& config);
Tracer(const FinalizedTracerConfig& config,
const std::shared_ptr<const IDGenerator>& generator);
Tracer(const FinalizedTracerConfig& config, const Clock& clock);
Tracer(const FinalizedTracerConfig& config,
const std::shared_ptr<const IDGenerator>& generator,
const Clock& clock);

// Create a new trace and return the root span of the trace. Optionally
// specify a `config` indicating the attributes of the root span.
Expand Down
Loading