mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2026-08-07 16:27:08 +03:00
Compare commits
1 Commits
rewrite-pa
...
docs/remov
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f613a6f1a4 |
@@ -1,3 +1,11 @@
|
||||
---
|
||||
build:
|
||||
list: never
|
||||
publishResources: false
|
||||
render: never
|
||||
sitemap:
|
||||
disable: true
|
||||
---
|
||||
VictoriaMetrics Observability Stack integrates with AI assistants through [MCP servers](https://docs.victoriametrics.com/ai-tools/#mcp-servers)
|
||||
and [agent skills](https://docs.victoriametrics.com/ai-tools/#agent-skills).
|
||||
The integrations allow AI agents and automation tools to query Metrics, Logs, and Traces, analyze telemetry data,
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
---
|
||||
build:
|
||||
list: never
|
||||
publishResources: false
|
||||
render: never
|
||||
sitemap:
|
||||
disable: true
|
||||
---
|
||||
Several VictoriaMetrics components can connect to cloud storage to read or write object data.
|
||||
|
||||
The following table shows the supported types of storage for each component:
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
---
|
||||
build:
|
||||
list: never
|
||||
publishResources: false
|
||||
render: never
|
||||
sitemap:
|
||||
disable: true
|
||||
---
|
||||
Using [Grafana](https://grafana.com/) with [vmauth](https://docs.victoriametrics.com/victoriametrics/vmauth/) is an effective way to provide [multi-tenant](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#multitenancy) access to your metrics, logs, and traces.
|
||||
vmauth provides a way to authenticate users using [JWT tokens](https://en.wikipedia.org/wiki/JSON_Web_Token) {{% available_from "v1.138.0" %}} issued by an external identity provider.
|
||||
Those tokens can include information about the user and their tenant, which vmauth can use to restrict access so users only see metrics in their own tenant.
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
---
|
||||
build:
|
||||
list: never
|
||||
publishResources: false
|
||||
render: never
|
||||
sitemap:
|
||||
disable: true
|
||||
---
|
||||
VictoriaMetrics software provides native [OpenTelemetry](https://opentelemetry.io/) ingestion across **metrics**, **logs**, and **traces** via dedicated components.
|
||||
This allows running OpenTelemetry-based observability pipeline with VictoriaMetrics software as your backend.
|
||||
|
||||
@@ -88,4 +96,4 @@ Depending on the Grafana datasource plugin there could be multiple correlations
|
||||
1. Trace to metrics, metric to logs, metric to traces - see [correlations via VictoriaMetrics plugin](https://docs.victoriametrics.com/victoriametrics/integrations/grafana/datasource/#correlations).
|
||||
1. Metrics to logs or traces correlations are possible via Prometheus datasource as well.
|
||||
1. Plugins Tempo, Jaeger, and Zipkin can correlate with logs or metrics using [Trace to logs](https://grafana.com/docs/grafana/latest/explore/trace-integration/#trace-to-logs)
|
||||
and [Trace to metrics](https://grafana.com/docs/grafana/latest/visualizations/explore/trace-integration/#trace-to-metrics) feature.
|
||||
and [Trace to metrics](https://grafana.com/docs/grafana/latest/visualizations/explore/trace-integration/#trace-to-metrics) feature.
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
---
|
||||
build:
|
||||
list: never
|
||||
publishResources: false
|
||||
render: never
|
||||
sitemap:
|
||||
disable: true
|
||||
---
|
||||
VictoriaMetrics offers public playgrounds where you can try the full observability stack online.
|
||||
|
||||
Some playgrounds are based on the [OpenTelemetry Astronomy Shop demo](https://github.com/open-telemetry/opentelemetry-demo), a sample microservices application that generates realistic metrics, logs, and traces. Other playgrounds use benchmark workloads such as [prometheus-benchmark](https://github.com/VictoriaMetrics/prometheus-benchmark) to demonstrate ingestion and query performance for Prometheus-compatible systems.
|
||||
@@ -158,4 +166,4 @@ Iximiuz Labs provides various [learning-by-doing resources for VictoriaMetrics](
|
||||
- [VictoriaMetrics cluster](https://labs.iximiuz.com/playgrounds/victoriametrics-cluster)
|
||||
- [VictoriaMetrics on Kubernetes](https://labs.iximiuz.com/playgrounds/victoriametrics-kubernetes)
|
||||
|
||||
Iximiuz Labs requires a [free account](https://labs.iximiuz.com/signup) to access the materials.
|
||||
Iximiuz Labs requires a [free account](https://labs.iximiuz.com/signup) to access the materials.
|
||||
|
||||
@@ -142,67 +142,40 @@ func subInt64NoOverflow(a, b int64) int64 {
|
||||
// - Fractional. For example, 1234567890.123
|
||||
// - Scientific. For example, 1.23456789e9
|
||||
func TryParseUnixTimestamp(s string) (int64, bool) {
|
||||
s, exp, ok := parseExponent(s)
|
||||
if expIdx := getExpIndex(s); expIdx >= 0 {
|
||||
// The timestamp is a scientific number such as 1.234e5
|
||||
decimalExp, ok := tryParseInt64(s[expIdx+1:])
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
n, ok := tryParseScientificUnixTimestamp(s[:expIdx], decimalExp)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
return n, true
|
||||
}
|
||||
|
||||
dotIdx := strings.IndexByte(s, '.')
|
||||
if dotIdx < 0 {
|
||||
// The timestamp is integer.
|
||||
n, ok := tryParseInt64(s)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
return getUnixTimestampNanoseconds(n), true
|
||||
}
|
||||
|
||||
// The timestamp is fractional.
|
||||
intStr := s[:dotIdx]
|
||||
fracStr := s[dotIdx+1:]
|
||||
n, ok := tryParseFractionalUnixTimestamp(intStr, fracStr)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
whole, frac, fracExp, ok := parseFraction(s)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Move decimal point `exp` positions to the right.
|
||||
if whole, ok = scale10xNoOverflow(whole, exp); !ok {
|
||||
return 0, false
|
||||
}
|
||||
if exp >= fracExp {
|
||||
if frac, ok = scale10xNoOverflow(frac, exp-fracExp); !ok {
|
||||
return 0, false
|
||||
}
|
||||
fracExp = 0
|
||||
} else {
|
||||
if whole, ok = addNoOverflow(whole, firstDigits(frac, fracExp-exp)); !ok {
|
||||
return 0, false
|
||||
}
|
||||
frac = lastDigits(frac, fracExp-exp)
|
||||
fracExp -= exp
|
||||
}
|
||||
|
||||
// Move decimal point `tsExp` positions to the right.
|
||||
tsExp := getUnixTimestampExponent(whole)
|
||||
if whole, ok = scale10xNoOverflow(whole, tsExp); !ok {
|
||||
return 0, false
|
||||
}
|
||||
if tsExp >= fracExp {
|
||||
if frac, ok = scale10xNoOverflow(frac, tsExp-fracExp); !ok {
|
||||
return 0, false
|
||||
}
|
||||
} else {
|
||||
frac = firstDigits(frac, fracExp-tsExp)
|
||||
}
|
||||
|
||||
return addNoOverflow(whole, frac)
|
||||
return n, true
|
||||
}
|
||||
|
||||
func parseExponent(s string) (string, int, bool) {
|
||||
i := getExponentIndex(s)
|
||||
if i == -1 {
|
||||
return s, 0, true
|
||||
}
|
||||
|
||||
exp, ok := tryParseInt64(s[i+1:])
|
||||
if !ok {
|
||||
return "", 0, false
|
||||
}
|
||||
|
||||
if exp < 0 || maxExponent < exp {
|
||||
return "", 0, false
|
||||
}
|
||||
|
||||
return s[:i], int(exp), true
|
||||
}
|
||||
|
||||
func getExponentIndex(s string) int {
|
||||
func getExpIndex(s string) int {
|
||||
if n := strings.IndexByte(s, 'e'); n >= 0 {
|
||||
return n
|
||||
}
|
||||
@@ -212,111 +185,151 @@ func getExponentIndex(s string) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
// TODO: check fraction contains only digits (add test)
|
||||
// TODO: truncate to max 18 digits first, then remove trailing zeroes
|
||||
func parseFraction(s string) (whole int64, frac int64, fracExp int, ok bool) {
|
||||
if len(s) == 0 || s == "." {
|
||||
return 0, 0, 0, false
|
||||
func tryParseScientificUnixTimestamp(s string, decimalExp int64) (int64, bool) {
|
||||
if decimalExp < 0 {
|
||||
// Negative exponents on a fractional mantissa are intentionally not
|
||||
// supported. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11268
|
||||
return 0, false
|
||||
}
|
||||
var negative bool
|
||||
if strings.HasPrefix(s, "-") {
|
||||
s = s[1:]
|
||||
negative = true
|
||||
dotIdx := strings.IndexByte(s, '.')
|
||||
if dotIdx < 0 {
|
||||
n, ok := tryParseInt64(s)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
n, ok = multiplyByDecimalExp(n, decimalExp)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
return getUnixTimestampNanoseconds(n), true
|
||||
}
|
||||
|
||||
var wholeStr, fracStr string
|
||||
i := strings.IndexByte(s, '.')
|
||||
if i == -1 {
|
||||
wholeStr = s
|
||||
} else if i == 0 {
|
||||
fracStr = s[i+1:]
|
||||
} else if i == len(s)-1 {
|
||||
wholeStr = s[:i]
|
||||
intStr := s[:dotIdx]
|
||||
fracStr := s[dotIdx+1:]
|
||||
if decimalExp >= int64(len(fracStr)) {
|
||||
// The exponent shifts the decimal point past every fractional digit.
|
||||
n, ok := tryParseDecimalMantissaAsInt(intStr, fracStr)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
decimalExp -= int64(len(fracStr))
|
||||
n, ok = multiplyByDecimalExp(n, decimalExp)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
return getUnixTimestampNanoseconds(n), true
|
||||
}
|
||||
|
||||
// The exponent leaves fractional digits, e.g. 1.784144612388E9 == 1784144612.388
|
||||
if decimalExp >= int64(len(decimalMultipliers)) {
|
||||
return 0, false
|
||||
}
|
||||
decimalExpInt := int(decimalExp)
|
||||
intStr = s[:dotIdx] + fracStr[:decimalExpInt]
|
||||
fracStr = fracStr[decimalExpInt:]
|
||||
return tryParseFractionalUnixTimestamp(intStr, fracStr)
|
||||
}
|
||||
|
||||
func tryParseDecimalMantissaAsInt(intStr, fracStr string) (int64, bool) {
|
||||
n, ok := tryParseInt64(intStr)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
decimalExp := int64(len(fracStr))
|
||||
num, ok := multiplyByDecimalExp(n, decimalExp)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
frac, ok := tryParseInt64(fracStr)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
if num >= 0 {
|
||||
if num > math.MaxInt64-frac {
|
||||
return 0, false
|
||||
}
|
||||
num += frac
|
||||
} else {
|
||||
wholeStr = s[:i]
|
||||
fracStr = s[i+1:]
|
||||
}
|
||||
|
||||
fracStr = strings.TrimRight(fracStr, "0")
|
||||
fracExp = maxExponent
|
||||
if len(fracStr) < fracExp {
|
||||
fracExp = len(fracStr)
|
||||
}
|
||||
fracStr = fracStr[0:fracExp]
|
||||
|
||||
if len(wholeStr) > 0 {
|
||||
whole, ok = tryParseInt64(wholeStr)
|
||||
if !ok {
|
||||
return 0, 0, 0, false
|
||||
if num < math.MinInt64+frac {
|
||||
return 0, false
|
||||
}
|
||||
num -= frac
|
||||
}
|
||||
if len(fracStr) > 0 {
|
||||
frac, ok = tryParseInt64(fracStr)
|
||||
if !ok {
|
||||
return 0, 0, 0, false
|
||||
|
||||
return num, true
|
||||
}
|
||||
|
||||
func tryParseFractionalUnixTimestamp(intStr, fracStr string) (int64, bool) {
|
||||
n, ok := tryParseInt64(intStr)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
isNegative := n < 0 || n == 0 && strings.HasPrefix(intStr, "-")
|
||||
|
||||
multiplier, maxFracDigits := getUnixTimestampMultiplier(n)
|
||||
// Truncate the fractional digits to valid length according to the unit precision.
|
||||
if len(fracStr) > maxFracDigits {
|
||||
// 1.123456789XXX is invalid.
|
||||
tail := fracStr[maxFracDigits:]
|
||||
for i := 0; i < len(tail); i++ {
|
||||
if tail[i] < '0' || tail[i] > '9' {
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
fracStr = fracStr[:maxFracDigits]
|
||||
}
|
||||
if negative {
|
||||
whole = -whole
|
||||
frac = -frac
|
||||
if len(fracStr) == 0 {
|
||||
return n * multiplier, true
|
||||
}
|
||||
return whole, frac, fracExp, true
|
||||
}
|
||||
|
||||
func tryParseInt64(s string) (int64, bool) {
|
||||
n, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
frac, ok := tryParseInt64(fracStr)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
return n, true
|
||||
}
|
||||
|
||||
func addNoOverflow(a, b int64) (int64, bool) {
|
||||
if a > 0 && b > 0 && a > math.MaxInt64-b {
|
||||
decimalExp := len(fracStr)
|
||||
if decimalExp >= len(decimalMultipliers) {
|
||||
return 0, false
|
||||
}
|
||||
if a < 0 && b < 0 && a < math.MinInt64-b {
|
||||
n *= multiplier
|
||||
scale := decimalMultipliers[decimalExp]
|
||||
frac *= multiplier / scale
|
||||
|
||||
if isNegative {
|
||||
if n < math.MinInt64+frac {
|
||||
return 0, false
|
||||
}
|
||||
return n - frac, true
|
||||
}
|
||||
if n > math.MaxInt64-frac {
|
||||
return 0, false
|
||||
}
|
||||
return a + b, true
|
||||
return n + frac, true
|
||||
}
|
||||
|
||||
func firstDigits(i int64, n int) int64 {
|
||||
return i / decimalMultipliers[n]
|
||||
}
|
||||
func multiplyByDecimalExp(n int64, decimalExp int64) (int64, bool) {
|
||||
if decimalExp < 0 {
|
||||
return 0, false
|
||||
}
|
||||
if decimalExp >= int64(len(decimalMultipliers)) {
|
||||
return 0, false
|
||||
}
|
||||
if decimalExp == 0 {
|
||||
return n, true
|
||||
}
|
||||
|
||||
func lastDigits(i int64, n int) int64 {
|
||||
return i % decimalMultipliers[n]
|
||||
}
|
||||
m := decimalMultipliers[decimalExp]
|
||||
|
||||
func scale10xNoOverflow(n int64, exp int) (int64, bool) {
|
||||
m := decimalMultipliers[exp]
|
||||
if n >= 0 && n > math.MaxInt64/m || n < 0 && n < math.MinInt64/m {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return n * m, true
|
||||
}
|
||||
|
||||
const maxExponent = 18
|
||||
|
||||
var decimalMultipliers = [...]int64{1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18}
|
||||
|
||||
func getUnixTimestampExponent(n int64) int {
|
||||
if n <= maxValidSecond && n >= minValidSecond {
|
||||
// The timestamp is in seconds.
|
||||
return 9
|
||||
}
|
||||
if n <= maxValidMilli && n >= minValidMilli {
|
||||
// The timestamp is in milliseconds.
|
||||
return 6
|
||||
}
|
||||
if n <= maxValidMicro && n >= minValidMicro {
|
||||
// The timestamp is in microseconds.
|
||||
return 3
|
||||
}
|
||||
// The timestamp is in nanoseconds
|
||||
return 0
|
||||
}
|
||||
var decimalMultipliers = [...]int64{0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18}
|
||||
|
||||
const (
|
||||
maxValidSecond = math.MaxInt64 / 1_000_000_000
|
||||
@@ -326,3 +339,33 @@ const (
|
||||
minValidMilli = math.MinInt64 / 1_000_000
|
||||
minValidMicro = math.MinInt64 / 1_000
|
||||
)
|
||||
|
||||
func getUnixTimestampNanoseconds(n int64) int64 {
|
||||
multiplier, _ := getUnixTimestampMultiplier(n)
|
||||
return n * multiplier
|
||||
}
|
||||
|
||||
func getUnixTimestampMultiplier(n int64) (int64, int) {
|
||||
if n <= maxValidSecond && n >= minValidSecond {
|
||||
// The timestamp is in seconds.
|
||||
return 1e9, 9
|
||||
}
|
||||
if n <= maxValidMilli && n >= minValidMilli {
|
||||
// The timestamp is in milliseconds.
|
||||
return 1e6, 6
|
||||
}
|
||||
if n <= maxValidMicro && n >= minValidMicro {
|
||||
// The timestamp is in microseconds.
|
||||
return 1e3, 3
|
||||
}
|
||||
// The timestamp is in nanoseconds
|
||||
return 1, 0
|
||||
}
|
||||
|
||||
func tryParseInt64(s string) (int64, bool) {
|
||||
n, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
return n, true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user