Skip to content

Commit d0e13f8

Browse files
committed
chore: fix duplicate metrics with duration bs
1 parent 925ed2f commit d0e13f8

File tree

3 files changed

+29
-10
lines changed

3 files changed

+29
-10
lines changed

internal/crowdsec/requester.go

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,16 @@ func QueryAlerts(limit int64, retry int) (models.Alerts, error) {
8282
for _, d := range ds {
8383
if dm, ok := d.(map[string]interface{}); ok {
8484
var dec models.Decision
85+
dec.ID = getInt(dm, "id")
8586
dec.UUID = getString(dm, "uuid")
8687
dec.Scenario = getString(dm, "scenario")
8788
dec.IPAddress = getString(dm, "value")
8889
dec.Type = getString(dm, "type")
89-
dec.Duration = calculateOriginalDuration(dec.CreatedAt, dec.Until)
9090
dec.Scope = getString(dm, "scope")
91-
dec.Until = getString(dm, "until")
92-
dec.CreatedAt = getString(dm, "created_at")
91+
92+
// Calculate original duration because CrowdSec API provides duration as remainder?
93+
remainingDuration := getString(dm, "duration")
94+
dec.Duration = calculateOriginalDuration(a.CreatedAt, remainingDuration)
9395

9496
dec.Country = a.Country
9597
dec.AsName = a.AsName
@@ -123,22 +125,36 @@ func getFloat(m map[string]interface{}, key string) float64 {
123125
return 0
124126
}
125127

126-
// calculateOriginalDuration calculates the original ban duration from created_at and until timestamps
127-
func calculateOriginalDuration(createdAt, until string) string {
128-
if createdAt == "" || until == "" {
128+
func getInt(m map[string]interface{}, key string) int {
129+
if v, ok := m[key].(float64); ok {
130+
return int(v)
131+
}
132+
if v, ok := m[key].(int); ok {
133+
return v
134+
}
135+
return 0
136+
}
137+
138+
func calculateOriginalDuration(alertCreatedAt, remainingDuration string) string {
139+
if alertCreatedAt == "" || remainingDuration == "" {
129140
return ""
130141
}
131142

132-
createdTime, err := time.Parse(time.RFC3339, createdAt)
143+
remaining, err := time.ParseDuration(remainingDuration)
133144
if err != nil {
134145
return ""
135146
}
136147

137-
untilTime, err := time.Parse(time.RFC3339, until)
148+
alertTime, err := time.Parse(time.RFC3339, alertCreatedAt)
138149
if err != nil {
139150
return ""
140151
}
141152

142-
duration := untilTime.Sub(createdTime)
143-
return duration.String()
153+
now := time.Now()
154+
elapsed := now.Sub(alertTime)
155+
originalDuration := remaining + elapsed
156+
157+
// Round to nearest minute to avoid duplicate metrics
158+
// Could be flaky, but better than nothing
159+
return originalDuration.Round(time.Minute).String()
144160
}

internal/exporter/exporter.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func New(cfg *config.Config) (*Exporter, error) {
3535
"CrowdSec decisions with detailed metadata",
3636
[]string{
3737
"instance",
38+
"id",
3839
"country",
3940
"asname",
4041
"asnumber",
@@ -91,6 +92,7 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
9192
prometheus.GaugeValue,
9293
1,
9394
e.config.Exporter.InstanceName,
95+
fmt.Sprintf("%d", decision.ID),
9496
decision.Country,
9597
decision.AsName,
9698
decision.AsNumber,

internal/models/decision.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package models
22

33
type Decision struct {
4+
ID int `json:"id"`
45
UUID string `json:"uuid"`
56
Scenario string `json:"scenario"`
67
IPAddress string `json:"ip"`

0 commit comments

Comments
 (0)