Skip to content

Commit 1d34414

Browse files
dbo11y: stop tracking alloy's own queries in mysql (#4978)
dbo11y: stop tracking alloy's own queries in mysql and postgres This PR introduces a change for excluding "own queries" in mysql: we add a new `setup_actors` collector that checks (and optionally updates) settings for the currently connected user. By default it just checks that `enabled=NO` and logs out if that's not the case. Optionally, the component can auto-update this setting itself. This behaviour is disabled by default, though: it follows the same pattern of `setup_consumers` where two boolean settings are required to enable the auto-update. Additionally, auto-update requires `INSERT` and `UPDATE` permissions (docs on the website).
1 parent 2c1bcce commit 1d34414

File tree

6 files changed

+852
-15
lines changed

6 files changed

+852
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ Main (unreleased)
3030

3131
### Bugfixes
3232

33-
3433
- (_Public Preview_) Additions to `database_observability.postgres` component:
3534
- `schema_details`
3635
- fixes collection of schema details for mixed case table names (@fridgepoet)
3736

3837
- (_Public Preview_) Additions to `database_observability.mysql` component:
3938
- replace the internal `server_id` label attribution in favor of a hash composed from `@@server_uuid` and `@@hostname`
39+
- add `setup_actors` collector that checks and optionally updates settings to avoid tracking queries for the currently connected user (@cristiangreco)
4040

4141
v1.12.0
4242
-----------------

docs/sources/reference/components/database_observability/database_observability.mysql.md

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,15 @@ You can use the following arguments with `database_observability.mysql`:
3737

3838
The following collectors are configurable:
3939

40-
| Name | Description | Enabled by default |
41-
|-------------------|----------------------------------------------------------|--------------------|
42-
| `query_details` | Collect queries information. | yes |
43-
| `schema_details` | Collect schemas and tables from `information_schema`. | yes |
44-
| `query_samples` | Collect query samples. | yes |
45-
| `setup_consumers` | Collect enabled `performance_schema.setup_consumers`. | yes |
46-
| `locks` | Collect queries that are waiting/blocking other queries. | no |
47-
| `explain_plans` | Collect explain plans information. | yes |
40+
| Name | Description | Enabled by default |
41+
|-------------------|--------------------------------------------------------------|--------------------|
42+
| `query_details` | Collect queries information. | yes |
43+
| `schema_details` | Collect schemas and tables from `information_schema`. | yes |
44+
| `query_samples` | Collect query samples. | yes |
45+
| `setup_consumers` | Collect enabled `performance_schema.setup_consumers`. | yes |
46+
| `setup_actors` | Check and update `performance_schema.setup_actors` settings. | yes |
47+
| `locks` | Collect queries that are waiting/blocking other queries. | no |
48+
| `explain_plans` | Collect explain plans information. | yes |
4849

4950
## Blocks
5051

@@ -55,6 +56,7 @@ You can use the following blocks with `database_observability.mysql`:
5556
| [`cloud_provider`][cloud_provider] | Provide Cloud Provider information. | no |
5657
| `cloud_provider` > [`aws`][aws] | Provide AWS database host information. | no |
5758
| [`setup_consumers`][setup_consumers] | Configure the `setup_consumers` collector. | no |
59+
| [`setup_actors`][setup_actors] | Configure the `setup_actors` collector. | no |
5860
| [`query_details`][query_details] | Configure the queries collector. | no |
5961
| [`schema_details`][schema_details] | Configure the schema and table details collector. | no |
6062
| [`explain_plans`][explain_plans] | Configure the explain plans collector. | no |
@@ -72,6 +74,7 @@ For example, `cloud_provider` > `aws` refers to a `aws` block defined inside an
7274
[explain_plans]: #explain_plans
7375
[locks]: #locks
7476
[query_samples]: #query_samples
77+
[setup_actors]: #setup_actors
7578

7679
### `cloud_provider`
7780

@@ -135,6 +138,14 @@ The `aws` block supplies the [ARN](https://docs.aws.amazon.com/IAM/latest/UserGu
135138
| `auto_enable_setup_consumers` | `boolean` | Whether to enable some specific `performance_schema.setup_consumers` settings. | `false` | no |
136139
| `setup_consumers_check_interval` | `duration` | How frequently to check if `setup_consumers` are correctly enabled. | `"1h"` | no |
137140

141+
### `setup_actors`
142+
143+
| Name | Type | Description | Default | Required |
144+
| -------------------------- | ---------- | ---------------------------------------------------------------------- | ------- | -------- |
145+
| `auto_update_setup_actors` | `boolean` | Whether to enable updating `performance_schema.setup_actors` settings. | `false` | no |
146+
| `collect_interval` | `duration` | How frequently to check if `setup_actors` are configured correctly. | `"1h"` | no |
147+
148+
138149
## Example
139150

140151
```alloy
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package collector
2+
3+
import (
4+
"context"
5+
"database/sql"
6+
"errors"
7+
"fmt"
8+
"strings"
9+
"time"
10+
11+
"github.com/go-kit/log"
12+
"go.uber.org/atomic"
13+
14+
"github.com/grafana/alloy/internal/runtime/logging/level"
15+
)
16+
17+
const (
18+
SetupActorsCollector = "setup_actors"
19+
20+
selectUserQuery = `SELECT substring_index(current_user(), '@', 1)`
21+
22+
selectQuery = `SELECT enabled, history
23+
FROM performance_schema.setup_actors
24+
WHERE user = ?`
25+
26+
updateQuery = `UPDATE performance_schema.setup_actors
27+
SET enabled='NO', history='NO'
28+
WHERE user = ?`
29+
30+
insertQuery = `INSERT INTO performance_schema.setup_actors
31+
(host, user, role, enabled, history)
32+
VALUES ('%', ?, '%', 'NO', 'NO')`
33+
)
34+
35+
type SetupActorsArguments struct {
36+
DB *sql.DB
37+
Logger log.Logger
38+
CollectInterval time.Duration
39+
AutoUpdateSetupActors bool
40+
}
41+
42+
type SetupActors struct {
43+
dbConnection *sql.DB
44+
collectInterval time.Duration
45+
autoUpdateSetupActors bool
46+
47+
logger log.Logger
48+
running *atomic.Bool
49+
ctx context.Context
50+
cancel context.CancelFunc
51+
}
52+
53+
func NewSetupActors(args SetupActorsArguments) (*SetupActors, error) {
54+
return &SetupActors{
55+
dbConnection: args.DB,
56+
running: &atomic.Bool{},
57+
logger: log.With(args.Logger, "collector", SetupActorsCollector),
58+
collectInterval: args.CollectInterval,
59+
autoUpdateSetupActors: args.AutoUpdateSetupActors,
60+
}, nil
61+
}
62+
63+
func (c *SetupActors) Name() string {
64+
return SetupActorsCollector
65+
}
66+
67+
func (c *SetupActors) Start(ctx context.Context) error {
68+
level.Debug(c.logger).Log("msg", "collector started")
69+
c.running.Store(true)
70+
71+
ctx, cancel := context.WithCancel(ctx)
72+
c.ctx = ctx
73+
c.cancel = cancel
74+
75+
var user string
76+
if err := c.dbConnection.QueryRowContext(ctx, selectUserQuery).Scan(&user); err != nil {
77+
level.Error(c.logger).Log("msg", "failed to get current user", "err", err)
78+
c.running.Store(false)
79+
cancel()
80+
return err
81+
}
82+
83+
go func() {
84+
defer func() {
85+
c.Stop()
86+
c.running.Store(false)
87+
}()
88+
89+
ticker := time.NewTicker(c.collectInterval)
90+
91+
for {
92+
if err := c.checkSetupActors(c.ctx, user); err != nil {
93+
level.Error(c.logger).Log("msg", "collector error", "err", err)
94+
}
95+
96+
select {
97+
case <-c.ctx.Done():
98+
return
99+
case <-ticker.C:
100+
// continue loop
101+
}
102+
}
103+
}()
104+
105+
return nil
106+
}
107+
108+
func (c *SetupActors) Stopped() bool {
109+
return !c.running.Load()
110+
}
111+
112+
func (c *SetupActors) Stop() {
113+
c.cancel()
114+
c.running.Store(false)
115+
}
116+
117+
func (c *SetupActors) checkSetupActors(ctx context.Context, user string) error {
118+
var enabled, history string
119+
err := c.dbConnection.QueryRowContext(ctx, selectQuery, user).Scan(&enabled, &history)
120+
if errors.Is(err, sql.ErrNoRows) {
121+
if c.autoUpdateSetupActors {
122+
return c.insertSetupActors(ctx, user)
123+
} else {
124+
level.Info(c.logger).Log("msg", "setup_actors configuration missing, but auto-update is disabled")
125+
return nil
126+
}
127+
} else if err != nil {
128+
level.Error(c.logger).Log("msg", "failed to query setup_actors table", "err", err)
129+
return err
130+
}
131+
132+
if strings.ToUpper(enabled) != "NO" || strings.ToUpper(history) != "NO" {
133+
if c.autoUpdateSetupActors {
134+
return c.updateSetupActors(ctx, user, enabled, history)
135+
} else {
136+
level.Info(c.logger).Log("msg", "setup_actors configuration is not correct, but auto-update is disabled")
137+
return nil
138+
}
139+
}
140+
141+
return nil
142+
}
143+
144+
func (c *SetupActors) insertSetupActors(ctx context.Context, user string) error {
145+
_, err := c.dbConnection.ExecContext(ctx, insertQuery, user)
146+
if err != nil {
147+
level.Error(c.logger).Log("msg", "failed to insert setup_actors row", "err", err, "user", user)
148+
return err
149+
}
150+
151+
level.Debug(c.logger).Log("msg", "inserted new setup_actors row", "user", user)
152+
return nil
153+
}
154+
155+
func (c *SetupActors) updateSetupActors(ctx context.Context, user string, enabled string, history string) error {
156+
r, err := c.dbConnection.ExecContext(ctx, updateQuery, user)
157+
if err != nil {
158+
level.Error(c.logger).Log("msg", "failed to update setup_actors row", "err", err, "user", user)
159+
return err
160+
}
161+
162+
rowsAffected, err := r.RowsAffected()
163+
if err != nil {
164+
level.Error(c.logger).Log("msg", "failed to get rows affected from setup_actors update", "err", err)
165+
return err
166+
}
167+
if rowsAffected == 0 {
168+
level.Error(c.logger).Log("msg", "no rows affected from setup_actors update", "user", user)
169+
return fmt.Errorf("no rows affected from setup_actors update")
170+
}
171+
172+
level.Debug(c.logger).Log("msg", "updated setup_actors row", "rows_affected", rowsAffected, "previous_enabled", enabled, "previous_history", history, "user", user)
173+
return nil
174+
}

0 commit comments

Comments
 (0)