@@ -27,24 +27,40 @@ async fn main() -> anyhow::Result<()> {
2727 ) ) )
2828 . context ( "load eBPF object" ) ?;
2929
30- attach ( & mut ebpf, "exec" , "syscalls" , "sys_enter_execve" ) ?;
31- attach ( & mut ebpf, "tls_write" , "syscalls" , "sys_enter_write" ) ?;
32- attach ( & mut ebpf, "tls_sendto" , "syscalls" , "sys_enter_sendto" ) ?;
33- attach ( & mut ebpf, "connect" , "syscalls" , "sys_enter_connect" ) ?;
34- attach ( & mut ebpf, "dns_query" , "syscalls" , "sys_enter_sendto" ) ?;
35- attach ( & mut ebpf, "dns_sendmsg" , "syscalls" , "sys_enter_sendmsg" ) ?;
36- attach ( & mut ebpf, "dns_sendmmsg" , "syscalls" , "sys_enter_sendmmsg" ) ?;
3730 // File-write capture is opt-in: openat is a firehose on a busy node (e.g. containerd
3831 // unpacking images), and the agent's own writes need downstream identity filtering.
3932 let files = std:: env:: var_os ( "A3S_OBSERVER_FILES" ) . is_some ( ) ;
33+ let mut probes = vec ! [
34+ ( "exec" , "sys_enter_execve" ) ,
35+ ( "tls_write" , "sys_enter_write" ) ,
36+ ( "tls_sendto" , "sys_enter_sendto" ) ,
37+ ( "connect" , "sys_enter_connect" ) ,
38+ ( "dns_query" , "sys_enter_sendto" ) ,
39+ ( "dns_sendmsg" , "sys_enter_sendmsg" ) ,
40+ ( "dns_sendmmsg" , "sys_enter_sendmmsg" ) ,
41+ ( "read_enter" , "sys_enter_read" ) ,
42+ ( "recv_enter" , "sys_enter_recvfrom" ) ,
43+ ( "read_exit" , "sys_exit_read" ) ,
44+ ( "recv_exit" , "sys_exit_recvfrom" ) ,
45+ ( "sock_close" , "sys_enter_close" ) ,
46+ ] ;
4047 if files {
41- attach ( & mut ebpf, "file_open" , "syscalls" , "sys_enter_openat" ) ?;
48+ probes. push ( ( "file_open" , "sys_enter_openat" ) ) ;
49+ }
50+ // Per-probe attach is non-fatal: kernels vary, and one missing tracepoint shouldn't take
51+ // down the whole collector — degrade to whatever attaches, fail only if nothing does.
52+ let mut attached = 0usize ;
53+ for ( prog, tp) in & probes {
54+ match attach ( & mut ebpf, prog, "syscalls" , tp) {
55+ Ok ( ( ) ) => attached += 1 ,
56+ Err ( e) => {
57+ tracing:: warn!( probe = prog, error = %e, "probe failed to attach — continuing" )
58+ }
59+ }
60+ }
61+ if attached == 0 {
62+ anyhow:: bail!( "no eBPF probes could be attached" ) ;
4263 }
43- attach ( & mut ebpf, "read_enter" , "syscalls" , "sys_enter_read" ) ?;
44- attach ( & mut ebpf, "recv_enter" , "syscalls" , "sys_enter_recvfrom" ) ?;
45- attach ( & mut ebpf, "read_exit" , "syscalls" , "sys_exit_read" ) ?;
46- attach ( & mut ebpf, "recv_exit" , "syscalls" , "sys_exit_recvfrom" ) ?;
47- attach ( & mut ebpf, "sock_close" , "syscalls" , "sys_enter_close" ) ?;
4864
4965 // A3S_OBSERVER_JSON=1 → NDJSON (pipe to vector/Loki/jq); otherwise human-readable log.
5066 let exporter: Box < dyn Exporter > = if std:: env:: var_os ( "A3S_OBSERVER_JSON" ) . is_some ( ) {
@@ -82,9 +98,11 @@ async fn main() -> anyhow::Result<()> {
8298 ) ?;
8399
84100 tracing:: info!(
101+ attached,
102+ total = probes. len( ) ,
85103 files,
86- "a3s-observer-collector: exec + TLS-SNI + connect + dns + LLM-metrics probes attached \
87- (file-write capture: set A3S_OBSERVER_FILES=1); streaming (Ctrl-C to stop)"
104+ "a3s-observer-collector: probes attached (file-write capture: set A3S_OBSERVER_FILES=1); \
105+ streaming (Ctrl-C to stop)"
88106 ) ;
89107
90108 let mut sigint = tokio:: signal:: unix:: signal ( tokio:: signal:: unix:: SignalKind :: interrupt ( ) ) ?;
0 commit comments