2024-06-17 10:13:18 +00:00
|
|
|
package insertutils
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2024-09-28 19:56:50 +00:00
|
|
|
"math"
|
|
|
|
"strconv"
|
2024-06-17 10:13:18 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logstorage"
|
|
|
|
)
|
|
|
|
|
2024-06-17 22:23:17 +00:00
|
|
|
// ExtractTimestampRFC3339NanoFromFields extracts RFC3339 timestamp in nanoseconds from the field with the name timeField at fields.
|
2024-06-17 10:13:18 +00:00
|
|
|
//
|
|
|
|
// The value for the timeField is set to empty string after returning from the function,
|
|
|
|
// so it could be ignored during data ingestion.
|
|
|
|
//
|
|
|
|
// The current timestamp is returned if fields do not contain a field with timeField name or if the timeField value is empty.
|
2024-06-17 22:23:17 +00:00
|
|
|
func ExtractTimestampRFC3339NanoFromFields(timeField string, fields []logstorage.Field) (int64, error) {
|
2024-06-17 10:13:18 +00:00
|
|
|
for i := range fields {
|
|
|
|
f := &fields[i]
|
|
|
|
if f.Name != timeField {
|
|
|
|
continue
|
|
|
|
}
|
2024-09-28 19:56:50 +00:00
|
|
|
nsecs, err := parseTimestamp(f.Value)
|
|
|
|
if err != nil {
|
|
|
|
return 0, fmt.Errorf("cannot parse timestamp from field %q: %s", timeField, err)
|
2024-06-17 10:13:18 +00:00
|
|
|
}
|
|
|
|
f.Value = ""
|
2024-09-28 19:56:50 +00:00
|
|
|
if nsecs == 0 {
|
|
|
|
nsecs = time.Now().UnixNano()
|
|
|
|
}
|
2024-06-17 10:13:18 +00:00
|
|
|
return nsecs, nil
|
|
|
|
}
|
|
|
|
return time.Now().UnixNano(), nil
|
|
|
|
}
|
2024-09-28 19:56:50 +00:00
|
|
|
|
|
|
|
func parseTimestamp(s string) (int64, error) {
|
|
|
|
if s == "" || s == "0" {
|
|
|
|
return time.Now().UnixNano(), nil
|
|
|
|
}
|
|
|
|
if len(s) <= len("YYYY") || s[len("YYYY")] != '-' {
|
|
|
|
return ParseUnixTimestamp(s)
|
|
|
|
}
|
|
|
|
nsecs, ok := logstorage.TryParseTimestampRFC3339Nano(s)
|
|
|
|
if !ok {
|
|
|
|
return 0, fmt.Errorf("cannot unmarshal rfc3339 timestamp %q", s)
|
|
|
|
}
|
|
|
|
return nsecs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ParseUnixTimestamp parses s as unix timestamp in either seconds or milliseconds and returns the parsed timestamp in nanoseconds.
|
|
|
|
func ParseUnixTimestamp(s string) (int64, error) {
|
|
|
|
n, err := strconv.ParseInt(s, 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return 0, fmt.Errorf("cannot parse unix timestamp from %q: %w", s, err)
|
|
|
|
}
|
|
|
|
if n < (1<<31) && n >= (-1<<31) {
|
|
|
|
// The timestamp is in seconds. Convert it to milliseconds
|
|
|
|
n *= 1e3
|
|
|
|
}
|
|
|
|
if n > int64(math.MaxInt64)/1e6 {
|
|
|
|
return 0, fmt.Errorf("too big timestamp in milliseconds: %d; mustn't exceed %d", n, int64(math.MaxInt64)/1e6)
|
|
|
|
}
|
|
|
|
if n < int64(math.MinInt64)/1e6 {
|
|
|
|
return 0, fmt.Errorf("too small timestamp in milliseconds: %d; must be bigger than %d", n, int64(math.MinInt64)/1e6)
|
|
|
|
}
|
|
|
|
n *= 1e6
|
|
|
|
return n, nil
|
|
|
|
}
|