-
Notifications
You must be signed in to change notification settings - Fork 415
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
[EXPORTER] Log SSL Connection Information #3113
base: main
Are you sure you want to change the base?
Changes from all commits
ae15206
b2e4069
6c07132
7cdf2d4
ab2c39b
3be305e
78f9a0b
d0b8589
5dc28ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ | |
#include "opentelemetry/ext/http/client/curl/http_client_curl.h" | ||
#include "opentelemetry/ext/http/client/curl/http_operation_curl.h" | ||
#include "opentelemetry/ext/http/client/http_client.h" | ||
#include "opentelemetry/nostd/string_view.h" | ||
#include "opentelemetry/sdk/common/global_log_handler.h" | ||
#include "opentelemetry/version.h" | ||
|
||
|
@@ -261,7 +262,8 @@ HttpOperation::HttpOperation(opentelemetry::ext::http::client::Method method, | |
// Default connectivity and response size options | ||
bool is_raw_response, | ||
std::chrono::milliseconds http_conn_timeout, | ||
bool reuse_connection) | ||
bool reuse_connection, | ||
bool is_log_enabled) | ||
: is_aborted_(false), | ||
is_finished_(false), | ||
is_cleaned_(false), | ||
|
@@ -281,6 +283,7 @@ HttpOperation::HttpOperation(opentelemetry::ext::http::client::Method method, | |
request_nwrite_(0), | ||
session_state_(opentelemetry::ext::http::client::SessionState::Created), | ||
compression_(compression), | ||
is_log_enabled_(is_log_enabled), | ||
response_code_(0) | ||
{ | ||
/* get a curl handle */ | ||
|
@@ -569,8 +572,73 @@ CURLcode HttpOperation::SetCurlOffOption(CURLoption option, curl_off_t value) | |
return rc; | ||
} | ||
|
||
int HttpOperation::CurlLoggerCallback(const CURL * /* handle */, | ||
curl_infotype type, | ||
const char *data, | ||
size_t size, | ||
void * /* clientp */) noexcept | ||
{ | ||
nostd::string_view text_to_log{data, size}; | ||
|
||
if (!text_to_log.empty() && text_to_log[size - 1] == '\n') | ||
{ | ||
text_to_log = text_to_log.substr(0, size - 1); | ||
} | ||
|
||
if (type == CURLINFO_TEXT) | ||
{ | ||
static const auto kTlsInfo = nostd::string_view("SSL connection using"); | ||
static const auto kFailureMsg = nostd::string_view("Recv failure:"); | ||
|
||
if (text_to_log.substr(0, kTlsInfo.size()) == kTlsInfo) | ||
{ | ||
OTEL_INTERNAL_LOG_INFO(text_to_log); | ||
} | ||
else if (text_to_log.substr(0, kFailureMsg.size()) == kFailureMsg) | ||
{ | ||
OTEL_INTERNAL_LOG_ERROR(text_to_log); | ||
} | ||
#ifdef CURL_DEBUG | ||
else | ||
{ | ||
OTEL_INTERNAL_LOG_DEBUG(text_to_log); | ||
} | ||
#endif // CURL_DEBUG | ||
} | ||
#ifdef CURL_DEBUG | ||
else if (type == CURLINFO_HEADER_OUT) | ||
{ | ||
static const auto kHeaderSent = nostd::string_view("Send header => "); | ||
|
||
while (!text_to_log.empty() && !std::iscntrl(text_to_log[0])) | ||
{ | ||
const auto pos = text_to_log.find('\n'); | ||
|
||
if (pos != nostd::string_view::npos) | ||
{ | ||
OTEL_INTERNAL_LOG_DEBUG(kHeaderSent << text_to_log.substr(0, pos - 1)); | ||
text_to_log = text_to_log.substr(pos + 1); | ||
} | ||
} | ||
} | ||
else if (type == CURLINFO_HEADER_IN) | ||
{ | ||
static const auto kHeaderRecv = nostd::string_view("Recv header => "); | ||
OTEL_INTERNAL_LOG_DEBUG(kHeaderRecv << text_to_log); | ||
} | ||
#endif // CURL_DEBUG | ||
|
||
return 0; | ||
} | ||
|
||
CURLcode HttpOperation::Setup() | ||
{ | ||
#ifdef ENABLE_CURL_LOGGING | ||
static constexpr auto kEnableCurlLogging = true; | ||
#else | ||
static constexpr auto kEnableCurlLogging = false; | ||
#endif // ENABLE_CURL_LOGGING | ||
|
||
if (!curl_resource_.easy_handle) | ||
{ | ||
return CURLE_FAILED_INIT; | ||
|
@@ -581,11 +649,28 @@ CURLcode HttpOperation::Setup() | |
curl_error_message_[0] = '\0'; | ||
curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_ERRORBUFFER, curl_error_message_); | ||
|
||
// Support for custom debug function callback was added in version 7.9.6 so we guard against | ||
// exposing the default CURL output by keeping verbosity always disabled in lower versions. | ||
#if LIBCURL_VERSION_NUM < CURL_VERSION_BITS(7, 9, 6) | ||
rc = SetCurlLongOption(CURLOPT_VERBOSE, 0L); | ||
if (rc != CURLE_OK) | ||
{ | ||
return rc; | ||
} | ||
#else | ||
rc = SetCurlLongOption(CURLOPT_VERBOSE, static_cast<long>(is_log_enabled_ || kEnableCurlLogging)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two concerns here:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regarding the explicit cast, it looked fairly safe given that the CURL API seems to only care about the value being 0 (disabled) or otherwise. Will update to a good ol' if statement, as requested. As for the logic, my impression was that we wanted to have the runtime drive this behavior regardless of what is set at compile-time, but if omitting If, what is ultimately needed is that the compile-time flag dictate the runtime behavior, then I guess it would need to be AND'ed, instead. Let me know what is the preferred approach with respect to the above and I will push all the required changes at the same time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regarding the OR (
Assume an application has a trace exporter and a metric exporter, both using OTLP HTTP to different endpoints. By setting For this reason, I think the AND logic is better. For people who wants to trace everything, it forces the application to use something like:
so in effect, the logic that was present in http_operation_curl.cc is moved to the application space, where the application (not opentelemetry-cpp) decides if/how it wants tracing to be done. Yes, it is a code change for the application, to benefit from the feature. However, this also allows to trace a metric exporter independently of a trace exporter, which I think is much more convenient to debug things, compared to the OR logic, especially when exporters points to different endpoints. And when debugging is no longer needed ("or read from an application specific configuration"), tracing can be turned off, without having to recompile. Please change the logic to AND then. |
||
if (rc != CURLE_OK) | ||
{ | ||
return rc; | ||
} | ||
|
||
rc = SetCurlPtrOption(CURLOPT_DEBUGFUNCTION, | ||
reinterpret_cast<void *>(&HttpOperation::CurlLoggerCallback)); | ||
if (rc != CURLE_OK) | ||
{ | ||
return rc; | ||
} | ||
#endif | ||
|
||
// Specify target URL | ||
rc = SetCurlStrOption(CURLOPT_URL, url_.c_str()); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please clarify (with a comment) the intent of CURL_DEBUG, which is separate from ENABLE_CURL_LOGGING.
As I understand it, ENABLE_CURL_LOGGING is exposed in CMake, to add the new logging feature.
On top of that, CURL_DEBUG seem to be a private developer flag (not exposed in cmake), for a developper to debug the new logging feature itself, if needed.
So, ENABLE_CURL_LOGGING may be used optionally in production, but CURL_DEBUG should not be used in production.
Is this accurate ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is correct,
CURL_DEBUG
is a guard that comes in handy when debugging something, where the full verbosity would be required. However, making it controllable by the user is probably not desirable as it could lead to unintentionally logging too much / sensitive information, such as request body, auth tokens, other sensitive in/out headers, etc.That said, though, if this is deemed necessary by future requirements, exposing additional logging should be as simple as "punching" a few more holes in the callback function, by simply adding the respective
if
/else if
statements outside this guarded block.So, in a way, the second use of
CURL_DEBUG
is to force the developer to have to explicitly opt-in for exposing more logging info from CURL, which hopefully also makes it easy to see what information the callback function is letting out into the wild.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the clarifications.
Do not change any code then, just add a comment that CURL_DEBUG is for maintainers, and should not be used in production (information leak).