diff --git a/internal/type_conversions.go b/internal/type_conversions.go index 464e464c1..204649ed2 100644 --- a/internal/type_conversions.go +++ b/internal/type_conversions.go @@ -2,9 +2,655 @@ package internal import ( "fmt" + "math" "strconv" ) +var ErrOutOfRange = strconv.ErrRange + +func ToFloat64(value interface{}) (float64, error) { + switch v := value.(type) { + case string: + return strconv.ParseFloat(v, 64) + case []byte: + return strconv.ParseFloat(string(v), 64) + case fmt.Stringer: + return strconv.ParseFloat(v.String(), 64) + case bool: + if v { + return 1, nil + } + return 0, nil + case int: + return float64(v), nil + case int8: + return float64(v), nil + case int16: + return float64(v), nil + case int32: + return float64(v), nil + case int64: + return float64(v), nil + case uint: + return float64(v), nil + case uint8: + return float64(v), nil + case uint16: + return float64(v), nil + case uint32: + return float64(v), nil + case uint64: + return float64(v), nil + case float32: + return float64(v), nil + case float64: + return v, nil + case nil: + return 0, nil + } + return 0, fmt.Errorf("type \"%T\" unsupported", value) +} + +func ToFloat32(value interface{}) (float32, error) { + switch v := value.(type) { + case string: + x, err := strconv.ParseFloat(v, 32) + return float32(x), err + case []byte: + x, err := strconv.ParseFloat(string(v), 32) + return float32(x), err + case fmt.Stringer: + x, err := strconv.ParseFloat(v.String(), 32) + return float32(x), err + case bool: + if v { + return 1, nil + } + return 0, nil + case int: + return float32(v), nil + case int8: + return float32(v), nil + case int16: + return float32(v), nil + case int32: + return float32(v), nil + case int64: + return float32(v), nil + case uint: + return float32(v), nil + case uint8: + return float32(v), nil + case uint16: + return float32(v), nil + case uint32: + return float32(v), nil + case uint64: + return float32(v), nil + case float32: + return v, nil + case float64: + if v < -math.MaxFloat32 || v > math.MaxFloat32 { + return float32(v), ErrOutOfRange + } + return float32(v), nil + case nil: + return 0, nil + } + return 0, fmt.Errorf("type \"%T\" unsupported", value) +} + +func ToUint64(value interface{}) (uint64, error) { + switch v := value.(type) { + case string: + return strconv.ParseUint(v, 10, 64) + case []byte: + return strconv.ParseUint(string(v), 10, 64) + case fmt.Stringer: + return strconv.ParseUint(v.String(), 10, 64) + case bool: + if v { + return 1, nil + } + return 0, nil + case int: + if v < 0 { + return uint64(v), ErrOutOfRange + } + return uint64(v), nil + case int8: + if v < 0 { + return uint64(v), ErrOutOfRange + } + return uint64(v), nil + case int16: + if v < 0 { + return uint64(v), ErrOutOfRange + } + return uint64(v), nil + case int32: + if v < 0 { + return uint64(v), ErrOutOfRange + } + return uint64(v), nil + case int64: + if v < 0 { + return uint64(v), ErrOutOfRange + } + return uint64(v), nil + case uint: + return uint64(v), nil + case uint8: + return uint64(v), nil + case uint16: + return uint64(v), nil + case uint32: + return uint64(v), nil + case uint64: + return v, nil + case float32: + if v < 0 || v > math.MaxUint64 { + return uint64(v), ErrOutOfRange + } + return uint64(v), nil + case float64: + if v < 0 || v > math.MaxUint64 { + return uint64(v), ErrOutOfRange + } + return uint64(v), nil + case nil: + return 0, nil + } + return 0, fmt.Errorf("type \"%T\" unsupported", value) +} + +func ToUint32(value interface{}) (uint32, error) { + switch v := value.(type) { + case string: + x, err := strconv.ParseUint(v, 10, 32) + return uint32(x), err + case []byte: + x, err := strconv.ParseUint(string(v), 10, 32) + return uint32(x), err + case fmt.Stringer: + x, err := strconv.ParseUint(v.String(), 10, 32) + return uint32(x), err + case bool: + if v { + return 1, nil + } + return 0, nil + case int: + if v < 0 || uint64(v) > math.MaxUint32 { + return uint32(v), ErrOutOfRange + } + return uint32(v), nil + case int8: + if v < 0 { + return uint32(v), ErrOutOfRange + } + return uint32(v), nil + case int16: + if v < 0 { + return uint32(v), ErrOutOfRange + } + return uint32(v), nil + case int32: + if v < 0 { + return uint32(v), ErrOutOfRange + } + return uint32(v), nil + case int64: + if v < 0 || v > math.MaxUint32 { + return uint32(v), ErrOutOfRange + } + return uint32(v), nil + case uint: + return uint32(v), nil + case uint8: + return uint32(v), nil + case uint16: + return uint32(v), nil + case uint32: + return v, nil + case uint64: + if v > math.MaxUint32 { + return uint32(v), ErrOutOfRange + } + return uint32(v), nil + case float32: + if v < 0 || v > math.MaxUint32 { + return uint32(v), ErrOutOfRange + } + return uint32(v), nil + case float64: + if v < 0 || v > math.MaxUint32 { + return uint32(v), ErrOutOfRange + } + return uint32(v), nil + case nil: + return 0, nil + } + return 0, fmt.Errorf("type \"%T\" unsupported", value) +} + +func ToUint16(value interface{}) (uint16, error) { + switch v := value.(type) { + case string: + x, err := strconv.ParseUint(v, 10, 32) + return uint16(x), err + case []byte: + x, err := strconv.ParseUint(string(v), 10, 32) + return uint16(x), err + case fmt.Stringer: + x, err := strconv.ParseUint(v.String(), 10, 32) + return uint16(x), err + case bool: + if v { + return 1, nil + } + return 0, nil + case int: + if v < 0 || v > math.MaxUint16 { + return uint16(v), ErrOutOfRange + } + return uint16(v), nil + case int8: + if v < 0 { + return uint16(v), ErrOutOfRange + } + return uint16(v), nil + case int16: + if v < 0 { + return uint16(v), ErrOutOfRange + } + return uint16(v), nil + case int32: + if v < 0 || v > math.MaxUint16 { + return uint16(v), ErrOutOfRange + } + return uint16(v), nil + case int64: + if v < 0 || v > math.MaxUint16 { + return uint16(v), ErrOutOfRange + } + return uint16(v), nil + case uint: + return uint16(v), nil + case uint8: + return uint16(v), nil + case uint16: + return v, nil + case uint32: + if v > math.MaxUint16 { + return uint16(v), ErrOutOfRange + } + return uint16(v), nil + case uint64: + if v > math.MaxUint16 { + return uint16(v), ErrOutOfRange + } + return uint16(v), nil + case float32: + if v < 0 || v > math.MaxUint16 { + return uint16(v), ErrOutOfRange + } + return uint16(v), nil + case float64: + if v < 0 || v > math.MaxUint16 { + return uint16(v), ErrOutOfRange + } + return uint16(v), nil + case nil: + return 0, nil + } + return 0, fmt.Errorf("type \"%T\" unsupported", value) +} + +func ToUint8(value interface{}) (uint8, error) { + switch v := value.(type) { + case string: + x, err := strconv.ParseUint(v, 10, 32) + return uint8(x), err + case []byte: + x, err := strconv.ParseUint(string(v), 10, 32) + return uint8(x), err + case fmt.Stringer: + x, err := strconv.ParseUint(v.String(), 10, 32) + return uint8(x), err + case bool: + if v { + return 1, nil + } + return 0, nil + case int: + if v < 0 || v > math.MaxUint8 { + return uint8(v), ErrOutOfRange + } + return uint8(v), nil + case int8: + if v < 0 { + return uint8(v), ErrOutOfRange + } + return uint8(v), nil + case int16: + if v < 0 || v > math.MaxUint8 { + return uint8(v), ErrOutOfRange + } + return uint8(v), nil + case int32: + if v < 0 || v > math.MaxUint8 { + return uint8(v), ErrOutOfRange + } + return uint8(v), nil + case int64: + if v < 0 || v > math.MaxUint8 { + return uint8(v), ErrOutOfRange + } + return uint8(v), nil + case uint: + return uint8(v), nil + case uint8: + return v, nil + case uint16: + if v > math.MaxUint8 { + return uint8(v), ErrOutOfRange + } + return uint8(v), nil + case uint32: + if v > math.MaxUint8 { + return uint8(v), ErrOutOfRange + } + return uint8(v), nil + case uint64: + if v > math.MaxUint8 { + return uint8(v), ErrOutOfRange + } + return uint8(v), nil + case float32: + if v < 0 || v > math.MaxUint8 { + return uint8(v), ErrOutOfRange + } + return uint8(v), nil + case float64: + if v < 0 || v > math.MaxUint8 { + return uint8(v), ErrOutOfRange + } + return uint8(v), nil + case nil: + return 0, nil + } + return 0, fmt.Errorf("type \"%T\" unsupported", value) +} + +func ToInt64(value interface{}) (int64, error) { + switch v := value.(type) { + case string: + return strconv.ParseInt(v, 10, 64) + case []byte: + return strconv.ParseInt(string(v), 10, 64) + case fmt.Stringer: + return strconv.ParseInt(v.String(), 10, 64) + case bool: + if v { + return 1, nil + } + return 0, nil + case int: + return int64(v), nil + case int8: + return int64(v), nil + case int16: + return int64(v), nil + case int32: + return int64(v), nil + case int64: + return v, nil + case uint: + if uint64(v) > math.MaxInt64 { + return int64(v), ErrOutOfRange + } + return int64(v), nil + case uint8: + return int64(v), nil + case uint16: + return int64(v), nil + case uint32: + return int64(v), nil + case uint64: + if v > math.MaxInt64 { + return int64(v), ErrOutOfRange + } + return int64(v), nil + case float32: + if v < math.MinInt64 || v > math.MaxInt64 { + return int64(v), ErrOutOfRange + } + return int64(v), nil + case float64: + if v < math.MinInt64 || v > math.MaxInt64 { + return int64(v), ErrOutOfRange + } + return int64(v), nil + case nil: + return 0, nil + } + return 0, fmt.Errorf("type \"%T\" unsupported", value) +} + +func ToInt32(value interface{}) (int32, error) { + switch v := value.(type) { + case string: + x, err := strconv.ParseInt(v, 10, 32) + return int32(x), err + case []byte: + x, err := strconv.ParseInt(string(v), 10, 32) + return int32(x), err + case fmt.Stringer: + x, err := strconv.ParseInt(v.String(), 10, 32) + return int32(x), err + case bool: + if v { + return 1, nil + } + return 0, nil + case int: + if int64(v) < math.MinInt32 || int64(v) > math.MaxInt32 { + return int32(v), ErrOutOfRange + } + return int32(v), nil + case int8: + return int32(v), nil + case int16: + return int32(v), nil + case int32: + return v, nil + case int64: + if v < math.MinInt32 || v > math.MaxInt32 { + return int32(v), ErrOutOfRange + } + return int32(v), nil + case uint: + if v > math.MaxInt32 { + return int32(v), ErrOutOfRange + } + return int32(v), nil + case uint8: + return int32(v), nil + case uint16: + return int32(v), nil + case uint32: + if v > math.MaxInt32 { + return int32(v), ErrOutOfRange + } + return int32(v), nil + case uint64: + if v > math.MaxInt32 { + return int32(v), ErrOutOfRange + } + return int32(v), nil + case float32: + if v < math.MinInt32 || v > math.MaxInt32 { + return int32(v), ErrOutOfRange + } + return int32(v), nil + case float64: + if v < math.MinInt32 || v > math.MaxInt32 { + return int32(v), ErrOutOfRange + } + return int32(v), nil + case nil: + return 0, nil + } + return 0, fmt.Errorf("type \"%T\" unsupported", value) +} + +func ToInt16(value interface{}) (int16, error) { + switch v := value.(type) { + case string: + x, err := strconv.ParseInt(v, 10, 32) + return int16(x), err + case []byte: + x, err := strconv.ParseInt(string(v), 10, 32) + return int16(x), err + case fmt.Stringer: + x, err := strconv.ParseInt(v.String(), 10, 32) + return int16(x), err + case bool: + if v { + return 1, nil + } + return 0, nil + case int: + return int16(v), nil + case int8: + return int16(v), nil + case int16: + return v, nil + case int32: + if v < math.MinInt16 || v > math.MaxInt16 { + return int16(v), ErrOutOfRange + } + return int16(v), nil + case int64: + if v < math.MinInt16 || v > math.MaxInt16 { + return int16(v), ErrOutOfRange + } + return int16(v), nil + case uint: + if v > math.MaxInt16 { + return int16(v), ErrOutOfRange + } + return int16(v), nil + case uint8: + return int16(v), nil + case uint16: + if v > math.MaxInt16 { + return int16(v), ErrOutOfRange + } + return int16(v), nil + case uint32: + if v > math.MaxInt16 { + return int16(v), ErrOutOfRange + } + return int16(v), nil + case uint64: + if v > math.MaxInt16 { + return int16(v), ErrOutOfRange + } + return int16(v), nil + case float32: + if v < math.MinInt16 || v > math.MaxInt16 { + return int16(v), ErrOutOfRange + } + return int16(v), nil + case float64: + if v < math.MinInt16 || v > math.MaxInt16 { + return int16(v), ErrOutOfRange + } + return int16(v), nil + case nil: + return 0, nil + } + return 0, fmt.Errorf("type \"%T\" unsupported", value) +} + +func ToInt8(value interface{}) (int8, error) { + switch v := value.(type) { + case string: + x, err := strconv.ParseInt(v, 10, 32) + return int8(x), err + case []byte: + x, err := strconv.ParseInt(string(v), 10, 32) + return int8(x), err + case fmt.Stringer: + x, err := strconv.ParseInt(v.String(), 10, 32) + return int8(x), err + case bool: + if v { + return 1, nil + } + return 0, nil + case int: + return int8(v), nil + case int8: + return v, nil + case int16: + if v < math.MinInt8 || v > math.MaxInt8 { + return int8(v), ErrOutOfRange + } + return int8(v), nil + case int32: + if v < math.MinInt8 || v > math.MaxInt8 { + return int8(v), ErrOutOfRange + } + return int8(v), nil + case int64: + if v < math.MinInt8 || v > math.MaxInt8 { + return int8(v), ErrOutOfRange + } + return int8(v), nil + case uint: + if v > math.MaxInt8 { + return int8(v), ErrOutOfRange + } + return int8(v), nil + case uint8: + if v > math.MaxInt8 { + return int8(v), ErrOutOfRange + } + return int8(v), nil + case uint16: + if v > math.MaxInt8 { + return int8(v), ErrOutOfRange + } + return int8(v), nil + case uint32: + if v > math.MaxInt8 { + return int8(v), ErrOutOfRange + } + return int8(v), nil + case uint64: + if v > math.MaxInt8 { + return int8(v), ErrOutOfRange + } + return int8(v), nil + case float32: + if v < math.MinInt8 || v > math.MaxInt8 { + return int8(v), ErrOutOfRange + } + return int8(v), nil + case float64: + if v < math.MinInt8 || v > math.MaxInt8 { + return int8(v), ErrOutOfRange + } + return int8(v), nil + case nil: + return 0, nil + } + return 0, fmt.Errorf("type \"%T\" unsupported", value) +} + func ToString(value interface{}) (string, error) { switch v := value.(type) { case string: @@ -45,135 +691,6 @@ func ToString(value interface{}) (string, error) { return "", fmt.Errorf("type \"%T\" unsupported", value) } -func ToFloat64(value interface{}) (float64, error) { - switch v := value.(type) { - case string: - return strconv.ParseFloat(v, 64) - case []byte: - return strconv.ParseFloat(string(v), 64) - case fmt.Stringer: - return strconv.ParseFloat(v.String(), 64) - case bool: - if v { - return float64(1), nil - } - return float64(0), nil - case int: - return float64(v), nil - case int8: - return float64(v), nil - case int16: - return float64(v), nil - case int32: - return float64(v), nil - case int64: - return float64(v), nil - case uint: - return float64(v), nil - case uint8: - return float64(v), nil - case uint16: - return float64(v), nil - case uint32: - return float64(v), nil - case uint64: - return float64(v), nil - case float32: - return float64(v), nil - case float64: - return v, nil - case nil: - return 0, nil - } - return 0, fmt.Errorf("type \"%T\" unsupported", value) -} - -func ToInt64(value interface{}) (int64, error) { - switch v := value.(type) { - case string: - return strconv.ParseInt(v, 10, 64) - case []byte: - return strconv.ParseInt(string(v), 10, 64) - case fmt.Stringer: - return strconv.ParseInt(v.String(), 10, 64) - case bool: - if v { - return int64(1), nil - } - return int64(0), nil - case int: - return int64(v), nil - case int8: - return int64(v), nil - case int16: - return int64(v), nil - case int32: - return int64(v), nil - case int64: - return v, nil - case uint: - return int64(v), nil - case uint8: - return int64(v), nil - case uint16: - return int64(v), nil - case uint32: - return int64(v), nil - case uint64: - return int64(v), nil - case float32: - return int64(v), nil - case float64: - return int64(v), nil - case nil: - return 0, nil - } - return 0, fmt.Errorf("type \"%T\" unsupported", value) -} - -func ToUint64(value interface{}) (uint64, error) { - switch v := value.(type) { - case string: - return strconv.ParseUint(v, 10, 64) - case []byte: - return strconv.ParseUint(string(v), 10, 64) - case fmt.Stringer: - return strconv.ParseUint(v.String(), 10, 64) - case bool: - if v { - return uint64(1), nil - } - return uint64(0), nil - case int: - return uint64(v), nil - case int8: - return uint64(v), nil - case int16: - return uint64(v), nil - case int32: - return uint64(v), nil - case int64: - return uint64(v), nil - case uint: - return uint64(v), nil - case uint8: - return uint64(v), nil - case uint16: - return uint64(v), nil - case uint32: - return uint64(v), nil - case uint64: - return v, nil - case float32: - return uint64(v), nil - case float64: - return uint64(v), nil - case nil: - return 0, nil - } - return 0, fmt.Errorf("type \"%T\" unsupported", value) -} - func ToBool(value interface{}) (bool, error) { switch v := value.(type) { case string: diff --git a/plugins/inputs/sql/sql.go b/plugins/inputs/sql/sql.go index 1d93a08bd..93307fa0d 100644 --- a/plugins/inputs/sql/sql.go +++ b/plugins/inputs/sql/sql.go @@ -55,7 +55,7 @@ type Query struct { fieldFilterString filter.Filter } -func (q *Query) parse(acc telegraf.Accumulator, rows *dbsql.Rows, t time.Time) (int, error) { +func (q *Query) parse(acc telegraf.Accumulator, rows *dbsql.Rows, t time.Time, logger telegraf.Logger) (int, error) { columnNames, err := rows.Columns() if err != nil { return 0, err @@ -140,7 +140,12 @@ func (q *Query) parse(acc telegraf.Accumulator, rows *dbsql.Rows, t time.Time) ( if q.fieldFilterInt.Match(name) { v, err := internal.ToInt64(columnData[i]) if err != nil { - return 0, fmt.Errorf("converting field column %q to int failed: %w", name, err) + if err != nil { + if !errors.Is(err, internal.ErrOutOfRange) { + return 0, fmt.Errorf("converting field column %q to int failed: %w", name, err) + } + logger.Warnf("field column %q: %v", name, err) + } } fields[name] = v continue @@ -149,7 +154,10 @@ func (q *Query) parse(acc telegraf.Accumulator, rows *dbsql.Rows, t time.Time) ( if q.fieldFilterUint.Match(name) { v, err := internal.ToUint64(columnData[i]) if err != nil { - return 0, fmt.Errorf("converting field column %q to uint failed: %w", name, err) + if !errors.Is(err, internal.ErrOutOfRange) { + return 0, fmt.Errorf("converting field column %q to uint failed: %w", name, err) + } + logger.Warnf("field column %q: %v", name, err) } fields[name] = v continue @@ -526,7 +534,7 @@ func (s *SQL) executeQuery(ctx context.Context, acc telegraf.Accumulator, q Quer if err != nil { return err } - rowCount, err := q.parse(acc, rows, tquery) + rowCount, err := q.parse(acc, rows, tquery, s.Log) s.Log.Debugf("Received %d rows and %d columns for query %q", rowCount, len(columnNames), q.Query) return err diff --git a/plugins/inputs/suricata/suricata.go b/plugins/inputs/suricata/suricata.go index 6797df792..67654819d 100644 --- a/plugins/inputs/suricata/suricata.go +++ b/plugins/inputs/suricata/suricata.go @@ -305,7 +305,7 @@ func (s *Suricata) parseGeneric(acc telegraf.Accumulator, result map[string]inte } for _, key := range []string{"src_port", "dest_port"} { if val, ok := result[key]; ok { - if convertedVal, err := internal.ToInt64(val); err == nil { + if convertedVal, err := internal.ToInt64(val); err == nil || errors.Is(err, internal.ErrOutOfRange) { fields[key] = convertedVal } } diff --git a/tools/package_incus_test/package_incus_test b/tools/package_incus_test/package_incus_test deleted file mode 100755 index c2436e1a9..000000000 Binary files a/tools/package_incus_test/package_incus_test and /dev/null differ