Skip to content

Extend network response with diagnostics #1588

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 10, 2025
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
55 changes: 52 additions & 3 deletions olp-cpp-sdk-core/include/olp/core/http/NetworkResponse.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2020 HERE Europe B.V.
* Copyright (C) 2019-2025 HERE Europe B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,13 +19,44 @@

#pragma once

#include <array>
#include <bitset>
#include <chrono>
#include <string>

#include <boost/optional/optional.hpp>

#include <olp/core/CoreApi.h>
#include <olp/core/http/NetworkTypes.h>

namespace olp {
namespace http {

/**
* @brief Network request timings.
*/
struct Diagnostics {
using MicroSeconds = std::chrono::duration<uint32_t, std::micro>;

enum Timings {
Queue = 0, // Delay until the request is processed
NameLookup, // Time taken for DNS name lookup
Connect, // Time taken to establish connection
SSL_Handshake, // Time taken to establish a secured connection
Send, // Time taken to send the request
Wait, // Time delay until server starts responding
Receive, // Time taken to receive the response
Total, // Total time taken for reqeust
Count
};

/// Timing values
std::array<MicroSeconds, Count> timings{};

/// Availability flag, specify which timing is available
std::bitset<Count> available_timings{};
};

/**
* @brief A network response abstraction for the HTTP request.
*/
Expand Down Expand Up @@ -126,6 +157,22 @@ class CORE_API NetworkResponse final {
*/
NetworkResponse& WithBytesDownloaded(uint64_t bytes_downloaded);

/**
* @brief Gets the optional diagnostics if set.
*
* @return Diagnostic values.
*/
const boost::optional<Diagnostics>& GetDiagnostics() const;

/**
* @brief Sets the request diagnostics.
*
* @param diagnostics Diagnostics values.
*
* @return A reference to *this.
*/
NetworkResponse& WithDiagnostics(Diagnostics diagnostics);

private:
/// The associated request ID.
RequestId request_id_{0};
Expand All @@ -134,9 +181,11 @@ class CORE_API NetworkResponse final {
/// The human-readable error message if the associated request failed.
std::string error_;
/// The number of bytes uploaded during the network request.
uint64_t bytes_uploaded_;
uint64_t bytes_uploaded_{0};
/// The number of bytes downloaded during the network request.
uint64_t bytes_downloaded_;
uint64_t bytes_downloaded_{0};
/// Diagnostics
boost::optional<Diagnostics> diagnostics_;
};

} // namespace http
Expand Down
11 changes: 10 additions & 1 deletion olp-cpp-sdk-core/src/http/NetworkResponse.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2020 HERE Europe B.V.
* Copyright (C) 2019-2025 HERE Europe B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -65,5 +65,14 @@
return *this;
}

NetworkResponse& NetworkResponse::WithDiagnostics(Diagnostics diagnostics) {
diagnostics_ = diagnostics;
return *this;

Check warning on line 70 in olp-cpp-sdk-core/src/http/NetworkResponse.cpp

View check run for this annotation

Codecov / codecov/patch

olp-cpp-sdk-core/src/http/NetworkResponse.cpp#L68-L70

Added lines #L68 - L70 were not covered by tests
}

const boost::optional<Diagnostics>& NetworkResponse::GetDiagnostics() const {
return diagnostics_;

Check warning on line 74 in olp-cpp-sdk-core/src/http/NetworkResponse.cpp

View check run for this annotation

Codecov / codecov/patch

olp-cpp-sdk-core/src/http/NetworkResponse.cpp#L73-L74

Added lines #L73 - L74 were not covered by tests
}

} // namespace http
} // namespace olp
50 changes: 48 additions & 2 deletions olp-cpp-sdk-core/src/http/curl/NetworkCurl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,49 @@ void SetupDns(CURL* curl_handle, const std::vector<std::string>& dns_servers) {
#endif
}

Diagnostics GetDiagnostics(CURL* handle) {
Diagnostics diagnostics;

static const std::pair<Diagnostics::Timings, CURLINFO> available_timings[] = {
#if CURL_AT_LEAST_VERSION(8, 6, 0)
{Diagnostics::Queue, CURLINFO_QUEUE_TIME_T},
#endif
{Diagnostics::NameLookup, CURLINFO_NAMELOOKUP_TIME_T},
{Diagnostics::Connect, CURLINFO_CONNECT_TIME_T},
{Diagnostics::SSL_Handshake, CURLINFO_APPCONNECT_TIME_T},
#if CURL_AT_LEAST_VERSION(8, 10, 0)
{Diagnostics::Send, CURLINFO_POSTTRANSFER_TIME_T},
{Diagnostics::Wait, CURLINFO_STARTTRANSFER_TIME_T},
#else
{Diagnostics::Send, CURLINFO_STARTTRANSFER_TIME_T},
#endif
{Diagnostics::Receive, CURLINFO_TOTAL_TIME_T},
};

curl_off_t last_time_point{0};

auto add_timing = [&](Diagnostics::Timings timing,
Diagnostics::MicroSeconds time) {
diagnostics.timings[timing] = time;
diagnostics.available_timings.set(timing);
};

for (const auto& available_timing : available_timings) {
curl_off_t time_point_us = 0;
if (curl_easy_getinfo(handle, available_timing.second, &time_point_us) ==
CURLE_OK &&
time_point_us > 0) {
add_timing(available_timing.first,
Diagnostics::MicroSeconds(time_point_us - last_time_point));
last_time_point = time_point_us;
}
}

add_timing(Diagnostics::Total, Diagnostics::MicroSeconds(last_time_point));

return diagnostics;
}

} // anonymous namespace

NetworkCurl::NetworkCurl(NetworkInitializationSettings settings)
Expand Down Expand Up @@ -1004,7 +1047,8 @@ void NetworkCurl::CompleteMessage(CURL* curl_handle, CURLcode result) {
auto response = NetworkResponse()
.WithRequestId(request_handle->id)
.WithBytesDownloaded(download_bytes)
.WithBytesUploaded(upload_bytes);
.WithBytesUploaded(upload_bytes)
.WithDiagnostics(GetDiagnostics(curl_handle));

if (request_handle->is_cancelled) {
response.WithStatus(static_cast<int>(ErrorCode::CANCELLED_ERROR))
Expand Down Expand Up @@ -1199,7 +1243,9 @@ void NetworkCurl::Run() {
.WithStatus(static_cast<int>(ErrorCode::IO_ERROR))
.WithError("CURL error")
.WithBytesDownloaded(download_bytes)
.WithBytesUploaded(upload_bytes);
.WithBytesUploaded(upload_bytes)
.WithDiagnostics(GetDiagnostics(curl_handle));

callback(response);
lock.lock();
}
Expand Down
Loading