Release Notes
This is a new major version. It added external database module support, new metric domains, runtime debug controls, extensible AWS Secrets Manager parsing, and a more resilient Datadog delivery path.
As described in the Blip versioning guidelines, this series is not entirely backwards-compatible with v1.2. Integrations that use the affected exported APIs must be updated before upgrading.
| Component | v1.2 | v2 |
|---|---|---|
| AWS secret password helper | aws.Secret.Password(context.Context) (string, error) | Removed; use GetSecret or GetSecretPayload |
| Database credential type | dbconn.Credentials | blip.DbCredentials |
| Database credential callback | Returned dbconn.Credentials | Returns blip.DbCredentials |
| Default connection factory | NewConnFactory(awsConfig, modifyDB) | NewConnFactory(awsConfig, modifyDB, ...ConnFactoryOption) |
| Database-size query helper | Returned (string, error) | Returns (string, []interface{}, error) |
| Table-size query helper | Returned (string, error) | Returns (string, []interface{}, error) |
| Table-I/O query helper | Returned string | Returns (string, []interface{}) |
heartbeat.BlipReader values | Comparable | Not comparable |
To upgrade an integration:
- Update imports from
github.com/cashapp/blip/...togithub.com/cashapp/blip/v2/...and requiregithub.com/cashapp/blip/v2 v2.1.0or later. - Replace
dbconn.Credentialswithblip.DbCredentialsand update anydbconn.CredentialFuncimplementations. - Accept the new variadic options argument when storing or wrapping
dbconn.NewConnFactory; ordinary two-argument calls continue to compile. - Capture the parameter slice returned by
DataSizeQuery,TableSizeQuery, andTableIoWaitQuery, and pass it to the database query call. - Replace
aws.Secret.Passwordcalls withGetSecretfor the default JSON object orGetSecretPayloadplus a password secret parser for custom payloads. - Stop comparing
heartbeat.BlipReadervalues directly; compare the relevant state exposed by the reader instead.
AWS Secrets Manager password-secret authentication now uses the secret’s optional string username value instead of always using the configured monitor username. Remove username from the secret to retain the v1.2 behavior.
Default sink HTTP clients now have a 10-second whole-request timeout plus bounded connection and response-header timeouts. Custom HTTP client factories are unchanged.
- Deprecated the
lockparameter ofmonitor.LoadermethodsStart,Stop, andUnload; it will be removed in v3.Startstill ignores it and always locks the loader, andStopandUnloadwait for the monitor to stop with either value. - Changed the
monitor-stoppedevent to set the monitor ID and the messagestopped in <duration>. Previously the event’s monitor ID was empty and its message was the monitor ID. - Added
monitor-loader.stop-timeout(default3s), how long a reload, unload, or API stop waits for a monitor to stop. Removed monitors now stop in parallel, outside the loader mutex, and a monitor that doesn’t stop in time keeps stopping in the background. - Added the
monitor-stop-timeoutevent and theerror:stopmonitor status for a monitor that hasn’t stopped within the stop timeout. Blip reports it again every 10 times the stop timeout until the monitor stops. - Added
monitor.Loader.TryStartandmonitor.StartResult, which report whether a monitor started, is waiting for a monitor with the same ID to stop, was already running, was declined by theStartMonitorplugin, or failed to start.POST /monitors/startnow returns 202 while a monitor with the same ID is still stopping (the monitor starts when it has stopped), and 409 when the monitor is already running, the plugin declines it, or it fails to start.POST /monitors/stopreturns 202 when the monitor is still stopping after the stop timeout. - Changed
monitor.Loader.Monitorto return nil for an unknown monitor ID. Previously it panicked. - Changed the loader to send the
monitor-stoppedandmonitor-stop-timeoutevents from its stop goroutine, so an event receiver that panics on either event crashes Blip. Previously, when the API stopped a monitor,net/httprecovered the panic. Event receivers must not panic. - Behavior change:
monitor.Loader.Stopnow keeps the monitor stopped acrossLoadandStartMonitorsuntilStart, unless its config changes or it’s removed and loaded again. Go callers that relied on the next reload to restart a stopped monitor must callStart.POST /monitors/stopkeeps a monitor stopped across reloads, as before. - Behavior change:
POST /monitors/startnow calls theStartMonitorplugin, so it returns 409 for a monitor that the plugin declines. Previously the API started the monitor directly and skipped the plugin, so it could start a monitor that the plugin filtered out. Integrations that start filtered monitors through the API must allow them in the plugin. - A monitor stop, or a restart after a subsystem fails, no longer waits for the next collection tick, plan change check, or heartbeat. It cancels a collection, read-only check, or heartbeat write in progress, and drops metrics not yet sent to sinks.
- Behavior change: Applied
timeout-connect(default10s) to MySQL connections. Previously it was ignored, so connecting to an unreachable host waited for the operating system TCP connect timeout. Set it to0to retain the old behavior. An invalidtimeout-connectvalue, which used to be ignored, now fails config validation, so Blip doesn’t start, or a monitor in a reload doesn’t load. For example, a bare number such astimeout-connect: 5has no unit and is invalid; use5s. - Added per-monitor fault counters, such as collector panics and timeouts, engine max runtime (EMR) timeouts, and dropped metrics, reported by the new
GET /status/monitors/countersAPI endpoint. Integrations can read them with the newstatus.ReportCounters, and register their own withstatus.Counter; the counter names arestatusconstants likestatus.COLLECTOR_PANICS. - Added the optional
sink.CounterSinkinterface for sinks that report monitor status counters; the monitor callsRegisterCounterseach time it starts. A custom sink that wrapssink.Retrymust forwardRegisterCountersto it, else the retry buffer’ssink-retry-droppedcounter isn’t reported. - Fixed the
engine-emr-timeoutevent, which was defined but never sent. It’s now sent once for each collection, or exporter scrape, that reaches the engine max runtime, so event receivers get one per EMR timeout. - Fixed the
trxandstmt.currentcollectors, therepl.lagcollector’srepl-checkquery, and thewait.io.tablecollector’s column read, which didn’t wrap query errors with%w, so a query stopped at the collector max runtime (CMR) was reported only as acollector-errorevent. They now wrap query errors with%w, so the query also counts incollector-timeouts. - Fixed the
stmt.currentcollector, which returned partial metrics and no error when reading rows failed, for example when the CMR stopped it mid-read. It now returns the error, so it’s reported as acollector-errorevent, and a CMR timeout counts incollector-timeouts. - Fixed the
wait.io.tablecollector after a failed read. Withtruncate-table=no, or on a read error not caused by the CMR, it returned partial metrics and no error; it now returns the error and no metrics. Withtruncate-table=yes(the default), it doesn’t truncate the table after a failed read, and the truncate error policy’s metric setting (droporzero) now applies to the next sample, which covers more than one interval. Previously, a failed query or row scan was followed by one sample reported as a one-interval delta, about twice too high. A failed read is also no longer subject to the truncate error policy’signoreandstopsettings: previously, a CMR timeout mid-read also failed the truncate, soignorehid the error andstopstopped the collector. - Fixed the
repl.lagcollector’s heartbeat reader, which kept running after its monitor stopped whenrepl.lagwas collected at more than one level. It now stops when its monitor stops. - Changed the engine to call a collector’s
Preparecleanup func whenPreparereturns an error with a non-nil cleanup func, and to call the cleanup funcs of the collectors already prepared when a later collector in the plan fails. Previously they were not called, so resources started inPrepareleaked. - Fixed built-in sinks rejecting the retry options
buffer-size,send-timeout, andsend-retry-wait. Set these options in each built-in sink’s options. The docs previously showed a separatesinks.retrysection, which fails with “sink retry not registered”. - Added validation of the retry options:
buffer-sizemust be from 1 to 10000,send-timeoutmust be greater than zero and at most 1m, andsend-retry-waitmust be greater than zero. Other values prevent the monitor from loading. Previously a built-in sink rejected any retry option, so no config that loaded before is affected. - Changed the retry sink to stop waiting
send-retry-waitbetween sends whensend-timeoutexpires. Previously a send cycle could run pastsend-timeoutby up to onesend-retry-wait. - Added
sink.RetryArgs.Validateand thesink.MAX_RETRY_BUFFER_SIZEandsink.MAX_RETRY_SEND_TIMEOUTconstants.sink.NewRetrydoesn’t callValidate, so custom sinks that buildRetryArgsfrom user input should call it first. - Fixed
repl.lagat multiple levels with the Blip heartbeat writer:report-no-heartbeatnow applies at every level, not only at one random level. Levels that don’t setwriter, or set it toauto, use the writer set at another level. Previously each of these levels auto-detected its own writer, so it could usepfswhile another level usedblip. The writer optionsrepl-check,table,source-id,source-role, andnetwork-latencyare read from one level: the first level, by name, that setswritertopfsorblip, else the first level that collectsrepl.lag. - Behavior change: The
repl.lagheartbeat reader now usesrepl-check; previously it ignored it at every level. With the Blip heartbeat writer andrepl-checkset, an instance that isn’t a replica now dropsrepl.lag.current, or reports -1 withreport-not-a-replica=yes, instead of reporting heartbeat lag. - Behavior change: Plans that set the
repl.lagwritertopfsat one level andblipat another now fail to prepare, and the monitor keeps retrying the plan. Previously each level used its own writer. Set the samewriterat every level, or set it at one level only. - Changed
heartbeat.BlipReader.Stopto wait for the reader to return, which takes up to the heartbeat read timeout (2s) if a heartbeat query is running. Previously the reader could report status after its monitor was stopped and removed, so the removed monitor reappeared inGET /status/monitors. - Behavior change: Fixed
monitor-loader.stop-lossto count the net drop in the number of monitors. Previously it compared the number of removed monitors with the number loaded, so a small removal could trigger stop-loss and removing every monitor could not. A percent stop-loss (for example,50%) never triggered; it now triggers when the drop is greater than that percent of the monitors loaded before the reload. - Behavior change: Changed the default MySQL connection factory to wait up to 30s (
dbconn.DefaultCredentialTimeout) for a monitor’s first credentials. Previously it waited 500ms, so AWS Secrets Manager or IAM auth credentials often failed on the first try withrequest canceled, context deadline exceededwhen the AWS SDK first had to fetch AWS credentials (for example, EKS IRSA plus a cross-accountAssumeRole). The monitor retried, but loading shared plans fromplans.tablefailed, so Blip exited at startup. Added thedbconn.WithCredentialTimeoutoption to change it; a negative value panics. A monitor stopped while it waits for credentials can take up to the credential timeout to stop. If its plans are in a table, it can take twice that, because loading them makes another connection. Blip startup can wait up to the credential timeout when it loads shared plans fromplans.table. When no monitors are configured and the top-levelawsconfig setsiam-authorpassword-secret, local auto-detect can also wait up to the credential timeout for each user and socket it tries. Zero disables the timeout, so a hung credentials source can block a monitor stop or Blip startup indefinitely. - Fixed
aws.Secret.GetSecretPayload,aws.Secret.GetSecret, andblip.DefaultPasswordSecretParser, which formatted errors with%s, andaws.ConfigFactory.Make, which dropped the IMDS error when AWS region auto-detection failed. Callers couldn’t useerrors.Asorerrors.Isto detect the underlying error, such as*aws.RequestCanceledErroror a Secrets Manager API error type. They now wrap the error; error messages are unchanged.
Version v2.0.0 was withdrawn before release completion because its module path lacked the /v2 suffix required by Go modules. v2.1.0 is the first usable v2 release.
- Added the required
/v2module and import path for the v2 series. - Added opt-in external database module registration with opaque module-owned configuration and strict validation.
- Added composable database providers, engine-neutral credential callbacks, and collector access to monitor-owned database resources.
- Added collector database compatibility metadata and plan validation against each monitor’s database type.
- Hardened monitor teardown to stop collectors before releasing database providers.
- Added the
autoincdomain for auto-increment column utilization. - Added the
error.account,error.global,error.host,error.thread, anderror.userdomains. - Added the
innodb.buffer-pooldomain. - Added runtime debug toggling through
GET /debugandSIGUSR1. - Added customizable parsing of AWS Secrets Manager
SecretStringandSecretBinarypayloads. - Added bounded and checkpointed Datadog payload submission to avoid oversized requests and resume partially acknowledged batches.
- Prevented sink requests from blocking metric delivery indefinitely.
- Preserved complete metric metadata and isolated counter state in the delta sink.
- Redacted database, sink, and authenticated proxy credentials from debug logs.
- Fixed query construction to use driver parameter interpolation across collectors and heartbeats.
- Fixed interpolation of multiple environment and monitor placeholders in one value.
- Fixed nondeterministic
query.response-timebucket selection and added detailed latency diagnostics. - Fixed a shutdown panic in signal handling.
- Updated the test matrix from MySQL 5.7 to MySQL 8.4 and refreshed dependencies.
This is a new series (new minor version). A quick summary of what’s new in this series:
- “Engine v2”: monitor.Engine was rewritten to better handle long-running collectors, which simplifies delta counter handling in the new sink.Delta. Previously, two levels could run in parallel because metrics were originally designed and intended to be stateless. But delta counters are implicitly stateful: interval 1 is required before interval 2 in order to calculate the delta. Serial level collection solves the order problem but then requires new handling for long-running domains. Engine v2 handles all collection cases (normal and edge) correctly and consistently.
As per the Blip versioning guidelines, this new series is not entirely backwards-compatible with v1.1 due to these changes:
| # | Component | v1.0 | v1.1 |
|---|---|---|---|
| 1 | blip.Plugins | TransformMetrics func(*Metrics) | TransformMetrics func([]*Metrics) error |
| 2 | Events | See below | See below |
How to upgrade (by number in the table above):
- The first argument changed from one
*blip.Metricsto a slice of metrics, and it returns an error. Update yourTransformMetricsplugin function to match, and you’ll most likely wrap its original logic in aforloop, like:
func(metrics []*blip.Metrics) error {
for _, m := range metrics {
/* Original logic */
}
return nil
}
- If using an integration that works with Blip events, see event/list.go for the new event names.
- Fixed bug (panic) in
monitor/level_collectorwhen plan has no levels. - Added
plan/default.None.
- Rewrote monitor.Engine (“engine v2”) and some of level collector (LCO)
- Removed parallel level collection; made level collection serial
- Fixed long-running domain handling
- Added collector max runtime (CMR) context per domain equal to minimum level frequency
- Added
ErrMore - Added collector fault fencing: collector and its results are fenced off (dropped) if non-responsive or returns too late
- Added domain priority: collectors are started by ascending domain frequency (e.g. 5s domain collectors start before 20s domain collectors)
- Added
blip.Metrics.Intervalfield - Added
sink.Deltawrapper for automatic/transparent delta counter handling - Removed multi-component status
- Renamed and added several events
- Changed
blip.Plugins.TransformMetrics - Changed testing default from MySQL 5.7 to MySQL 8.0
This is a new series (new minor version). A quick summary of what’s new in this series:
- The Datadog sink sends delta counters, which is what Datadog expects.
- The repl.lag collector defaults to MySQL 8.x Performance Schema replication tables.
As per the Blip versioning guidelines, this new series is not entirely backwards-compatible with v1.0 due to these changes:
| # | Component | v1.0 | v1.1 |
|---|---|---|---|
| 1 | datadog sink | Sends cumulative counters | Sends delta counters |
| 2 | repl.lag collector | Default writer=blip | Default writer=auto will use Performance Schema on MySQL 8.x |
How to upgrade (by number in the table above):
- Datadog counters are deltas by default, so the new behavior works better. Use
.as_rate()instead of therate()function. Note that Datadog charts work best when the interval is set for each metric. - To continue using Blip heartbeats, explicitly configure
repl.lagwith optionwriter=blip.
datadogsink:- Changed to send delta counters instead of cumulative counters (PR #106)
repl.lagcollector:- Added MySQL 8.x Performance Schema support (auto-detected or writer=pfs) (PR #118)
wait.io.tablecollector:- Added
count_starto metrics
- Added
- Added sink
prom-pushgateway(Prometheus Pushgateway) - Updated built-in AWS RDS CA from rds-ca-2019 to the global bundle (PR #113)
- Made HA manager a configurable plugin (PR #116)
- Changed
max_used_connetionsto gauge (PR #111) - Fixed GitHub Dependabot alerts
datadogsink:- Fixed timestamps: DD expects timestamp as seconds, not milliseconds
- Send new
event.SINK_ERRORand debug DD API errors on successful request
query.response-timeandwait.io.tablecollectors:- Added
truncate-timeoutoption and error policy - Fixed docs: option
truncate-tabledefaults to “yes”
- Added
- Fixed GitHub Dependabot alerts
datadogsink:- Fixed intermittent panic
- Fixed HTTP error 413 (payload too large) by dynamically partitioning metrics
- Added option
api-compress(default: yes)
replcollector:- Added option
report-not-a-replica - Moved pkg vars
statusQueryandnewTermstoReplto handle multiple collectors on different versions - Fixed docs (only
repl.runningis currently collected)
- Added option
- Updated
aws/AuthToken.Password: pass context toauth.BuildAuthToken - Fixed GitHub Dependabot alerts
- Fixed
blip.VERSION
- First GA, production-ready release.