Skip to content

Commit

Permalink
Better support for Go HTTP Client calls (#1564)
Browse files Browse the repository at this point in the history
  • Loading branch information
grcevski authored Jan 23, 2025
1 parent c0ed5d3 commit 58527b5
Show file tree
Hide file tree
Showing 38 changed files with 240 additions and 83 deletions.
8 changes: 6 additions & 2 deletions bpf/go_grpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,9 @@ int beyla_uprobe_server_handleStream_return(struct pt_regs *ctx) {
trace->start_monotime_ns = invocation->start_monotime_ns;
trace->status = status;
trace->content_length = 0;
trace->method[0] = 0;
trace->method[0] = '\0';
trace->host[0] = '\0';
trace->scheme[0] = '\0';
trace->go_start_monotime_ns = invocation->start_monotime_ns;
bpf_map_delete_elem(&ongoing_goroutines, &g_key);

Expand Down Expand Up @@ -427,7 +429,9 @@ static __always_inline int grpc_connect_done(struct pt_regs *ctx, void *err) {
trace->go_start_monotime_ns = invocation->start_monotime_ns;
trace->end_monotime_ns = bpf_ktime_get_ns();
trace->content_length = 0;
trace->method[0] = 0;
trace->method[0] = '\0';
trace->host[0] = '\0';
trace->scheme[0] = '\0';

// Read arguments from the original set of registers

Expand Down
42 changes: 35 additions & 7 deletions bpf/go_nethttp.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
typedef struct http_client_data {
u8 method[METHOD_MAX_LEN];
u8 path[PATH_MAX_LEN];
u8 host[HOST_MAX_LEN];
u8 scheme[SCHEME_MAX_LEN];
s64 content_length;

pid_info pid;
Expand Down Expand Up @@ -320,6 +322,8 @@ int beyla_uprobe_ServeHTTPReturns(struct pt_regs *ctx) {
trace->type = EVENT_HTTP_REQUEST;
trace->start_monotime_ns = invocation->start_monotime_ns;
trace->end_monotime_ns = bpf_ktime_get_ns();
trace->host[0] = '\0';
trace->scheme[0] = '\0';

goroutine_metadata *g_metadata = bpf_map_lookup_elem(&ongoing_goroutines, &g_key);
if (g_metadata) {
Expand Down Expand Up @@ -412,16 +416,38 @@ static __always_inline void roundTripStartHelper(struct pt_regs *ctx) {
sizeof(url_ptr),
(void *)(req + go_offset_of(ot, (go_offset){.v = _url_ptr_pos})));

if (!url_ptr || !read_go_str("path",
url_ptr,
go_offset_of(ot, (go_offset){.v = _path_ptr_pos}),
&trace.path,
sizeof(trace.path))) {
bpf_dbg_printk("can't read http Request.URL.Path");
return;
if (url_ptr) {
if (!read_go_str("path",
url_ptr,
go_offset_of(ot, (go_offset){.v = _path_ptr_pos}),
&trace.path,
sizeof(trace.path))) {
bpf_dbg_printk("can't read http Request.URL.Path");
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;
}
}

bpf_dbg_printk("path: %s", trace.path);
bpf_dbg_printk("host: %s", trace.host);
bpf_dbg_printk("scheme: %s", trace.scheme);

// Write event
if (bpf_map_update_elem(&ongoing_http_client_requests, &g_key, &invocation, BPF_ANY)) {
Expand Down Expand Up @@ -488,6 +514,8 @@ int beyla_uprobe_roundTripReturn(struct pt_regs *ctx) {
// Copy the values read on request start
__builtin_memcpy(trace->method, data->method, sizeof(trace->method));
__builtin_memcpy(trace->path, data->path, sizeof(trace->path));
__builtin_memcpy(trace->host, data->host, sizeof(trace->host));
__builtin_memcpy(trace->scheme, data->scheme, sizeof(trace->scheme));
trace->content_length = data->content_length;

// Get request/response struct
Expand Down
2 changes: 2 additions & 0 deletions bpf/go_offsets.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ typedef enum {
// http
_url_ptr_pos,
_path_ptr_pos,
_host_ptr_pos,
_scheme_ptr_pos,
_method_ptr_pos,
_status_code_ptr_pos,
_content_length_ptr_pos,
Expand Down
4 changes: 4 additions & 0 deletions bpf/tracer_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#define KAFKA_MAX_LEN 256
#define REDIS_MAX_LEN 256
#define MAX_TOPIC_NAME_LEN 64
#define HOST_MAX_LEN 100
#define SCHEME_MAX_LEN 10

// Trace of an HTTP call invocation. It is instantiated by the return uprobe and forwarded to the
// user space through the events ringbuffer.
Expand All @@ -37,6 +39,8 @@ typedef struct http_request_trace_t {
u64 end_monotime_ns;
u8 method[METHOD_MAX_LEN];
u8 path[PATH_MAX_LEN];
u8 host[HOST_MAX_LEN];
u8 scheme[SCHEME_MAX_LEN];
u16 status;
connection_info_t conn __attribute__((aligned(8)));
s64 content_length;
Expand Down
4 changes: 3 additions & 1 deletion configs/offsets/tracker_input.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
"Header"
],
"net/url.URL": [
"Path"
"Path",
"Host",
"Scheme"
],
"net/http.Response": [
"StatusCode"
Expand Down
12 changes: 10 additions & 2 deletions pkg/export/otel/traces.go
Original file line number Diff line number Diff line change
Expand Up @@ -602,11 +602,19 @@ func traceAttributes(span *request.Span, optionalAttrs map[attr.Name]struct{}) [
request.ServerPort(span.HostPort),
}
case request.EventTypeHTTPClient:
host := request.HTTPClientHost(span)
scheme := request.HTTPScheme(span)
url := span.Path
if span.HasOriginalHost() {
url = request.URLFull(scheme, host, span.Path)
}

attrs = []attribute.KeyValue{
request.HTTPRequestMethod(span.Method),
request.HTTPResponseStatusCode(span.Status),
request.HTTPUrlFull(span.Path),
request.ServerAddr(request.HostAsServer(span)),
request.HTTPUrlFull(url),
semconv.HTTPScheme(scheme),
request.ServerAddr(host),
request.ServerPort(span.HostPort),
request.HTTPRequestBodySize(int(span.RequestLength())),
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/internal/ebpf/common/bpf_arm64_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pkg/internal/ebpf/common/bpf_arm64_bpfel.o
Git LFS file not shown
4 changes: 3 additions & 1 deletion pkg/internal/ebpf/common/bpf_x86_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pkg/internal/ebpf/common/bpf_x86_bpfel.o
Git LFS file not shown
3 changes: 3 additions & 0 deletions pkg/internal/ebpf/common/httpfltr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ func TestToRequestTrace(t *testing.T) {
End: 789012,
HostPort: 1,
Service: svc.Attrs{},
Statement: "http;",
}
assert.Equal(t, expected, result)
}
Expand Down Expand Up @@ -154,6 +155,7 @@ func TestToRequestTraceNoConnection(t *testing.T) {
Status: 200,
HostPort: 7033,
Service: svc.Attrs{},
Statement: "http;",
}
assert.Equal(t, expected, result)
}
Expand Down Expand Up @@ -191,6 +193,7 @@ func TestToRequestTrace_BadHost(t *testing.T) {
End: 789012,
HostPort: 0,
Service: svc.Attrs{},
Statement: "http;",
}
assert.Equal(t, expected, result)

Expand Down
6 changes: 6 additions & 0 deletions pkg/internal/ebpf/common/httpfltr_transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ import (

// misses serviceID
func httpInfoToSpan(info *HTTPInfo) request.Span {
scheme := "http"
if info.Ssl == 1 {
scheme = "https"
}

return request.Span{
Type: request.EventType(info.Type),
Method: info.Method,
Expand All @@ -38,6 +43,7 @@ func httpInfoToSpan(info *HTTPInfo) request.Span {
UserPID: info.Pid.UserPid,
Namespace: info.Pid.Ns,
},
Statement: scheme + request.SchemeHostSeparator,
}
}

Expand Down
28 changes: 12 additions & 16 deletions pkg/internal/ebpf/common/spanner.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package ebpfcommon

import (
"bytes"
"log/slog"
"strings"
"unsafe"

trace2 "go.opentelemetry.io/otel/trace"
Expand All @@ -15,16 +15,10 @@ var log = slog.With("component", "goexec.spanner")

func HTTPRequestTraceToSpan(trace *HTTPRequestTrace) request.Span {
// From C, assuming 0-ended strings
methodLen := bytes.IndexByte(trace.Method[:], 0)
if methodLen < 0 {
methodLen = len(trace.Method)
}
method := string(trace.Method[:methodLen])
pathLen := bytes.IndexByte(trace.Path[:], 0)
if pathLen < 0 {
pathLen = len(trace.Path)
}
path := string(trace.Path[:pathLen])
method := cstr(trace.Method[:])
path := cstr(trace.Path[:])
scheme := cstr(trace.Scheme[:])
origHost := cstr(trace.Host[:])

peer := ""
hostname := ""
Expand All @@ -36,6 +30,11 @@ func HTTPRequestTraceToSpan(trace *HTTPRequestTrace) request.Span {
hostPort = int(trace.Conn.D_port)
}

schemeHost := ""
if scheme != "" || origHost != "" {
schemeHost = strings.Join([]string{scheme, origHost}, request.SchemeHostSeparator)
}

return request.Span{
Type: request.EventType(trace.Type),
Method: method,
Expand All @@ -58,6 +57,7 @@ func HTTPRequestTraceToSpan(trace *HTTPRequestTrace) request.Span {
UserPID: trace.Pid.UserPid,
Namespace: trace.Pid.Ns,
},
Statement: schemeHost,
}
}

Expand All @@ -68,11 +68,7 @@ func SQLRequestTraceToSpan(trace *SQLRequestTrace) request.Span {
}

// From C, assuming 0-ended strings
sqlLen := bytes.IndexByte(trace.Sql[:], 0)
if sqlLen < 0 {
sqlLen = len(trace.Sql)
}
sql := string(trace.Sql[:sqlLen])
sql := cstr(trace.Sql[:])

method, path := sqlprune.SQLParseOperationAndTable(sql)

Expand Down
6 changes: 4 additions & 2 deletions pkg/internal/ebpf/gotracer/bpf_arm64_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pkg/internal/ebpf/gotracer/bpf_arm64_bpfel.o
Git LFS file not shown
6 changes: 4 additions & 2 deletions pkg/internal/ebpf/gotracer/bpf_debug_arm64_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pkg/internal/ebpf/gotracer/bpf_debug_arm64_bpfel.o
Git LFS file not shown
6 changes: 4 additions & 2 deletions pkg/internal/ebpf/gotracer/bpf_debug_x86_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pkg/internal/ebpf/gotracer/bpf_debug_x86_bpfel.o
Git LFS file not shown
6 changes: 4 additions & 2 deletions pkg/internal/ebpf/gotracer/bpf_tp_arm64_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 58527b5

Please sign in to comment.