Skip to content

Commit

Permalink
fixing bug from issue #5, adding new metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
wymangr committed Nov 16, 2023
1 parent 95c6036 commit 5def84a
Show file tree
Hide file tree
Showing 5 changed files with 726 additions and 125 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# blueiris_exporter
Prometheus exporter for Blue Iris.
Confirmed working on Blue Iris version's 5.5.0.12 and 5.6.2.8
Confirmed working on Blue Iris version's 5.5.0.12 to 5.7.9.12

If you receive a `Unable to parse log line` error, please send me the details and I will work on adding support for it. Blue Iris has changed it's log format for AI a few times and I'm working on adding support for all of it. Also, if you have any ideas for different metrics, let me know!
If you increment `parse_errors` metrics, please send me the details and I will work on adding support for it. Blue Iris has changed it's log format for AI a few times and I'm working on adding support for all of it. Also, if you have any ideas for different metrics, let me know!

## Todo
Tests

## Flags

Expand Down Expand Up @@ -137,6 +140,8 @@ ai_restarted | Number of times Blue Iris restarted the AI in the current logfile
ai_timeout | Number of AI timeouts in the current logfile
ai_servererror | Count of AI server not responding errors in the current logfile
ai_notresponding | Count of AI not responding errors in the current logfile
ai_starting | Count of AI is being started log lines
ai_started | Count of AI has been started log lines
logerror | Count of unique errors in the current logfile
logerror_total | Count of total errors in the logs
camera_status | Status of each camera. 0=up, 1=down
Expand All @@ -147,7 +152,10 @@ logwarning_total | Count all warnings in the current logfile
folder_disk_free | Free space of the disk the folder is using in bytes
folder_used | Size percentage of the limit a folder is using
hours_used | Hour percentage of the limit a folder is using
parse_errors | Lines in the Blue Iris log that this exporter was unable to parse. Open an issue to add support
parse_errors_total | Total number of lines in the Blue Iris log that this exporter was unable to parse


## Grafana Dashboard
https://grafana.com/grafana/dashboards/17432-blueiris/
![Grafana Dashboard](images/grafana-dashboard.png)
63 changes: 56 additions & 7 deletions blueiris/blueirisMetrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,15 @@ var (
notrespondingcount float64
errorMetricsTotal float64
warningMetricsTotal float64
parseErrorsTotal float64
restartCount float64
aiRestartingCount float64
aiRestartedCount float64
triggerCount map[string]float64
pushCount map[string]float64
errorMetrics map[string]float64
warningMetrics map[string]float64
parseErrors map[string]float64
)

func BlueIris(ch chan<- prometheus.Metric, m common.MetricInfo, SecMet []common.MetricInfo, logpath string) {
Expand All @@ -53,10 +57,14 @@ func BlueIris(ch chan<- prometheus.Metric, m common.MetricInfo, SecMet []common.
pushCount = make(map[string]float64)
errorMetricsTotal = 0
warningMetricsTotal = 0
parseErrorsTotal = 0
restartCount = 0
aiRestartingCount = 0
aiRestartedCount = 0
timeoutcount = 0
servererrorcount = 0
notrespondingcount = 0
parseErrors = make(map[string]float64)

dir := logpath
files, err := ioutil.ReadDir(dir)
Expand Down Expand Up @@ -154,6 +162,10 @@ func BlueIris(ch chan<- prometheus.Metric, m common.MetricInfo, SecMet []common.
}
}
}
case "ai_starting":
ch <- prometheus.MustNewConstMetric(sm.Desc, sm.Type, aiRestartingCount)
case "ai_started":
ch <- prometheus.MustNewConstMetric(sm.Desc, sm.Type, aiRestartedCount)
case "ai_restarted":
ch <- prometheus.MustNewConstMetric(sm.Desc, sm.Type, restartCount)
case "ai_timeout":
Expand Down Expand Up @@ -188,6 +200,16 @@ func BlueIris(ch chan<- prometheus.Metric, m common.MetricInfo, SecMet []common.
ch <- prometheus.MustNewConstMetric(sm.Desc, sm.Type, v, camera, status, detail)
}

case "parse_errors":
if len(parseErrors) == 0 {
ch <- prometheus.MustNewConstMetric(sm.Desc, sm.Type, 0, "")
} else {
for parse_line, va := range parseErrors {
ch <- prometheus.MustNewConstMetric(sm.Desc, sm.Type, va, parse_line)
}
}
case "parse_errors_total":
ch <- prometheus.MustNewConstMetric(sm.Desc, sm.Type, parseErrorsTotal)
case "logerror":
if len(errorMetrics) == 0 {
ch <- prometheus.MustNewConstMetric(sm.Desc, sm.Type, 0, "")
Expand Down Expand Up @@ -280,6 +302,12 @@ func findObject(line string) (match []string, r *regexp.Regexp, matchType string
} else if strings.Contains(line, "AI has been restarted") {
restartCount++

} else if strings.Contains(line, "AI: is being started") {
aiRestartingCount++

} else if strings.Contains(line, "AI: has been started") {
aiRestartedCount++

} else if strings.Contains(line, "DeepStack: Server error") {
servererrorcount++

Expand All @@ -290,7 +318,8 @@ func findObject(line string) (match []string, r *regexp.Regexp, matchType string
r := regexp.MustCompile(`(?P<camera>[^\s\\]*)(\s*(?P<motion>EXTERNAL|MOTION|DIO))`)
match := r.FindStringSubmatch(line)
if len(match) == 0 {
common.BIlogger(fmt.Sprintf("Unable to parse log line: \n%v", line), "console")
parseErrors = appendCounterMap(parseErrors, line)
parseErrorsTotal++
} else {
cameraMatch := r.SubexpIndex("camera")
camera := match[cameraMatch]
Expand All @@ -304,7 +333,8 @@ func findObject(line string) (match []string, r *regexp.Regexp, matchType string
r := regexp.MustCompile(`(?P<camera>[^\s\\]*)(\s*Push:\s)(?P<status>.+)(\sto\s)(?P<detail>.+)`)
match := r.FindStringSubmatch(line)
if len(match) == 0 {
common.BIlogger(fmt.Sprintf("Unable to parse log line: \n%v", line), "console")
parseErrors = appendCounterMap(parseErrors, line)
parseErrorsTotal++
} else {
cameraMatch := r.SubexpIndex("camera")
statusMatch := r.SubexpIndex("status")
Expand All @@ -322,7 +352,12 @@ func findObject(line string) (match []string, r *regexp.Regexp, matchType string
match := r.FindStringSubmatch(newLine)

if len(match) == 0 {
common.BIlogger(fmt.Sprintf("Unable to parse log line: \n%v", newLine), "console")
r2 := regexp.MustCompile(`(?P<camera>[^\s\\]*)(\sAI:\s|\sDeepStack:\s)(\[Objects\]\s|Alert\s|\[.+\]\s|)(?P<object>[aA-zZ]*|cancelled)(\s|:)(\[|)(?P<detail>[0-9]*|.*)`)
match2 := r2.FindStringSubmatch(newLine)
if len(match2) == 0 {
parseErrors = appendCounterMap(parseErrors, line)
parseErrorsTotal++
}
return nil, nil, ""
} else {
if strings.Contains(newLine, "cancelled") {
Expand All @@ -336,7 +371,8 @@ func findObject(line string) (match []string, r *regexp.Regexp, matchType string
r := regexp.MustCompile(`(?P<camera>[^\s\\]*)(\s*Signal:\s)(?P<status>.+)`)
match := r.FindStringSubmatch(line)
if len(match) == 0 {
common.BIlogger(fmt.Sprintf("Unable to parse log line: \n%v", line), "console")
parseErrors = appendCounterMap(parseErrors, line)
parseErrorsTotal++
} else {
cameraMatch := r.SubexpIndex("camera")
statusMatch := r.SubexpIndex("status")
Expand All @@ -362,7 +398,8 @@ func findObject(line string) (match []string, r *regexp.Regexp, matchType string
r1 := regexp.MustCompile(`(?P<folder>[^\s\\]*)(\s*Delete:).+(\[((?P<sizeused>.+)\/(?P<sizelimit>.+)),\s(?P<diskfree>.+)\sfree\])`)
match1 := r1.FindStringSubmatch(line)
if len(match1) == 0 {
common.BIlogger(fmt.Sprintf("Unable to parse log line: \n%v", line), "console")
parseErrors = appendCounterMap(parseErrors, line)
parseErrorsTotal++
return nil, nil, ""
}
folderMatch1 := r1.SubexpIndex("folder")
Expand Down Expand Up @@ -447,7 +484,8 @@ func findObject(line string) (match []string, r *regexp.Regexp, matchType string
r := regexp.MustCompile(`.*\s\s\s(?P<error>.*)`)
match := r.FindStringSubmatch(line)
if len(match) == 0 {
common.BIlogger(fmt.Sprintf("Unable to parse log line: \n%v", line), "console")
parseErrors = appendCounterMap(parseErrors, line)
parseErrorsTotal++
return nil, nil, ""
} else {
ErrorMatch := r.SubexpIndex("error")
Expand All @@ -465,7 +503,8 @@ func findObject(line string) (match []string, r *regexp.Regexp, matchType string
r := regexp.MustCompile(`.*\s\s\s(?P<warning>.*)`)
match := r.FindStringSubmatch(line)
if len(match) == 0 {
common.BIlogger(fmt.Sprintf("Unable to parse log line: \n%v", line), "console")
parseErrors = appendCounterMap(parseErrors, line)
parseErrorsTotal++
return nil, nil, ""
} else {
WarningMatch := r.SubexpIndex("warning")
Expand All @@ -481,3 +520,13 @@ func findObject(line string) (match []string, r *regexp.Regexp, matchType string
}
return nil, nil, ""
}

func appendCounterMap(m map[string]float64, key string) map[string]float64 {
if val, ok := m[key]; ok {
val++
m[key] = val
} else {
m[key] = 1
}
return m
}
Loading

0 comments on commit 5def84a

Please sign in to comment.