mirror of
https://github.com/hanzoai/o11y.git
synced 2026-10-15 12:58:33 +00:00
* debrand: signoz/SigNoz/SIGNOZ -> o11y/O11y/O11Y across the tree Rename all SigNoz *branding* to O11y in file contents, file/dir names, package names, env vars, config keys, comments, docs, SDK code, and the ClickHouse schema identifiers the querier reads. Collector dependency: - Repoint github.com/hanzoai/signoz-otel-collector -> github.com/hanzoai/otel-collector and bump v0.144.6 -> v0.144.7 (go.mod + go.sum reconciled via go mod tidy). Internal package paths also debranded upstream: signozschemamigrator -> o11yschemamigrator, signozlogspipelineprocessor -> o11ylogspipelineprocessor. - Fix: v0.144.7 dropped otelconst.DistributedFieldKeysTable from the collector's public constants; pin FieldKeysTable = "distributed_field_keys" locally in pkg/telemetrymetadata/tables.go. Package/dir renames (package decl + all importers): pkg/apiserver/signozapiserver -> o11yapiserver, plus signozalertmanager, signozauthzapi, signozglobal, signozquerier, signozruler, and pkg/signoz -> pkg/o11y. Schema (read plane): signoz_traces/metrics/logs/metadata/analytics/meter and signoz_index_v3/index_v2/error_index_v2/spans (+ distributed_*) -> o11y_*. Data-preserving cutover migration added: deploy/clickhouse/migrations/0001_rename_signoz_to_o11y.sql (metadata-only RENAME DATABASE/TABLE, no drop/recreate). Preserved (attribution / external / wire contracts): - LICENSE + NOTICE verbatim (incl. "software from SigNoz", "Copyright ... SigNoz Inc."). - Upstream github.com/SigNoz/* repo URLs + @SigNoz/* CODEOWNERS teams. - Billing resource-attribute regex "signoz.workspace.*" (external wire contract). go build ./pkg/... ./cmd/... = 0; gofmt clean; renamed+schema pkg tests pass. * o11y: bump collector to v0.144.8 (o11y_* physical schema writer) + lockstep deploy plan Collector v0.144.8's schema-migrator + exporters now CREATE/WRITE the same o11y_* physical databases/tables the querier reads and the RENAME migration (0001_rename_signoz_to_o11y.sql) targets. Cross-checked byte-identical: writer DB set == migration target DB set (6); writer prefixed-table set == migration target table set (8); o11y querier reads and cloud reads are subsets of that set. Zero table-name mismatches between writer, readers, and migration. Collector go.mod unchanged between v0.144.7 and v0.144.8 (identical go.mod hash) — pure source rename, no module-graph change. Adds deploy/clickhouse/DEPLOY_signoz_to_o11y_cutover.md: the lockstep order (collector v0.144.8 -> RENAME migration -> o11y+cloud readers) with a fresh/scratch-ClickHouse pre-flight (create via migrator, emit trace+metric, query back) and rollback. Ships together or telemetry blackholes. go build ./pkg/... ./cmd/community = 0.
219 lines
6.4 KiB
Go
219 lines
6.4 KiB
Go
package querybuilder
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"time"
|
|
|
|
"github.com/hanzoai/o11y/pkg/types/metrictypes"
|
|
qbtypes "github.com/hanzoai/o11y/pkg/types/querybuildertypes/querybuildertypesv5"
|
|
)
|
|
|
|
const (
|
|
NsToSeconds = 1000000000
|
|
BucketAdjustment = 1800 // 30 minutes
|
|
|
|
RecommendedNumberOfPoints = 300
|
|
MaxAllowedNumberOfPoints = 1500
|
|
MaxAllowedSeries = 3000
|
|
)
|
|
|
|
// ToNanoSecs takes epoch and returns it in ns.
|
|
func ToNanoSecs(epoch uint64) uint64 {
|
|
temp := epoch
|
|
count := 0
|
|
if epoch == 0 {
|
|
count = 1
|
|
} else {
|
|
for epoch != 0 {
|
|
epoch /= 10
|
|
count++
|
|
}
|
|
}
|
|
return temp * uint64(math.Pow(10, float64(19-count)))
|
|
}
|
|
|
|
// ToMilliSecs takes an epoch whose resolution is inferred from its magnitude
|
|
// (s/ms/µs/ns) and returns it in milliseconds. A millisecond epoch for the
|
|
// current era has 13 digits (e.g. ~1.7e12 in 2026), so the value is scaled so
|
|
// its digit-width matches: smaller values (seconds) are scaled up, larger ones
|
|
// (micro/nanoseconds) are scaled down. Zero is returned unchanged.
|
|
func ToMilliSecs(epoch uint64) uint64 {
|
|
if epoch == 0 {
|
|
return 0
|
|
}
|
|
temp := epoch
|
|
count := 0
|
|
for epoch != 0 {
|
|
epoch /= 10
|
|
count++
|
|
}
|
|
const msDigits = 13
|
|
if count < msDigits {
|
|
return temp * uint64(math.Pow(10, float64(msDigits-count)))
|
|
}
|
|
return temp / uint64(math.Pow(10, float64(count-msDigits)))
|
|
}
|
|
|
|
// TODO(srikanthccv): should these be rounded to nearest multiple of 60 instead of 5 if step > 60?
|
|
// That would make graph look nice but "nice" but should be less important than the usefulness.
|
|
func RecommendedStepInterval(start, end uint64) uint64 {
|
|
start = ToNanoSecs(start)
|
|
end = ToNanoSecs(end)
|
|
|
|
step := (end - start) / RecommendedNumberOfPoints / 1e9
|
|
|
|
if step < 5 {
|
|
return 5
|
|
}
|
|
|
|
// return the nearest lower multiple of 5
|
|
return step - step%5
|
|
}
|
|
|
|
func MinAllowedStepInterval(start, end uint64) uint64 {
|
|
start = ToNanoSecs(start)
|
|
end = ToNanoSecs(end)
|
|
|
|
step := (end - start) / MaxAllowedNumberOfPoints / 1e9
|
|
|
|
if step < 5 {
|
|
return 5
|
|
}
|
|
|
|
// return the nearest lower multiple of 5
|
|
return step - step%5
|
|
}
|
|
|
|
func RecommendedStepIntervalForMeter(start, end uint64) uint64 {
|
|
start = ToNanoSecs(start)
|
|
end = ToNanoSecs(end)
|
|
|
|
step := (end - start) / RecommendedNumberOfPoints / 1e9
|
|
|
|
// for meter queries the minimum step interval allowed is 1 hour as this is our granularity
|
|
if step < 3600 {
|
|
return 3600
|
|
}
|
|
|
|
// return the nearest lower multiple of 3600 ( 1 hour )
|
|
recommended := step - step%3600
|
|
|
|
// if the time range is greater than 1 month set the step interval to be multiple of 1 day
|
|
if end-start >= uint64(30*24*time.Hour.Nanoseconds()) {
|
|
if recommended < 86400 {
|
|
recommended = 86400
|
|
} else {
|
|
recommended = uint64(math.Round(float64(recommended)/86400)) * 86400
|
|
}
|
|
}
|
|
|
|
return recommended
|
|
}
|
|
|
|
func MinAllowedStepIntervalForMeter(start, end uint64) uint64 {
|
|
start = ToNanoSecs(start)
|
|
end = ToNanoSecs(end)
|
|
|
|
step := (end - start) / RecommendedNumberOfPoints / 1e9
|
|
|
|
// for meter queries the minimum step interval allowed is 1 hour as this is our granularity
|
|
if step < 3600 {
|
|
return 3600
|
|
}
|
|
|
|
// return the nearest lower multiple of 3600 ( 1 hour )
|
|
minAllowed := step - step%3600
|
|
|
|
return minAllowed
|
|
}
|
|
|
|
func RecommendedStepIntervalForMetric(start, end uint64) uint64 {
|
|
start = ToNanoSecs(start)
|
|
end = ToNanoSecs(end)
|
|
|
|
step := (end - start) / RecommendedNumberOfPoints / 1e9
|
|
|
|
// TODO(srikanthccv): make this make use of the reporting frequency and remove the 60
|
|
if step < 60 {
|
|
return 60
|
|
}
|
|
|
|
// return the nearest lower multiple of 60
|
|
recommended := step - step%60
|
|
|
|
// if the time range is greater than 1 day, and less than 1 week set the step interval to be multiple of 5 minutes
|
|
// if the time range is greater than 1 week, set the step interval to be multiple of 30 mins
|
|
if end-start >= uint64(24*time.Hour.Nanoseconds()) && end-start < uint64(7*24*time.Hour.Nanoseconds()) {
|
|
recommended = uint64(math.Round(float64(recommended)/300)) * 300
|
|
} else if end-start >= uint64(7*24*time.Hour.Nanoseconds()) {
|
|
recommended = uint64(math.Round(float64(recommended)/1800)) * 1800
|
|
}
|
|
return recommended
|
|
}
|
|
|
|
func MinAllowedStepIntervalForMetric(start, end uint64) uint64 {
|
|
start = ToNanoSecs(start)
|
|
end = ToNanoSecs(end)
|
|
|
|
step := (end - start) / RecommendedNumberOfPoints / 1e9
|
|
|
|
// TODO(srikanthccv): make this make use of the reporting frequency and remove the 60
|
|
if step < 60 {
|
|
return 60
|
|
}
|
|
|
|
// return the nearest lower multiple of 60
|
|
minAllowed := step - step%60
|
|
|
|
// if the time range is greater than 1 day, and less than 1 week set the step interval to be multiple of 5 minutes
|
|
// if the time range is greater than 1 week, set the step interval to be multiple of 30 mins
|
|
if end-start >= uint64(24*time.Hour.Nanoseconds()) && end-start < uint64(7*24*time.Hour.Nanoseconds()) {
|
|
minAllowed = uint64(math.Round(float64(minAllowed)/300)) * 300
|
|
} else if end-start >= uint64(7*24*time.Hour.Nanoseconds()) {
|
|
minAllowed = uint64(math.Round(float64(minAllowed)/1800)) * 1800
|
|
}
|
|
return minAllowed
|
|
}
|
|
|
|
func AdjustedMetricTimeRange(start, end, step uint64, mq qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]) (uint64, uint64) {
|
|
// align the start to the step interval
|
|
start = start - (start % (step * 1000))
|
|
// if the query is a rate query, we adjust the start time by one more step
|
|
// so that we can calculate the rate for the first data point
|
|
hasRunningDiff := false
|
|
for _, fn := range mq.Functions {
|
|
if fn.Name == qbtypes.FunctionNameRunningDiff {
|
|
hasRunningDiff = true
|
|
break
|
|
}
|
|
}
|
|
if (mq.Aggregations[0].TimeAggregation == metrictypes.TimeAggregationRate || mq.Aggregations[0].TimeAggregation == metrictypes.TimeAggregationIncrease) &&
|
|
mq.Aggregations[0].Temporality != metrictypes.Delta {
|
|
start -= step * 1000
|
|
}
|
|
if hasRunningDiff {
|
|
start -= step * 1000
|
|
}
|
|
// align the end to the nearest minute
|
|
adjustStep := uint64(math.Min(float64(step), 60))
|
|
end = end - (end % (adjustStep * 1000))
|
|
return start, end
|
|
}
|
|
|
|
func AssignReservedVars(vars map[string]any, start, end uint64) {
|
|
start = ToNanoSecs(start)
|
|
end = ToNanoSecs(end)
|
|
|
|
vars["start_timestamp"] = start / 1_000_000_000
|
|
vars["end_timestamp"] = end / 1_000_000_000
|
|
vars["start_timestamp_ms"] = start / 1_000_000
|
|
vars["end_timestamp_ms"] = end / 1_000_000
|
|
vars["O11Y_START_TIME"] = start / 1_000_000
|
|
vars["O11Y_END_TIME"] = end / 1_000_000
|
|
vars["start_timestamp_nano"] = start
|
|
vars["end_timestamp_nano"] = end
|
|
vars["start_datetime"] = fmt.Sprintf("toDateTime(%d)", start/1_000_000_000)
|
|
vars["end_datetime"] = fmt.Sprintf("toDateTime(%d)", end/1_000_000_000)
|
|
}
|