Skip to content

Commit

Permalink
removed logoffset, fixed concurrent map writes crash, updated how exp…
Browse files Browse the repository at this point in the history
…orter reads log file
  • Loading branch information
wymangr committed Aug 28, 2024
1 parent 2ea87a1 commit 5c6110e
Show file tree
Hide file tree
Showing 8 changed files with 3,056 additions and 3,030 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ Flag | Description | Default value | Required
-|-|-|-
`--telemetry.addr` | addresses on which to expose metrics | `:2112` | No
`--logpath` | Directory path to the Blue Iris Logs | `C:\BlueIris\log\` | No
`--logoffset` | Number in MB to offset the log file before reading. Helpful for large log files. 0 to disable | `10` | No
`--telemetry.path` | URL path for surfacing collected metrics | `/metrics` | No
`--service.install` | Install blueiris_exporter as a Windows service | None | No
`--service.uninstall` | Uninstall blueiris_exporter Windows service | None | No
Expand Down
138 changes: 70 additions & 68 deletions blueiris/blueirisMetrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import (
"bufio"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"regexp"
"strconv"
"strings"
"sync"
"time"

"github.com/prometheus/client_golang/prometheus"
Expand All @@ -25,51 +25,41 @@ type aidata struct {
latest string
}

var latestai = make(map[string]string)
var camerastatus = make(map[string]map[string]interface{})
var diskStats = make(map[string]map[string]float64)

// var pushes = make(map[string]map[string]interface{})
var lastLogLine string = ""
var lastLogFile string = ""

var (
timeoutcount float64
servererrorcount float64
notrespondingcount float64
errorMetricsTotal float64
warningMetricsTotal float64
parseErrorsTotal float64
restartCount float64
aiErrorCount 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
profileCount map[string]float64
timeoutcount float64 = 0
servererrorcount float64 = 0
notrespondingcount float64 = 0
errorMetricsTotal float64 = 0
warningMetricsTotal float64 = 0
parseErrorsTotal float64 = 0
restartCount float64 = 0
aiErrorCount float64 = 0
aiRestartingCount float64 = 0
aiRestartedCount float64 = 0
triggerCount map[string]float64 = make(map[string]float64)
pushCount map[string]float64 = make(map[string]float64)
errorMetrics map[string]float64 = make(map[string]float64)
warningMetrics map[string]float64 = make(map[string]float64)
parseErrors map[string]float64 = make(map[string]float64)
profileCount map[string]float64 = make(map[string]float64)
aiMetrics map[string]aidata = make(map[string]aidata)
diskStats map[string]map[string]float64 = make(map[string]map[string]float64)
camerastatus map[string]map[string]interface{} = make(map[string]map[string]interface{})
latestai map[string]string = make(map[string]string)
)

func BlueIris(ch chan<- prometheus.Metric, m common.MetricInfo, SecMet []common.MetricInfo, logpath string, logOffset int64) {
var mutex = sync.RWMutex{}

func BlueIris(ch chan<- prometheus.Metric, m common.MetricInfo, SecMet []common.MetricInfo, logpath string) {

scrapeTime := time.Now()
aiMetrics := make(map[string]aidata)
errorMetrics = make(map[string]float64)
warningMetrics = make(map[string]float64)
triggerCount = make(map[string]float64)
pushCount = make(map[string]float64)
profileCount = make(map[string]float64)
errorMetricsTotal = 0
warningMetricsTotal = 0
parseErrorsTotal = 0
restartCount = 0
aiErrorCount = 0
aiRestartingCount = 0
aiRestartedCount = 0
timeoutcount = 0
servererrorcount = 0
notrespondingcount = 0
mutex.Lock()

parseErrors = make(map[string]float64)
startScanning := false

dir := logpath
files, err := ioutil.ReadDir(dir)
Expand Down Expand Up @@ -100,44 +90,55 @@ func BlueIris(ch chan<- prometheus.Metric, m common.MetricInfo, SecMet []common.
}
defer file.Close()

offset := 0 - (logOffset * 1000000)
if offset != 0 {
file.Seek(offset, io.SeekEnd)
if lastLogFile != "" && lastLogFile != newestFile {
startScanning = true
}
lastLogFile = newestFile

scanner := bufio.NewScanner(file)
scanner.Scan()

for scanner.Scan() {
match, r, matchType := findObject(scanner.Text())
if (matchType == "alert") || (matchType == "canceled") {
cameraMatch := r.SubexpIndex("camera")
durationMatch := r.SubexpIndex("duration")
objectMatch := r.SubexpIndex("object")
detailMatch := r.SubexpIndex("detail")

camera := match[cameraMatch]
duration, err := strconv.ParseFloat(match[durationMatch], 64)
if err != nil {
common.BIlogger(fmt.Sprintf("BlueIris - Error parsing duration float. Err: %v", err), "error")
ch <- prometheus.MustNewConstMetric(m.Errors.WithLabelValues(err.Error()).Desc(), prometheus.CounterValue, 1, "BlueIris")
continue
if lastLogLine == scanner.Text() || lastLogLine == "" {
startScanning = true
if lastLogLine == "" {
lastLogLine = scanner.Text()
}
continue
}

alertcount := aiMetrics[camera+matchType].alertcount
alertcount++
if startScanning {
lastLogLine = scanner.Text()
match, r, matchType := findObject(scanner.Text())
if (matchType == "alert") || (matchType == "canceled") {
cameraMatch := r.SubexpIndex("camera")
durationMatch := r.SubexpIndex("duration")
objectMatch := r.SubexpIndex("object")
detailMatch := r.SubexpIndex("detail")

camera := match[cameraMatch]
duration, err := strconv.ParseFloat(match[durationMatch], 64)
if err != nil {
common.BIlogger(fmt.Sprintf("BlueIris - Error parsing duration float. Err: %v", err), "error")
ch <- prometheus.MustNewConstMetric(m.Errors.WithLabelValues(err.Error()).Desc(), prometheus.CounterValue, 1, "BlueIris")
continue
}

makeMap(camera, camerastatus)
camerastatus[camera]["status"] = 0.0
camerastatus[camera]["detail"] = "object"
aiMetrics[camera+matchType] = aidata{
camera: camera,
duration: duration,
object: match[objectMatch],
alertcount: alertcount,
detail: match[detailMatch],
latest: scanner.Text(),
}
alertcount := aiMetrics[camera+matchType].alertcount
alertcount++

makeMap(camera, camerastatus)
camerastatus[camera]["status"] = 0.0
camerastatus[camera]["detail"] = "object"
aiMetrics[camera+matchType] = aidata{
camera: camera,
duration: duration,
object: match[objectMatch],
alertcount: alertcount,
detail: match[detailMatch],
latest: scanner.Text(),
}
}
}
}

Expand Down Expand Up @@ -269,6 +270,7 @@ func BlueIris(ch chan<- prometheus.Metric, m common.MetricInfo, SecMet []common.
ch <- prometheus.MustNewConstMetric(m.Errors.WithLabelValues("BlueIris").Desc(), prometheus.CounterValue, 0, "BlueIris")
ch <- prometheus.MustNewConstMetric(m.Timer, prometheus.GaugeValue, time.Since(scrapeTime).Seconds(), "BlueIris")

mutex.Unlock()
}

func makeMap(camera string, m map[string]map[string]interface{}) {
Expand Down
31 changes: 11 additions & 20 deletions blueiris_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main
import (
"fmt"
"net/http"
"strconv"
"strings"
"sync"

Expand All @@ -14,11 +13,10 @@ import (
"gopkg.in/alecthomas/kingpin.v2"
)

func NewExporterBlueIris(selectedServerMetrics map[int]common.MetricInfo, logpath string, logOffset int64) (*ExporterBlueIris, error) {
func NewExporterBlueIris(selectedServerMetrics map[int]common.MetricInfo, logpath string) (*ExporterBlueIris, error) {
return &ExporterBlueIris{
blueIrisServerMetrics: selectedServerMetrics,
logpath: logpath,
lofOffset: logOffset,
}, nil
}

Expand All @@ -37,23 +35,18 @@ func (e *ExporterBlueIris) Collect(ch chan<- prometheus.Metric) {
if m.Collect {
name := m.Name
wg.Add(1)
go CollectMetrics(&wg, ch, m, name, e.logpath, e.lofOffset)
go CollectMetrics(&wg, ch, m, name, e.logpath)
}
}

wg.Wait()
}

func start(logpath string, metricsPath string, port string, logOffset string) error {
func start(logpath string, metricsPath string, port string) error {

var finalPort string
var finalLogpath string

finalLogOffset, errOffset := strconv.ParseInt(logOffset, 10, 64)
if errOffset != nil {
return errOffset
}

if strings.HasSuffix(logpath, `\`) {
finalLogpath = logpath
} else if strings.HasSuffix(logpath, `/`) {
Expand All @@ -66,17 +59,20 @@ func start(logpath string, metricsPath string, port string, logOffset string) er
}
}

exporterBlueIris, _ := NewExporterBlueIris(blueIrisServerMetrics, finalLogpath, finalLogOffset)
exporterBlueIris, _ := NewExporterBlueIris(blueIrisServerMetrics, finalLogpath)
blueIrisReg := prometheus.NewRegistry()
blueIrisReg.MustRegister(exporterBlueIris, promcollectors.NewGoCollector())

blueIrisReg.Gather()

http.Handle(metricsPath, promhttp.HandlerFor(blueIrisReg, promhttp.HandlerOpts{}))

if strings.Contains(port, ":") {
finalPort = port
} else {
finalPort = ":" + port
}
common.BIlogger("Starting Blue Iris Exporter http server", "info")
err := http.ListenAndServe(finalPort, nil)
if err != nil {
return err
Expand Down Expand Up @@ -132,17 +128,13 @@ func main() {
"telemetry.path",
"URL path for surfacing collected metrics.",
).Default("/metrics").String()
logOffset = kingpin.Flag(
"logoffset",
"Size in MG to offset the logfile",
).Default("10").String()
)

kingpin.HelpFlag.Short('h')
kingpin.Parse()

if *install {
err := installService(svcName, svcNameLong, *logpath, *metricsPath, *port, *logOffset)
err := installService(svcName, svcNameLong, *logpath, *metricsPath, *port)
if err != nil {
common.BIlogger(err.Error(), "error")
}
Expand Down Expand Up @@ -173,14 +165,13 @@ func main() {
common.BIlogger(err.Error(), "error")
}
} else {
var a string = fmt.Sprintf(`starting Blue Iris Exporter with the following:
var a string = fmt.Sprintf(`Starting Blue Iris Exporter with the following:
Log Path: %v
Metric Path: %v
Port: %v
Log Offset: %v MB`, *logpath, *metricsPath, *port, *logOffset)
Port: %v`, *logpath, *metricsPath, *port)
common.BIlogger(a, "info")

err := start(*logpath, *metricsPath, *port, *logOffset)
err := start(*logpath, *metricsPath, *port)
if err != nil {
common.BIlogger(fmt.Sprintf("Error starting blueiris_exporter. err: %v", err), "error")
}
Expand Down
2 changes: 1 addition & 1 deletion common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type MetricInfo struct {
Name string
Collect bool
SecondaryCollect []int
Function func(ch chan<- prometheus.Metric, m MetricInfo, SecMet []MetricInfo, logpath string, logOffset int64)
Function func(ch chan<- prometheus.Metric, m MetricInfo, SecMet []MetricInfo, logpath string)
Server string
Errors *prometheus.CounterVec
Timer *prometheus.Desc
Expand Down
Loading

0 comments on commit 5c6110e

Please sign in to comment.