@@ -199,28 +199,29 @@ type ServiceInfo struct {
199199
200200// ContainerMetrics contains Docker/Podman container metrics
201201type ContainerMetrics struct {
202- ContainerID string `json:"container_id"`
203- ContainerName string `json:"container_name"`
204- ImageName string `json:"image_name"`
205- ImageTag string `json:"image_tag"`
206- Runtime string `json:"runtime"`
207- Status string `json:"status"`
208- Health string `json:"health"`
209- StartedAt int64 `json:"started_at"`
210- ExitCode * int16 `json:"exit_code"`
211- CPUPercent float64 `json:"cpu_percent"`
212- CPUSystemPercent float64 `json:"cpu_system_percent"`
213- MemoryUsage uint64 `json:"memory_usage"`
214- MemoryLimit uint64 `json:"memory_limit"`
215- MemoryPercent float64 `json:"memory_percent"`
216- NetRxBytes uint64 `json:"net_rx_bytes"`
217- NetTxBytes uint64 `json:"net_tx_bytes"`
218- BlockReadBytes uint64 `json:"block_read_bytes"`
219- BlockWriteBytes uint64 `json:"block_write_bytes"`
220- PIDsCurrent uint32 `json:"pids_current"`
221- PIDsLimit uint32 `json:"pids_limit"`
222- Ports string `json:"ports"`
223- Labels string `json:"labels"`
202+ ContainerID string `json:"container_id"`
203+ ContainerName string `json:"container_name"`
204+ ImageName string `json:"image_name"`
205+ ImageTag string `json:"image_tag"`
206+ Runtime string `json:"runtime"`
207+ Status string `json:"status"`
208+ Health string `json:"health"`
209+ StartedAt int64 `json:"started_at"`
210+ ExitCode * int16 `json:"exit_code"`
211+ CPUPercent float64 `json:"cpu_percent"`
212+ CPUSystemPercent float64 `json:"cpu_system_percent"`
213+ MemoryUsage uint64 `json:"memory_usage"`
214+ MemoryLimit uint64 `json:"memory_limit"`
215+ MemoryPercent float64 `json:"memory_percent"`
216+ NetRxBytes uint64 `json:"net_rx_bytes"`
217+ NetTxBytes uint64 `json:"net_tx_bytes"`
218+ BlockReadBytes uint64 `json:"block_read_bytes"`
219+ BlockWriteBytes uint64 `json:"block_write_bytes"`
220+ PIDsCurrent uint32 `json:"pids_current"`
221+ PIDsLimit uint32 `json:"pids_limit"`
222+ Ports string `json:"ports"`
223+ Labels string `json:"labels"`
224+ RecentLogs []string `json:"recent_logs"` // Container logs (errors/warnings)
224225}
225226
226227// SystemSummary contains aggregated system metrics for the main dashboard
@@ -1189,10 +1190,10 @@ func registerContainerMetrics() error {
11891190}
11901191
11911192func registerLogMetrics () error {
1192- // catops.log - Log entries from services (sent as individual metrics)
1193+ // catops.log - Log entries from containers (sent as individual metrics)
11931194 _ , err := meter .Int64ObservableGauge (
11941195 "catops.log" ,
1195- metric .WithDescription ("Log entries from services " ),
1196+ metric .WithDescription ("Log entries from containers " ),
11961197 metric .WithUnit ("{entries}" ),
11971198 metric .WithInt64Callback (func (ctx context.Context , o metric.Int64Observer ) error {
11981199 cacheMu .RLock ()
@@ -1202,22 +1203,22 @@ func registerLogMetrics() error {
12021203 return nil
12031204 }
12041205
1205- // Send logs from services
1206- for _ , s := range m .Services {
1207- if len (s .RecentLogs ) == 0 {
1206+ // Send logs from containers (simple approach like self-hosted)
1207+ for _ , c := range m .Containers {
1208+ if len (c .RecentLogs ) == 0 {
12081209 continue
12091210 }
12101211
1211- for idx , logLine := range s .RecentLogs {
1212+ for idx , logLine := range c .RecentLogs {
12121213 level := detectLogLevel (logLine )
12131214 attrs := []attribute.KeyValue {
1214- attribute .String ("source" , s . LogSource ),
1215- attribute .String ("source_path" , s . ServiceName ),
1215+ attribute .String ("source" , "docker" ),
1216+ attribute .String ("source_path" , c . ContainerName ),
12161217 attribute .String ("level" , level ),
12171218 attribute .String ("message" , truncateString (logLine , 500 )),
1218- attribute .String ("service" , s . ServiceName ),
1219- attribute .String ("container_id" , s .ContainerID ),
1220- attribute .Int ("pid" , s . PID ),
1219+ attribute .String ("service" , c . ContainerName ),
1220+ attribute .String ("container_id" , c .ContainerID ),
1221+ attribute .Int ("pid" , 0 ),
12211222 }
12221223 o .Observe (int64 (idx ), metric .WithAttributes (attrs ... ))
12231224 }
@@ -2021,8 +2022,12 @@ func collectDockerContainers() ([]ContainerMetrics, error) {
20212022 containers = append (containers , c )
20222023 }
20232024
2024- // Skip docker inspect for each container - too expensive (N syscalls)
2025- // Basic stats from "docker stats" are enough for monitoring
2025+ // Collect logs for containers using global log collector (for deduplication)
2026+ logCollector := GetLogCollector ()
2027+ for i := range containers {
2028+ logs , _ := logCollector .CollectContainerLogs (containers [i ].ContainerID )
2029+ containers [i ].RecentLogs = logs
2030+ }
20262031
20272032 return containers , nil
20282033}
0 commit comments