mirror of
https://github.com/unpoller/unpoller.git
synced 2026-04-05 00:44:09 -04:00
- Add job=unpoller to every Loki stream (alarm, anomaly, event, ids,
system_log, protect_log, protect_thumbnail) for standard Grafana/Loki
source filtering with {job="unpoller"}
- Add event_type and inner_alert_action labels to IDS streams using
EventType and InnerAlertAction fields
- Add event_type and inner_alert_action labels to Alarm streams using
Key and InnerAlertAction fields
- Skip severity/category on Anomaly: the unifi.Anomaly struct has no
such fields
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
72 lines
2.2 KiB
Go
72 lines
2.2 KiB
Go
package lokiunifi
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strconv"
|
|
|
|
"github.com/unpoller/unifi/v5"
|
|
)
|
|
|
|
const typeProtectLog = "ProtectLog"
|
|
const typeProtectThumbnail = "ProtectThumbnail"
|
|
|
|
// ProtectLogEvent stores a structured UniFi Protect Log Entry for batch sending to Loki.
|
|
// Logs the raw JSON for parsing with Loki's `| json` pipeline.
|
|
// If the event has a thumbnail, it's sent as a separate log line.
|
|
func (r *Report) ProtectLogEvent(event *unifi.ProtectLogEntry, logs *Logs) {
|
|
if event.Datetime().Before(r.Oldest) {
|
|
return
|
|
}
|
|
|
|
r.Counts[typeProtectLog]++ // increase counter and append new log line.
|
|
|
|
// Store thumbnail separately before marshaling (it's excluded from JSON by default now)
|
|
thumbnailBase64 := event.ThumbnailBase64
|
|
|
|
// Marshal event to JSON for the log line (without thumbnail to keep it small)
|
|
event.ThumbnailBase64 = "" // Temporarily clear for marshaling
|
|
msg, err := json.Marshal(event)
|
|
if err != nil {
|
|
msg = []byte(event.Msg())
|
|
}
|
|
event.ThumbnailBase64 = thumbnailBase64 // Restore
|
|
|
|
// Add event log line
|
|
logs.Streams = append(logs.Streams, LogStream{
|
|
Entries: [][]string{{strconv.FormatInt(event.Datetime().UnixNano(), 10), string(msg)}},
|
|
Labels: CleanLabels(MergeLabels(map[string]string{
|
|
"application": "unifi_protect_log",
|
|
"job": "unpoller",
|
|
"source": event.SourceName,
|
|
"event_type": event.GetEventType(),
|
|
"category": event.GetCategory(),
|
|
"severity": event.GetSeverity(),
|
|
"camera": event.Camera,
|
|
}, r.ExtraLabels)),
|
|
})
|
|
|
|
// Add thumbnail as separate log line if present
|
|
if thumbnailBase64 != "" {
|
|
r.Counts[typeProtectThumbnail]++
|
|
|
|
thumbnailJSON, _ := json.Marshal(map[string]string{
|
|
"event_id": event.ID,
|
|
"thumbnail_base64": thumbnailBase64,
|
|
"mime_type": "image/jpeg",
|
|
})
|
|
|
|
// Use timestamp + 1 nanosecond to ensure ordering (thumbnail after event)
|
|
logs.Streams = append(logs.Streams, LogStream{
|
|
Entries: [][]string{{strconv.FormatInt(event.Datetime().UnixNano()+1, 10), string(thumbnailJSON)}},
|
|
Labels: CleanLabels(MergeLabels(map[string]string{
|
|
"application": "unifi_protect_thumbnail",
|
|
"job": "unpoller",
|
|
"source": event.SourceName,
|
|
"event_id": event.ID,
|
|
"camera": event.Camera,
|
|
}, r.ExtraLabels)),
|
|
})
|
|
}
|
|
}
|
|
|