Skip to content

Commit

Permalink
fix(inputs.mysql): Parse boolean values in metric v1 correctly (#15063)
Browse files Browse the repository at this point in the history
  • Loading branch information
srebhan authored Mar 27, 2024
1 parent 57ed9fd commit 8c4fd53
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 3 deletions.
26 changes: 23 additions & 3 deletions plugins/inputs/mysql/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ type Mysql struct {

Log telegraf.Logger `toml:"-"`
tls.ClientConfig
lastT time.Time
getStatusQuery string
lastT time.Time
getStatusQuery string
loggedConvertFields map[string]bool
}

const (
Expand Down Expand Up @@ -85,6 +86,8 @@ func (m *Mysql) Init() error {
m.Servers = append(m.Servers, &s)
}

m.loggedConvertFields = make(map[string]bool)

// Register the TLS configuration. Due to the registry being a global
// one for the mysql package, we need to define unique IDs to avoid
// side effects and races between different plugin instances. Therefore,
Expand Down Expand Up @@ -773,7 +776,24 @@ func (m *Mysql) gatherGlobalStatuses(db *sql.DB, servtag string, acc telegraf.Ac
for _, mapped := range v1.Mappings {
if strings.HasPrefix(key, mapped.OnServer) {
// convert numeric values to integer
i, _ := strconv.Atoi(string(val))
var i int
v := string(val)
switch v {
case "ON", "true":
i = 1
case "OFF", "false":
i = 0
default:
if i, err = strconv.Atoi(v); err != nil {
// Make the value a <nil> value to prevent adding
// the field containing nonsense values.
i = 0
if !m.loggedConvertFields[key] {
m.Log.Warnf("Cannot convert value %q for key %q to integer outputting zero...", v, key)
m.loggedConvertFields[key] = true
}
}
}
fields[mapped.InExport+key[len(mapped.OnServer):]] = i
found = true
}
Expand Down
45 changes: 45 additions & 0 deletions plugins/inputs/mysql/mysql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ func TestMysqlDefaultsToLocalIntegration(t *testing.T) {

dsn := fmt.Sprintf("root@tcp(%s:%s)/", container.Address, container.Ports[servicePort])
s := config.NewSecret([]byte(dsn))
defer s.Destroy()
m := &Mysql{
Servers: []*config.Secret{&s},
Log: &testutil.Logger{},
}
require.NoError(t, m.Init())

Expand Down Expand Up @@ -74,11 +76,13 @@ func TestMysqlMultipleInstancesIntegration(t *testing.T) {

dsn := fmt.Sprintf("root@tcp(%s:%s)/?tls=false", container.Address, container.Ports[servicePort])
s := config.NewSecret([]byte(dsn))
defer s.Destroy()
m := &Mysql{
Servers: []*config.Secret{&s},
IntervalSlow: config.Duration(30 * time.Second),
GatherGlobalVars: true,
MetricVersion: 2,
Log: &testutil.Logger{},
}
require.NoError(t, m.Init())

Expand All @@ -93,6 +97,7 @@ func TestMysqlMultipleInstancesIntegration(t *testing.T) {
m2 := &Mysql{
Servers: []*config.Secret{&s2},
MetricVersion: 2,
Log: &testutil.Logger{},
}
require.NoError(t, m2.Init())

Expand Down Expand Up @@ -126,9 +131,11 @@ func TestPercona8Integration(t *testing.T) {

dsn := fmt.Sprintf("root:secret@tcp(%s:%s)/", container.Address, container.Ports[servicePort])
s := config.NewSecret([]byte(dsn))
defer s.Destroy()
plugin := &Mysql{
Servers: []*config.Secret{&s},
GatherUserStatistics: true,
Log: &testutil.Logger{},
}
require.NoError(t, plugin.Init())

Expand All @@ -141,6 +148,44 @@ func TestPercona8Integration(t *testing.T) {
require.True(t, acc.HasFloatField("mysql_user_stats", "busy_time"))
}

func TestGaleraIntegration(t *testing.T) {
if testing.Short() {
t.Skip("Skipping integration test in short mode")
}

container := testutil.Container{
Image: "bitnami/mariadb-galera",
Env: map[string]string{"ALLOW_EMPTY_PASSWORD": "yes"},
ExposedPorts: []string{servicePort},
WaitingFor: wait.ForAll(
wait.ForLog("Synchronized with group, ready for connections"),
wait.ForListeningPort(nat.Port(servicePort)),
),
}
require.NoError(t, container.Start(), "failed to start container")
defer container.Terminate()

dsn := fmt.Sprintf("root@tcp(%s:%s)/", container.Address, container.Ports[servicePort])
s := config.NewSecret([]byte(dsn))
defer s.Destroy()
plugin := &Mysql{
Servers: []*config.Secret{&s},
Log: &testutil.Logger{},
}
require.NoError(t, plugin.Init())

var acc testutil.Accumulator
require.NoError(t, plugin.Gather(&acc))
require.Empty(t, acc.Errors)
require.True(t, acc.HasIntField("mysql", "wsrep_ready"))
for _, m := range acc.GetTelegrafMetrics() {
if v, found := m.GetField("wsrep_ready"); found {
require.EqualValues(t, 1, v, "invalid value for field wsrep_ready")
break
}
}
}

func TestMysqlGetDSNTag(t *testing.T) {
tests := []struct {
input string
Expand Down

0 comments on commit 8c4fd53

Please sign in to comment.