Skip to content
This repository has been archived by the owner on Apr 2, 2024. It is now read-only.

Commit

Permalink
Improve function naming for getting jsonb and label value
Browse files Browse the repository at this point in the history
Change function names to val() and jsonb() for getting
the label value from an id and the jsonb from a label array.

Change the type name for a label array from label_ids to
label_array for consistency.

Fix places where a connection pool was started before a
migration to start after. This doen't work if a migration alters
database to change gucs because pool connection started before
the migrate won't pick up the change. This lead to test flakiness
and could produce real bugs too.
  • Loading branch information
cevian committed Apr 24, 2020
1 parent 454d6f6 commit 67b2fbd
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 64 deletions.
15 changes: 9 additions & 6 deletions cmd/timescale-prometheus/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,19 +137,22 @@ func main() {

http.Handle(cfg.telemetryPath, promhttp.Handler())

elector = initElector(cfg)

// migrate has to happen after elector started
if cfg.migrate {
migrate(&cfg.pgmodelCfg)
}

// client has to be initiated after migrate since migrate
// can change database GUC settings
client, err := pgclient.NewClient(&cfg.pgmodelCfg)
if err != nil {
log.Error(err)
os.Exit(1)
}
defer client.Close()

elector = initElector(cfg)

if cfg.migrate {
migrate(&cfg.pgmodelCfg)
}

http.Handle("/write", timeHandler("write", write(client)))
http.Handle("/read", timeHandler("read", read(client)))
http.Handle("/healthz", health(client))
Expand Down
20 changes: 13 additions & 7 deletions docs/sql_schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ simply `cpu_usage` view). The view contains a the following column:
- labels - The array of label ids
- plus a column for each label name's id in the metric's label set

A label value can be retrieved from the label name id using the `get_label_value`
function. A full json for the series can be retrieved with `label_array_to_jsonb(labels)`.
A label value can be retrieved from the label name id using the `val`
function. A full json for the series can be retrieved with `jsonb(labels)`.

For example:
```
Expand All @@ -42,12 +42,15 @@ For example:
```

Example query for single point with their labels:

```
SELECT
label_array_to_jsonb(labels) as labels,
jsonb(labels) as labels,
value
FROM cpu_usage
WHERE time < now();

```
Results:
```
labels | value
----------------------------------------------+-------
Expand All @@ -59,12 +62,15 @@ WHERE time < now();

Example query for a rollup:

```
SELECT
get_label_value(node_id) as node,
val(node_id) as node,
avg(value)
FROM cpu_usage
WHERE time < now()
GROUP BY node_id
```
Results:

```
node | avg
Expand Down Expand Up @@ -143,7 +149,7 @@ FROM cpu_usage u
WHERE labels ? ('namepace' == 'dev') AND labels ? ('node' == 'brain')
```

Label matchers are formed by using a qualifier of the form `labels ? (<tag_key> <operator> <pattern>)`.
Label matchers are formed by using a qualifier of the form `labels ? (<tag_key> <operator> <pattern>)` (note: the parantheses are mandatory).
There are four operators,

- `==` match tag values that are equal to the pattern
Expand All @@ -165,7 +171,7 @@ For those coming from PromQL there are a few differences to keep in mind:

The `eq` function tests exact equivalence between labels, without comparing the metric name (`__name__`) label key.
For instance if the labels `a` is `{"__name__":"metric", "foo":"bar", "baz":"frob"}`
then `SELECT eq(a, jsonb {"__name__":"something else", "foo":"bar", "baz":"frob"})` will evaluate to `true`, however, unlike `@>` if `SELECT eq(a, {"__name__":"metric", "foo":"bar"})` will evaluate to `false`.
then `SELECT eq(a, jsonb {"__name__":"something else", "foo":"bar", "baz":"frob"})` will evaluate to `true`, however, unlike `@>`, the query `SELECT eq(a, {"__name__":"metric", "foo":"bar"})` will evaluate to `false`.
Thus, it can be used to compare across metrics or within a metric.

For example, to join 2 series that are scraped at the same time:
Expand Down
48 changes: 29 additions & 19 deletions pkg/pgmodel/migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,15 @@ func TestSQLRetentionPeriod(t *testing.T) {
})
}

func getFingerprintFromJson(t *testing.T, jsonRes []byte) model.Fingerprint {
labelSetRes := make(model.LabelSet)
err := json.Unmarshal(jsonRes, &labelSetRes)
if err != nil {
t.Fatal(err)
}
return labelSetRes.Fingerprint()
}

func TestSQLJsonLabelArray(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
Expand Down Expand Up @@ -548,7 +557,7 @@ func TestSQLJsonLabelArray(t *testing.T) {
t.Fatal(err)
}
var labelArray []int
err = db.QueryRow(context.Background(), "SELECT * FROM prom.jsonb_to_label_array($1)", jsonOrig).Scan(&labelArray)
err = db.QueryRow(context.Background(), "SELECT * FROM prom.label_array($1)", jsonOrig).Scan(&labelArray)
if err != nil {
t.Fatal(err)
}
Expand All @@ -575,18 +584,14 @@ func TestSQLJsonLabelArray(t *testing.T) {
t.Fatalf("Expected label arrays to be equal: %v != %v", labelArray, labelArrayKV)
}

var jsonres []byte
err = db.QueryRow(context.Background(), "SELECT * FROM prom.label_array_to_jsonb(($1::int[]))", labelArray).Scan(&jsonres)
var jsonRes []byte
err = db.QueryRow(context.Background(), "SELECT * FROM jsonb(($1::int[]))", labelArray).Scan(&jsonRes)
if err != nil {
t.Fatal(err)
}
labelSetRes := make(model.LabelSet, len(ts.Labels))
err = json.Unmarshal(jsonres, &labelSetRes)
if err != nil {
t.Fatal(err)
}
if labelSet.Fingerprint() != labelSetRes.Fingerprint() {
t.Fatalf("Json not equal: got\n%v\nexpected\n%v", string(jsonres), string(jsonOrig))
fingerprintRes := getFingerprintFromJson(t, jsonRes)
if labelSet.Fingerprint() != fingerprintRes {
t.Fatalf("Json not equal: got\n%v\nexpected\n%v", string(fingerprintRes), string(jsonOrig))

}

Expand Down Expand Up @@ -626,19 +631,15 @@ func TestSQLJsonLabelArray(t *testing.T) {
t.Fatalf("Expected the series ids to be equal: %v != %v", seriesID, seriesIDKeyVal)
}

err = db.QueryRow(context.Background(), "SELECT prom.label_array_to_jsonb(labels) FROM _prom_catalog.series WHERE id=$1",
seriesID).Scan(&jsonres)
if err != nil {
t.Fatal(err)
}
labelSetRes = make(model.LabelSet, len(ts.Labels))
err = json.Unmarshal(jsonres, &labelSetRes)
err = db.QueryRow(context.Background(), "SELECT prom.jsonb(labels) FROM _prom_catalog.series WHERE id=$1",
seriesID).Scan(&jsonRes)
if err != nil {
t.Fatal(err)
}
fingerprintRes = getFingerprintFromJson(t, jsonRes)

if labelSet.Fingerprint() != labelSetRes.Fingerprint() {
t.Fatalf("Json not equal: got\n%v\nexpected\n%v", string(jsonres), string(jsonOrig))
if labelSet.Fingerprint() != fingerprintRes {
t.Fatalf("Json not equal: got\n%v\nexpected\n%v", string(jsonRes), string(jsonOrig))

}

Expand Down Expand Up @@ -1099,6 +1100,15 @@ func TestMain(m *testing.M) {
func withDB(t testing.TB, DBName string, f func(db *pgxpool.Pool, t testing.TB)) {
testhelpers.WithDB(t, DBName, func(db *pgxpool.Pool, t testing.TB, connectURL string) {
performMigrate(t, DBName, connectURL)

//need to get a new pool after the Migrate to catch any GUC changes made during Migrate
db, err := pgxpool.Connect(context.Background(), connectURL)
if err != nil {
t.Fatal(err)
}
defer func() {
db.Close()
}()
f(db, t)
})
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/pgmodel/migrations/migration_files_generated.go

Large diffs are not rendered by default.

0 comments on commit 67b2fbd

Please sign in to comment.