Skip to content

Commit 8e72a42

Browse files
Extend network response with diagnostics
Implement request diagnostics for NetworkCurl. Add response timings for a request, it includes timings for: * queue time * dns resolution time * connect + ssl handshake time * send, wait, receive time * total time taken Relates-To: OCMAM-418 Signed-off-by: Mykhailo Kuchma <ext-mykhailo.kuchma@here.com>
1 parent 04fa9de commit 8e72a42

File tree

3 files changed

+110
-6
lines changed

3 files changed

+110
-6
lines changed

olp-cpp-sdk-core/include/olp/core/http/NetworkResponse.h

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2019-2020 HERE Europe B.V.
2+
* Copyright (C) 2019-2025 HERE Europe B.V.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,13 +19,44 @@
1919

2020
#pragma once
2121

22+
#include <array>
23+
#include <bitset>
24+
#include <chrono>
2225
#include <string>
2326

27+
#include <boost/optional/optional.hpp>
28+
2429
#include <olp/core/CoreApi.h>
2530
#include <olp/core/http/NetworkTypes.h>
2631

2732
namespace olp {
2833
namespace http {
34+
35+
/**
36+
* @brief Network request timings.
37+
*/
38+
struct Diagnostics {
39+
using MicroSeconds = std::chrono::duration<uint32_t, std::micro>;
40+
41+
enum Timings {
42+
Queue = 0, // Delay until the request is processed
43+
NameLookup, // Time taken for DNS name lookup
44+
Connect, // Time taken to establish connection
45+
SSL_Handshake, // Time taken to establish a secured connection
46+
Send, // Time taken to send the request
47+
Wait, // Time delay until server starts responding
48+
Receive, // Time taken to receive the response
49+
Total, // Total time taken for reqeust
50+
Count
51+
};
52+
53+
/// Timing values
54+
std::array<MicroSeconds, Count> timings{};
55+
56+
/// Availability flag, specify which timing is available
57+
std::bitset<Count> available_timings{};
58+
};
59+
2960
/**
3061
* @brief A network response abstraction for the HTTP request.
3162
*/
@@ -126,6 +157,22 @@ class CORE_API NetworkResponse final {
126157
*/
127158
NetworkResponse& WithBytesDownloaded(uint64_t bytes_downloaded);
128159

160+
/**
161+
* @brief Gets the optional diagnostics if set.
162+
*
163+
* @return Diagnostic values.
164+
*/
165+
const boost::optional<Diagnostics>& GetDiagnostics() const;
166+
167+
/**
168+
* @brief Sets the request diagnostics.
169+
*
170+
* @param diagnostics Diagnostics values.
171+
*
172+
* @return A reference to *this.
173+
*/
174+
NetworkResponse& WithDiagnostics(Diagnostics diagnostics);
175+
129176
private:
130177
/// The associated request ID.
131178
RequestId request_id_{0};
@@ -134,9 +181,11 @@ class CORE_API NetworkResponse final {
134181
/// The human-readable error message if the associated request failed.
135182
std::string error_;
136183
/// The number of bytes uploaded during the network request.
137-
uint64_t bytes_uploaded_;
184+
uint64_t bytes_uploaded_{0};
138185
/// The number of bytes downloaded during the network request.
139-
uint64_t bytes_downloaded_;
186+
uint64_t bytes_downloaded_{0};
187+
/// Diagnostics
188+
boost::optional<Diagnostics> diagnostics_;
140189
};
141190

142191
} // namespace http

olp-cpp-sdk-core/src/http/NetworkResponse.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2019-2020 HERE Europe B.V.
2+
* Copyright (C) 2019-2025 HERE Europe B.V.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -65,5 +65,14 @@ NetworkResponse& NetworkResponse::WithBytesDownloaded(
6565
return *this;
6666
}
6767

68+
NetworkResponse& NetworkResponse::WithDiagnostics(Diagnostics diagnostics) {
69+
diagnostics_ = diagnostics;
70+
return *this;
71+
}
72+
73+
const boost::optional<Diagnostics>& NetworkResponse::GetDiagnostics() const {
74+
return diagnostics_;
75+
}
76+
6877
} // namespace http
6978
} // namespace olp

olp-cpp-sdk-core/src/http/curl/NetworkCurl.cpp

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,49 @@ void SetupDns(CURL* curl_handle, const std::vector<std::string>& dns_servers) {
348348
#endif
349349
}
350350

351+
Diagnostics GetDiagnostics(CURL* handle) {
352+
Diagnostics diagnostics;
353+
354+
static const std::pair<Diagnostics::Timings, CURLINFO> available_timings[] = {
355+
#if CURL_AT_LEAST_VERSION(8, 6, 0)
356+
{Diagnostics::Queue, CURLINFO_QUEUE_TIME_T},
357+
#endif
358+
{Diagnostics::NameLookup, CURLINFO_NAMELOOKUP_TIME_T},
359+
{Diagnostics::Connect, CURLINFO_CONNECT_TIME_T},
360+
{Diagnostics::SSL_Handshake, CURLINFO_APPCONNECT_TIME_T},
361+
#if CURL_AT_LEAST_VERSION(8, 10, 0)
362+
{Diagnostics::Send, CURLINFO_POSTTRANSFER_TIME_T},
363+
{Diagnostics::Wait, CURLINFO_STARTTRANSFER_TIME_T},
364+
#else
365+
{Diagnostics::Send, CURLINFO_STARTTRANSFER_TIME_T},
366+
#endif
367+
{Diagnostics::Receive, CURLINFO_TOTAL_TIME_T},
368+
};
369+
370+
curl_off_t last_time_point{0};
371+
372+
auto add_timing = [&](Diagnostics::Timings timing,
373+
Diagnostics::MicroSeconds time) {
374+
diagnostics.timings[timing] = time;
375+
diagnostics.available_timings.set(timing);
376+
};
377+
378+
for (const auto& available_timing : available_timings) {
379+
curl_off_t time_point_us = 0;
380+
if (curl_easy_getinfo(handle, available_timing.second, &time_point_us) ==
381+
CURLE_OK &&
382+
time_point_us > 0) {
383+
add_timing(available_timing.first,
384+
Diagnostics::MicroSeconds(time_point_us - last_time_point));
385+
last_time_point = time_point_us;
386+
}
387+
}
388+
389+
add_timing(Diagnostics::Total, Diagnostics::MicroSeconds(last_time_point));
390+
391+
return diagnostics;
392+
}
393+
351394
} // anonymous namespace
352395

353396
NetworkCurl::NetworkCurl(NetworkInitializationSettings settings)
@@ -1004,7 +1047,8 @@ void NetworkCurl::CompleteMessage(CURL* curl_handle, CURLcode result) {
10041047
auto response = NetworkResponse()
10051048
.WithRequestId(request_handle->id)
10061049
.WithBytesDownloaded(download_bytes)
1007-
.WithBytesUploaded(upload_bytes);
1050+
.WithBytesUploaded(upload_bytes)
1051+
.WithDiagnostics(GetDiagnostics(curl_handle));
10081052

10091053
if (request_handle->is_cancelled) {
10101054
response.WithStatus(static_cast<int>(ErrorCode::CANCELLED_ERROR))
@@ -1199,7 +1243,9 @@ void NetworkCurl::Run() {
11991243
.WithStatus(static_cast<int>(ErrorCode::IO_ERROR))
12001244
.WithError("CURL error")
12011245
.WithBytesDownloaded(download_bytes)
1202-
.WithBytesUploaded(upload_bytes);
1246+
.WithBytesUploaded(upload_bytes)
1247+
.WithDiagnostics(GetDiagnostics(curl_handle));
1248+
12031249
callback(response);
12041250
lock.lock();
12051251
}

0 commit comments

Comments
 (0)