Skip to content
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

Better support for Go HTTP Client calls #1564

Merged
merged 6 commits into from
Jan 23, 2025

Conversation

grcevski
Copy link
Contributor

This PR enriches the information we generated for Go HTTP client calls. We use the original host name where possible and we extract the scheme too.

I also fixed a few tests which could be flaky sometimes. The traces test could sometimes miss inqueue and processing because we couldn't capture that information and the Go client program calls out to grafana.com and if we can't reach it we'd never generate any requests. I added a timeout.

@grcevski grcevski requested a review from a team as a code owner January 22, 2025 22:07
Copy link

codecov bot commented Jan 22, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 71.18%. Comparing base (285162b) to head (380c786).
Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1564      +/-   ##
==========================================
+ Coverage   71.15%   71.18%   +0.03%     
==========================================
  Files         197      197              
  Lines       19671    19730      +59     
==========================================
+ Hits        13996    14044      +48     
- Misses       4995     5004       +9     
- Partials      680      682       +2     
Flag Coverage Δ
integration-test 53.39% <98.33%> (+0.07%) ⬆️
k8s-integration-test 52.73% <91.66%> (-0.62%) ⬇️
oats-test 34.35% <21.66%> (+0.10%) ⬆️
unittests 47.31% <51.66%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@rafaelroquetto rafaelroquetto left a comment

Choose a reason for hiding this comment

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

LGTM

bpf/go_nethttp.h Outdated
Comment on lines 428 to 444
if (!url_ptr || !read_go_str("host",
url_ptr,
go_offset_of(ot, (go_offset){.v = _host_ptr_pos}),
&trace.host,
sizeof(trace.host))) {
bpf_dbg_printk("can't read http Request.URL.Host");
return;
}

if (!url_ptr || !read_go_str("scheme",
url_ptr,
go_offset_of(ot, (go_offset){.v = _scheme_ptr_pos}),
&trace.scheme,
sizeof(trace.scheme))) {
bpf_dbg_printk("can't read http Request.URL.Scheme");
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (!url_ptr || !read_go_str("host",
url_ptr,
go_offset_of(ot, (go_offset){.v = _host_ptr_pos}),
&trace.host,
sizeof(trace.host))) {
bpf_dbg_printk("can't read http Request.URL.Host");
return;
}
if (!url_ptr || !read_go_str("scheme",
url_ptr,
go_offset_of(ot, (go_offset){.v = _scheme_ptr_pos}),
&trace.scheme,
sizeof(trace.scheme))) {
bpf_dbg_printk("can't read http Request.URL.Scheme");
return;
}
if (!url_ptr) {
return;
}
if (!read_go_str("host",
url_ptr,
go_offset_of(ot, (go_offset){.v = _host_ptr_pos}),
&trace.host,
sizeof(trace.host))) {
bpf_dbg_printk("can't read http Request.URL.Host");
return;
}
if (!read_go_str("scheme",
url_ptr,
go_offset_of(ot, (go_offset){.v = _scheme_ptr_pos}),
&trace.scheme,
sizeof(trace.scheme))) {
bpf_dbg_printk("can't read http Request.URL.Scheme");
return;
}

rationale: it go me a bit confused if we were checking for a side-effect on url_ptr after the first call

alternatively, check if base_ptr is not null in read_go_str & co.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good idea, I'll refactor it.

bpf/go_nethttp.h Outdated
Comment on lines 325 to 326
trace->host[0] = 0;
trace->scheme[0] = 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
trace->host[0] = 0;
trace->scheme[0] = 0;
trace->method = '\0';
trace->path = '\0';
trace->host[0] = '\0';
trace->scheme[0] = '\0';
  • ensure method and path are always null-terminated as well (it matters in spanner.go I guess)
  • just being pedantic here, so feel free to ignore - \0 helps the reader visualise we are dealing with a string and not with some sort of array of int.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok, sure, I'll replace those.

Copy link
Contributor

Choose a reason for hiding this comment

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

@rafaelroquetto can you explain a bit more that? how is 0 equal to '\0'? shouldn't be just empty string?

Copy link
Contributor

Choose a reason for hiding this comment

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

@marctc of course! - all of those above are C strings. A C string is defined to be an array of char that ends with the null terminator, i.e. the number 0.

So the string literal

const char rabbit_str[] = "Rabbit";

is equivalent to

const char rabbit_[7] = { 'R', 'a', 'b', 'b', 'i', 't', '\0' };
// or
const char rabbit_[7] = { 'R', 'a', 'b', 'b', 'i', 't', 0 };

The null terminator tells string manipulation functions where the end of the string is, for instance, to calculate the length of a C string, we can do

size_t strlen(const char* str)
{
   size_t i = 0;
   while (*str++ != '\0') ++i;
   return i;
}

In C, the char literal '\0' has the value of 0. They are the same, and have the same size (usually sizeof(int)). In C++ they are not the same - 0 is an int literal whose size is sizeof(int), whereas '\0' is a char literal whose size is sizeof(char) - so sizeof(0) != sizeof('\0') in C++.

What @grcevski is doing here is simply setting the first element of those char arrays to the null-terminator \0, which represents an empty C-string:

char something[16]; // uninitialised -> garbage
something[0] = '\0'; // something is now { '\0', ... garbage ... };
printf("str: '%s', size = %lu\n", something, strlen(something)); // prints "str: '' size = 0"

In other words, it suffices to set the first char as 0 instead of zeroing the entire buffer. My point was then to suggest using the char literal '\0' rather than the int literal 0 to explicitly indicate to the reader these buffers are actually carrying C strings.

Copy link
Contributor

Choose a reason for hiding this comment

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

In other words, it suffices to set the first char as 0 instead of zeroing the entire buffer. My point was then to suggest using the char literal '\0' rather than the int literal 0 to explicitly indicate to the reader these buffers are actually carrying C strings.

gotcha, thanks for the explanation!

Comment on lines +18 to +21
method := cstr(trace.Method[:])
path := cstr(trace.Path[:])
scheme := cstr(trace.Scheme[:])
origHost := cstr(trace.Host[:])
Copy link
Contributor

Choose a reason for hiding this comment

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

nice

Copy link
Contributor

@rafaelroquetto rafaelroquetto left a comment

Choose a reason for hiding this comment

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

Thanks for the changes

@grcevski grcevski merged commit 58527b5 into grafana:main Jan 23, 2025
15 checks passed
@grcevski grcevski deleted the go_http_client_calls branch January 23, 2025 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants