|
| 1 | +// Unless explicitly stated otherwise all files in this repository are licensed |
| 2 | +// under the Apache License Version 2.0. |
| 3 | +// This product includes software developed at Datadog (https://www.datadoghq.com/). |
| 4 | +// Copyright 2016-present Datadog, Inc. |
| 5 | + |
| 6 | +//go:build linux_bpf |
| 7 | + |
| 8 | +package actuator |
| 9 | + |
| 10 | +import ( |
| 11 | + "slices" |
| 12 | + |
| 13 | + "github.com/DataDog/datadog-agent/pkg/dyninst/ir" |
| 14 | +) |
| 15 | + |
| 16 | +// DebugInfo contains a snapshot of the actuator's internal state for |
| 17 | +// debugging purposes, exposed via the flare mechanism. |
| 18 | +type DebugInfo struct { |
| 19 | + Processes []ProcessDebugInfo `json:"processes"` |
| 20 | + Programs []ProgramDebugInfo `json:"programs"` |
| 21 | + DiscoveredTypes map[string][]string `json:"discovered_types"` |
| 22 | + CurrentlyLoading *ir.ProgramID `json:"currently_loading"` |
| 23 | + QueuedLoading []ir.ProgramID `json:"queued_loading"` |
| 24 | + Counters CountersDebugInfo `json:"counters"` |
| 25 | + CircuitBreaker CircuitBreakerInfo `json:"circuit_breaker"` |
| 26 | +} |
| 27 | + |
| 28 | +// ProcessDebugInfo contains debug information about a single process in the |
| 29 | +// actuator's state machine. |
| 30 | +type ProcessDebugInfo struct { |
| 31 | + PID int32 `json:"pid"` |
| 32 | + State string `json:"state"` |
| 33 | + Service string `json:"service"` |
| 34 | + CurrentProgram ir.ProgramID `json:"current_program"` |
| 35 | + ProbeCount int `json:"probe_count"` |
| 36 | +} |
| 37 | + |
| 38 | +// ProgramDebugInfo contains debug information about a single program in the |
| 39 | +// actuator's state machine. |
| 40 | +type ProgramDebugInfo struct { |
| 41 | + ProgramID ir.ProgramID `json:"program_id"` |
| 42 | + State string `json:"state"` |
| 43 | + ProcessPID int32 `json:"process_pid"` |
| 44 | + ProbeCount int `json:"probe_count"` |
| 45 | + NeedsRecompilation bool `json:"needs_recompilation"` |
| 46 | +} |
| 47 | + |
| 48 | +// CountersDebugInfo contains cumulative counters from the actuator. |
| 49 | +type CountersDebugInfo struct { |
| 50 | + Loaded uint64 `json:"loaded"` |
| 51 | + LoadFailed uint64 `json:"load_failed"` |
| 52 | + Attached uint64 `json:"attached"` |
| 53 | + AttachFailed uint64 `json:"attach_failed"` |
| 54 | + Detached uint64 `json:"detached"` |
| 55 | + Unloaded uint64 `json:"unloaded"` |
| 56 | + TypeRecompilationsTriggered uint64 `json:"type_recompilations_triggered"` |
| 57 | +} |
| 58 | + |
| 59 | +// CircuitBreakerInfo contains the circuit breaker configuration. |
| 60 | +type CircuitBreakerInfo struct { |
| 61 | + Interval string `json:"interval"` |
| 62 | + PerProbeCPULimit float64 `json:"per_probe_cpu_limit"` |
| 63 | + AllProbesCPULimit float64 `json:"all_probes_cpu_limit"` |
| 64 | + InterruptOverhead string `json:"interrupt_overhead"` |
| 65 | +} |
| 66 | + |
| 67 | +// debugInfo returns a snapshot of the state machine for debugging. |
| 68 | +func (s *state) debugInfo() DebugInfo { |
| 69 | + processes := make([]ProcessDebugInfo, 0, len(s.processes)) |
| 70 | + for _, p := range s.processes { |
| 71 | + processes = append(processes, ProcessDebugInfo{ |
| 72 | + PID: p.processID.PID, |
| 73 | + State: p.state.String(), |
| 74 | + Service: p.service, |
| 75 | + CurrentProgram: p.currentProgram, |
| 76 | + ProbeCount: len(p.probes), |
| 77 | + }) |
| 78 | + } |
| 79 | + |
| 80 | + programs := make([]ProgramDebugInfo, 0, len(s.programs)) |
| 81 | + for _, p := range s.programs { |
| 82 | + programs = append(programs, ProgramDebugInfo{ |
| 83 | + ProgramID: p.id, |
| 84 | + State: p.state.String(), |
| 85 | + ProcessPID: p.processID.PID, |
| 86 | + ProbeCount: len(p.config), |
| 87 | + NeedsRecompilation: p.needsRecompilation, |
| 88 | + }) |
| 89 | + } |
| 90 | + |
| 91 | + discoveredTypes := make(map[string][]string, len(s.discoveredTypes)) |
| 92 | + for svc, types := range s.discoveredTypes { |
| 93 | + discoveredTypes[svc] = slices.Clone(types) |
| 94 | + } |
| 95 | + |
| 96 | + var currentlyLoading *ir.ProgramID |
| 97 | + if s.currentlyLoading != nil { |
| 98 | + id := s.currentlyLoading.id |
| 99 | + currentlyLoading = &id |
| 100 | + } |
| 101 | + |
| 102 | + queuedLoading := make([]ir.ProgramID, 0, s.queuedLoading.len()) |
| 103 | + for _, item := range s.queuedLoading.m { |
| 104 | + queuedLoading = append(queuedLoading, item.value.id) |
| 105 | + } |
| 106 | + |
| 107 | + return DebugInfo{ |
| 108 | + Processes: processes, |
| 109 | + Programs: programs, |
| 110 | + DiscoveredTypes: discoveredTypes, |
| 111 | + CurrentlyLoading: currentlyLoading, |
| 112 | + QueuedLoading: queuedLoading, |
| 113 | + Counters: CountersDebugInfo{ |
| 114 | + Loaded: s.counters.loaded, |
| 115 | + LoadFailed: s.counters.loadFailed, |
| 116 | + Attached: s.counters.attached, |
| 117 | + AttachFailed: s.counters.attachFailed, |
| 118 | + Detached: s.counters.detached, |
| 119 | + Unloaded: s.counters.unloaded, |
| 120 | + TypeRecompilationsTriggered: s.counters.typeRecompilationsTriggered, |
| 121 | + }, |
| 122 | + CircuitBreaker: CircuitBreakerInfo{ |
| 123 | + Interval: s.breakerCfg.Interval.String(), |
| 124 | + PerProbeCPULimit: s.breakerCfg.PerProbeCPULimit, |
| 125 | + AllProbesCPULimit: s.breakerCfg.AllProbesCPULimit, |
| 126 | + InterruptOverhead: s.breakerCfg.InterruptOverhead.String(), |
| 127 | + }, |
| 128 | + } |
| 129 | +} |
0 commit comments