Skip to content

Commit

Permalink
fix: time macros, trace span durations under 1ms (#721)
Browse files Browse the repository at this point in the history
  • Loading branch information
SpencerTorres authored Feb 21, 2024
1 parent 409f765 commit 727298b
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 73 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## Unreleased

### Features

- Added `$__fromTime_ms` macro that represents the dashboard "from" time in milliseconds using a `DateTime64(3)`
- Added `$__toTime_ms` macro that represents the dashboard "to" time in milliseconds using a `DateTime64(3)`
- Added `$__timeFilter_ms` macro that uses `DateTime64(3)` for millisecond precision time filtering

### Fixes

- Fixed performance issues caused by `$__timeFilter` using a `DateTime64(3)` instead of `DateTime` (#699)
- Fixed trace queries from rounding span durations under 1ms to `0` (#720)

## 4.0.2

### Fixes
Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,13 @@ WHERE $__timeFilter(date_time)

| Macro | Description | Output example |
|----------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------|
| *$__timeFilter(columnName)* | Replaced by a conditional that filters the data (using the provided column) based on the time range of the panel in milliseconds | `time >= toDateTime64(1480001790/1000, 3) AND time <= toDateTime64(1482576232/1000, 3) )` |
| *$__dateFilter(columnName)* | Replaced by a conditional that filters the data (using the provided column) based on the date range of the panel | `date >= '2022-10-21' AND date <= '2022-10-23' )` |
| *$__fromTime* | Replaced by the starting time of the range of the panel casted to `DateTime64(3)` | `toDateTime64(1415792726371/1000, 3)` |
| *$__toTime* | Replaced by the ending time of the range of the panel casted to `DateTime64(3)` | `toDateTime64(1415792726371/1000, 3)` |
| *$__dateFilter(columnName)* | Replaced by a conditional that filters the data (using the provided column) based on the date range of the panel | `date >= toDate('2022-10-21') AND date <= toDate('2022-10-23')` |
| *$__timeFilter(columnName)* | Replaced by a conditional that filters the data (using the provided column) based on the time range of the panel in seconds | `time >= toDateTime(1415792726) AND time <= toDateTime(1447328726)` |
| *$__timeFilter_ms(columnName)* | Replaced by a conditional that filters the data (using the provided column) based on the time range of the panel in milliseconds | `time >= fromUnixTimestamp64Milli(1415792726123) AND time <= fromUnixTimestamp64Milli(1447328726456)` |
| *$__fromTime* | Replaced by the starting time of the range of the panel casted to `DateTime` | `toDateTime(1415792726)` |
| *$__toTime* | Replaced by the ending time of the range of the panel casted to `DateTime` | `toDateTime(1447328726)` |
| *$__fromTime_ms* | Replaced by the starting time of the range of the panel casted to `DateTime64(3)` | `fromUnixTimestamp64Milli(1415792726123)` |
| *$__toTime_ms* | Replaced by the ending time of the range of the panel casted to `DateTime64(3)` | `fromUnixTimestamp64Milli(1447328726456)` |
| *$__interval_s* | Replaced by the interval in seconds | `20` |
| *$__timeInterval(columnName)* | Replaced by a function calculating the interval based on window size in seconds, useful when grouping | `toStartOfInterval(toDateTime(column), INTERVAL 20 second)` |
| *$__timeInterval_ms(columnName)* | Replaced by a function calculating the interval based on window size in milliseconds, useful when grouping | `toStartOfInterval(toDateTime64(column, 3), INTERVAL 20 millisecond)` |
Expand Down
1 change: 1 addition & 0 deletions cspell.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
],
"words": [
"concats",
"Milli",
"traceid",
"aggregatable",
"aheads",
Expand Down
85 changes: 52 additions & 33 deletions pkg/macros/macros.go
Original file line number Diff line number Diff line change
@@ -1,42 +1,47 @@
package macros

import (
"errors"
"fmt"
"math"
"strings"
"time"

"github.com/grafana/sqlds/v2"
)

var (
ErrorNoArgumentsToMacro = errors.New("expected minimum of 1 argument. But no argument found")
ErrorInsufficientArgumentsToMacro = errors.New("expected number of arguments not matching")
)

type timeQueryType string
// Converts a time.Time to a Date
func timeToDate(t time.Time) string {
return fmt.Sprintf("toDate('%s')", t.Format("2006-01-02"))
}

const (
timeQueryTypeFrom timeQueryType = "from"
timeQueryTypeTo timeQueryType = "to"
)
// Converts a time.Time to a UTC DateTime with seconds precision
func timeToDateTime(t time.Time) string {
return fmt.Sprintf("toDateTime(%d)", t.Unix())
}

func newTimeFilter(queryType timeQueryType, query *sqlds.Query) (string, error) {
date := query.TimeRange.From
if queryType == timeQueryTypeTo {
date = query.TimeRange.To
}
return fmt.Sprintf("toDateTime64(%d/1000, 3)", date.UnixMilli()), nil
// Converts a time.Time to a UTC DateTime64 with milliseconds precision
func timeToDateTime64(t time.Time) string {
return fmt.Sprintf("fromUnixTimestamp64Milli(%d)", t.UnixMilli())
}

// FromTimeFilter return time filter query based on grafana's timepicker's from time
// FromTimeFilter returns a time filter expression based on grafana's timepicker's "from" time in seconds
func FromTimeFilter(query *sqlds.Query, args []string) (string, error) {
return newTimeFilter(timeQueryTypeFrom, query)
return timeToDateTime(query.TimeRange.From), nil
}

// ToTimeFilter return time filter query based on grafana's timepicker's to time
// ToTimeFilter returns a time filter expression based on grafana's timepicker's "to" time in seconds
func ToTimeFilter(query *sqlds.Query, args []string) (string, error) {
return newTimeFilter(timeQueryTypeTo, query)
return timeToDateTime(query.TimeRange.To), nil
}

// FromTimeFilterMs returns a time filter expression based on grafana's timepicker's "from" time in milliseconds
func FromTimeFilterMs(query *sqlds.Query, args []string) (string, error) {
return timeToDateTime64(query.TimeRange.From), nil
}

// ToTimeFilterMs returns a time filter expression based on grafana's timepicker's "to" time in milliseconds
func ToTimeFilterMs(query *sqlds.Query, args []string) (string, error) {
return timeToDateTime64(query.TimeRange.To), nil
}

func TimeFilter(query *sqlds.Query, args []string) (string, error) {
Expand All @@ -46,38 +51,38 @@ func TimeFilter(query *sqlds.Query, args []string) (string, error) {

var (
column = args[0]
from = query.TimeRange.From.UTC().UnixMilli()
to = query.TimeRange.To.UTC().UnixMilli()
from = query.TimeRange.From
to = query.TimeRange.To
)

return fmt.Sprintf("%s >= toDateTime64(%d/1000, 3) AND %s <= toDateTime64(%d/1000, 3)", column, from, column, to), nil
return fmt.Sprintf("%s >= %s AND %s <= %s", column, timeToDateTime(from), column, timeToDateTime(to)), nil
}

func DateFilter(query *sqlds.Query, args []string) (string, error) {
func TimeFilterMs(query *sqlds.Query, args []string) (string, error) {
if len(args) != 1 {
return "", fmt.Errorf("%w: expected 1 argument, received %d", sqlds.ErrorBadArgumentCount, len(args))
}

var (
column = args[0]
from = query.TimeRange.From.Format("2006-01-02")
to = query.TimeRange.To.Format("2006-01-02")
from = query.TimeRange.From
to = query.TimeRange.To
)

return fmt.Sprintf("%s >= '%s' AND %s <= '%s'", column, from, column, to), nil
return fmt.Sprintf("%s >= %s AND %s <= %s", column, timeToDateTime64(from), column, timeToDateTime64(to)), nil
}

func TimeFilterMs(query *sqlds.Query, args []string) (string, error) {
func DateFilter(query *sqlds.Query, args []string) (string, error) {
if len(args) != 1 {
return "", fmt.Errorf("%w: expected 1 argument, received %d", sqlds.ErrorBadArgumentCount, len(args))
}

var (
column = args[0]
from = query.TimeRange.From.UTC().UnixMilli()
to = query.TimeRange.To.UTC().UnixMilli()
from = query.TimeRange.From
to = query.TimeRange.To
)

return fmt.Sprintf("%s >= '%d' AND %s <= '%d'", column, from, column, to), nil
return fmt.Sprintf("%s >= %s AND %s <= %s", column, timeToDate(from), column, timeToDate(to)), nil
}

func TimeInterval(query *sqlds.Query, args []string) (string, error) {
Expand Down Expand Up @@ -124,3 +129,17 @@ func IsValidComparisonPredicates(comparison_predicates string) bool {
}
return false
}

// Macros is a map of all macro functions
var Macros = map[string]sqlds.MacroFunc{
"fromTime": FromTimeFilter,
"toTime": ToTimeFilter,
"fromTime_ms": FromTimeFilterMs,
"toTime_ms": ToTimeFilterMs,
"timeFilter": TimeFilter,
"timeFilter_ms": TimeFilterMs,
"dateFilter": DateFilter,
"timeInterval": TimeInterval,
"timeInterval_ms": TimeIntervalMs,
"interval_s": IntervalSeconds,
}
Loading

0 comments on commit 727298b

Please sign in to comment.