Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(inputs.mysql): Parse boolean values in metric v1 correctly #15063

Merged
merged 2 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading