Add byte counters for InfluxDB and Prometheus outputs (issue #350)

Track the number of bytes written per request for both InfluxDB and Prometheus outputs.

InfluxDB:
- Added bytesT counter constant
- Implemented calculateMetricBytes() to estimate line protocol size
- Updated batchV1() and batchV2() to count bytes per point
- Updated log output to display bytes written

Prometheus:
- Added Bytes field to Report struct
- Updated export() to calculate approximate metric byte size
- Updated log output to display bytes written

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Cody Lee 2025-12-11 10:55:33 -06:00
parent f86eb46192
commit a00aeb2eb5
No known key found for this signature in database
3 changed files with 38 additions and 4 deletions

View File

@ -94,17 +94,40 @@ func (r *Report) error(err error) {
const (
pointT = item("Point")
fieldT = item("Fields")
bytesT = item("Bytes")
)
// calculateMetricBytes estimates the size of a metric in InfluxDB line protocol format.
// Format: measurement,tag1=value1,tag2=value2 field1=value1,field2=value2 timestamp
func calculateMetricBytes(m *metric) int {
bytes := len(m.Table) // measurement name
// Add tags
for k, v := range m.Tags {
bytes += len(k) + len(v) + 2 // tag key + tag value + '=' and ','
}
// Add fields
for k, v := range m.Fields {
bytes += len(k) + len(fmt.Sprint(v)) + 2 // field key + field value + '=' and ','
}
bytes += 20 // approximate size for timestamp and separators
return bytes
}
func (r *Report) batchV1(m *metric, p *influxV1.Point) {
r.addCount(pointT)
r.addCount(fieldT, len(m.Fields))
r.addCount(bytesT, calculateMetricBytes(m))
r.bp.AddPoint(p)
}
func (r *Report) batchV2(m *metric, p *influxV2Write.Point) {
r.addCount(pointT)
r.addCount(fieldT, len(m.Fields))
r.addCount(bytesT, calculateMetricBytes(m))
r.writer.WritePoint(p)
}
@ -116,10 +139,10 @@ func (r *Report) String() string {
return fmt.Sprintf("Site: %d, Client: %d, "+
"Gateways: %d, %s: %d, %s: %d, %s/%s/%s/%s: %d/%d/%d/%d, "+
"DPI Site/Client: %d/%d, %s: %d, %s: %d, Err: %d, Dur: %v",
"DPI Site/Client: %d/%d, %s: %d, %s: %d, %s: %d, Err: %d, Dur: %v",
len(m.Sites), len(m.Clients),
c[udmT]+c[usgT]+c[uxgT]+c[uciT]+c[ubbT], uapT, c[uapT], uswT, c[uswT],
idsT, eventT, alarmT, anomalyT, c[idsT], c[eventT], c[alarmT], c[anomalyT],
len(m.SitesDPI), len(m.ClientsDPI), pointT, c[pointT], fieldT, c[fieldT],
len(r.Errors), r.Elapsed.Round(time.Millisecond))
bytesT, c[bytesT], len(r.Errors), r.Elapsed.Round(time.Millisecond))
}

View File

@ -87,6 +87,7 @@ type Report struct {
Total int // Total count of metrics recorded.
Errors int // Total count of errors recording metrics.
Zeros int // Total count of metrics equal to zero.
Bytes int // Total count of bytes written.
USG int // Total count of USG devices.
USW int // Total count of USW devices.
PDU int // Total count of PDU devices.

View File

@ -51,9 +51,9 @@ func (r *Report) report(c poller.Logger, descs map[*prometheus.Desc]bool) {
c.Logf("UniFi Measurements Exported. Site: %d, Client: %d, "+
"UAP: %d, USG/UDM: %d, USW: %d, DPI Site/Client: %d/%d, Desc: %d, "+
"Metric: %d, Err: %d, 0s: %d, Req/Total: %v / %v",
"Metric: %d, Bytes: %d, Err: %d, 0s: %d, Req/Total: %v / %v",
len(m.Sites), len(m.Clients), r.UAP, r.UDM+r.USG+r.UXG, r.USW, len(m.SitesDPI),
len(m.ClientsDPI), len(descs), r.Total, r.Errors, r.Zeros,
len(m.ClientsDPI), len(descs), r.Total, r.Bytes, r.Errors, r.Zeros,
r.Fetch.Round(time.Millisecond/oneDecimalPoint),
r.Elapsed.Round(time.Millisecond/oneDecimalPoint))
}
@ -65,6 +65,16 @@ func (r *Report) export(m *metric, v float64) prometheus.Metric {
r.Zeros++
}
// Calculate approximate byte size of the metric in Prometheus text format.
// Format: metric_name{label1="value1",label2="value2"} value timestamp
bytes := len(m.Desc.String()) // Metric name with label names
for _, label := range m.Labels {
bytes += len(label) + 3 // label value + quotes and comma/equals overhead
}
bytes += 20 // approximate size for value and timestamp
r.Bytes += bytes
return prometheus.MustNewConstMetric(m.Desc, m.ValueType, v, m.Labels...)
}