1
0
Fork 0

Adding upstream version 1.34.4.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-24 07:26:29 +02:00
parent e393c3af3f
commit 4978089aab
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
4963 changed files with 677545 additions and 0 deletions

View file

@ -0,0 +1,43 @@
# MessagePack
[MessagePack](https://msgpack.org) is an efficient binary serialization format. It lets you exchange data among multiple languages like JSON.
## Format Definitions
Output of this format is MessagePack binary representation of metrics that have identical structure of the below JSON.
```json
{
"name":"cpu",
"time": <TIMESTAMP>, // https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type
"tags":{
"tag_1":"host01",
...
},
"fields":{
"field_1":30,
"field_2":true,
"field_3":"field_value"
"field_4":30.1
...
}
}
```
MessagePack has it's own timestamp representation. You can find additional information from [MessagePack specification](https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type).
## MessagePack Configuration
There are no additional configuration options for MessagePack format.
```toml
[[outputs.file]]
## Files to write to, "stdout" is a specially handled file.
files = ["stdout", "/tmp/metrics.out"]
## Data format to output.
## Each data format has its own unique set of configuration options, read
## more about them here:
## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md
data_format = "msgpack"
```

View file

@ -0,0 +1,104 @@
package msgpack
import (
"encoding/binary"
"time"
"github.com/tinylib/msgp/msgp"
)
//go:generate msgp
// Metric is structure to define MessagePack message format
// will be used by msgp code generator
type Metric struct {
Name string `msg:"name"`
Time MessagePackTime `msg:"time,extension"`
Tags map[string]string `msg:"tags"`
Fields map[string]interface{} `msg:"fields"`
}
// MessagePackTime implements the official timestamp extension type
// https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type
//
// tinylib/msgp has been using their own custom extension type and the official extension
// is not available. (https://github.com/tinylib/msgp/issues/214)
type MessagePackTime struct {
time time.Time
}
func init() {
msgp.RegisterExtension(-1, func() msgp.Extension { return new(MessagePackTime) })
}
// ExtensionType implements the Extension interface
func (*MessagePackTime) ExtensionType() int8 {
return -1
}
// Len implements the Extension interface
// The timestamp extension uses variable length encoding depending the input
//
// 32bits: [1970-01-01 00:00:00 UTC, 2106-02-07 06:28:16 UTC) range. If the nanoseconds part is 0
// 64bits: [1970-01-01 00:00:00.000000000 UTC, 2514-05-30 01:53:04.000000000 UTC) range.
// 96bits: [-584554047284-02-23 16:59:44 UTC, 584554051223-11-09 07:00:16.000000000 UTC) range.
func (z *MessagePackTime) Len() int {
sec := z.time.Unix()
nsec := z.time.Nanosecond()
if sec < 0 || sec >= (1<<34) { // 96 bits encoding
return 12
}
if sec >= (1<<32) || nsec != 0 {
return 8
}
return 4
}
// MarshalBinaryTo implements the Extension interface
func (z *MessagePackTime) MarshalBinaryTo(buf []byte) error {
length := z.Len()
if length == 4 {
sec := z.time.Unix()
binary.BigEndian.PutUint32(buf, uint32(sec))
} else if length == 8 {
sec := z.time.Unix()
nsec := z.time.Nanosecond()
data := uint64(nsec)<<34 | (uint64(sec) & 0x03_ffff_ffff)
binary.BigEndian.PutUint64(buf, data)
} else if length == 12 {
sec := z.time.Unix()
nsec := z.time.Nanosecond()
binary.BigEndian.PutUint32(buf, uint32(nsec))
binary.BigEndian.PutUint64(buf[4:], uint64(sec))
}
return nil
}
// UnmarshalBinary implements the Extension interface
func (z *MessagePackTime) UnmarshalBinary(buf []byte) error {
length := len(buf)
if length == 4 {
sec := binary.BigEndian.Uint32(buf)
z.time = time.Unix(int64(sec), 0)
} else if length == 8 {
data := binary.BigEndian.Uint64(buf)
nsec := (data & 0xfffffffc_00000000) >> 34
sec := data & 0x00000003_ffffffff
z.time = time.Unix(int64(sec), int64(nsec))
} else if length == 12 {
nsec := binary.BigEndian.Uint32(buf)
sec := binary.BigEndian.Uint64(buf[4:])
z.time = time.Unix(int64(sec), int64(nsec))
}
return nil
}

View file

@ -0,0 +1,417 @@
package msgpack
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
import (
"github.com/tinylib/msgp/msgp"
)
// DecodeMsg implements msgp.Decodable
func (z *MessagePackTime) DecodeMsg(dc *msgp.Reader) (err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, err = dc.ReadMapHeader()
if err != nil {
err = msgp.WrapError(err)
return
}
for zb0001 > 0 {
zb0001--
field, err = dc.ReadMapKeyPtr()
if err != nil {
err = msgp.WrapError(err)
return
}
switch msgp.UnsafeString(field) {
default:
err = dc.Skip()
if err != nil {
err = msgp.WrapError(err)
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z MessagePackTime) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 0
err = en.Append(0x80)
if err != nil {
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z MessagePackTime) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 0
o = append(o, 0x80)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *MessagePackTime) UnmarshalMsg(bts []byte) (o []byte, err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
for zb0001 > 0 {
zb0001--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
switch msgp.UnsafeString(field) {
default:
bts, err = msgp.Skip(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
}
}
o = bts
return
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z MessagePackTime) Msgsize() (s int) {
s = 1
return
}
// DecodeMsg implements msgp.Decodable
func (z *Metric) DecodeMsg(dc *msgp.Reader) (err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, err = dc.ReadMapHeader()
if err != nil {
err = msgp.WrapError(err)
return
}
for zb0001 > 0 {
zb0001--
field, err = dc.ReadMapKeyPtr()
if err != nil {
err = msgp.WrapError(err)
return
}
switch msgp.UnsafeString(field) {
case "name":
z.Name, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "Name")
return
}
case "time":
err = dc.ReadExtension(&z.Time)
if err != nil {
err = msgp.WrapError(err, "Time")
return
}
case "tags":
var zb0002 uint32
zb0002, err = dc.ReadMapHeader()
if err != nil {
err = msgp.WrapError(err, "Tags")
return
}
if z.Tags == nil {
z.Tags = make(map[string]string, zb0002)
} else if len(z.Tags) > 0 {
for key := range z.Tags {
delete(z.Tags, key)
}
}
for zb0002 > 0 {
zb0002--
var za0001 string
var za0002 string
za0001, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "Tags")
return
}
za0002, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "Tags", za0001)
return
}
z.Tags[za0001] = za0002
}
case "fields":
var zb0003 uint32
zb0003, err = dc.ReadMapHeader()
if err != nil {
err = msgp.WrapError(err, "Fields")
return
}
if z.Fields == nil {
z.Fields = make(map[string]interface{}, zb0003)
} else if len(z.Fields) > 0 {
for key := range z.Fields {
delete(z.Fields, key)
}
}
for zb0003 > 0 {
zb0003--
var za0003 string
var za0004 interface{}
za0003, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "Fields")
return
}
za0004, err = dc.ReadIntf()
if err != nil {
err = msgp.WrapError(err, "Fields", za0003)
return
}
z.Fields[za0003] = za0004
}
default:
err = dc.Skip()
if err != nil {
err = msgp.WrapError(err)
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z *Metric) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 4
// write "name"
err = en.Append(0x84, 0xa4, 0x6e, 0x61, 0x6d, 0x65)
if err != nil {
return
}
err = en.WriteString(z.Name)
if err != nil {
err = msgp.WrapError(err, "Name")
return
}
// write "time"
err = en.Append(0xa4, 0x74, 0x69, 0x6d, 0x65)
if err != nil {
return
}
err = en.WriteExtension(&z.Time)
if err != nil {
err = msgp.WrapError(err, "Time")
return
}
// write "tags"
err = en.Append(0xa4, 0x74, 0x61, 0x67, 0x73)
if err != nil {
return
}
err = en.WriteMapHeader(uint32(len(z.Tags)))
if err != nil {
err = msgp.WrapError(err, "Tags")
return
}
for za0001, za0002 := range z.Tags {
err = en.WriteString(za0001)
if err != nil {
err = msgp.WrapError(err, "Tags")
return
}
err = en.WriteString(za0002)
if err != nil {
err = msgp.WrapError(err, "Tags", za0001)
return
}
}
// write "fields"
err = en.Append(0xa6, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73)
if err != nil {
return
}
err = en.WriteMapHeader(uint32(len(z.Fields)))
if err != nil {
err = msgp.WrapError(err, "Fields")
return
}
for za0003, za0004 := range z.Fields {
err = en.WriteString(za0003)
if err != nil {
err = msgp.WrapError(err, "Fields")
return
}
err = en.WriteIntf(za0004)
if err != nil {
err = msgp.WrapError(err, "Fields", za0003)
return
}
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z *Metric) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 4
// string "name"
o = append(o, 0x84, 0xa4, 0x6e, 0x61, 0x6d, 0x65)
o = msgp.AppendString(o, z.Name)
// string "time"
o = append(o, 0xa4, 0x74, 0x69, 0x6d, 0x65)
o, err = msgp.AppendExtension(o, &z.Time)
if err != nil {
err = msgp.WrapError(err, "Time")
return
}
// string "tags"
o = append(o, 0xa4, 0x74, 0x61, 0x67, 0x73)
o = msgp.AppendMapHeader(o, uint32(len(z.Tags)))
for za0001, za0002 := range z.Tags {
o = msgp.AppendString(o, za0001)
o = msgp.AppendString(o, za0002)
}
// string "fields"
o = append(o, 0xa6, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73)
o = msgp.AppendMapHeader(o, uint32(len(z.Fields)))
for za0003, za0004 := range z.Fields {
o = msgp.AppendString(o, za0003)
o, err = msgp.AppendIntf(o, za0004)
if err != nil {
err = msgp.WrapError(err, "Fields", za0003)
return
}
}
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *Metric) UnmarshalMsg(bts []byte) (o []byte, err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
for zb0001 > 0 {
zb0001--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
switch msgp.UnsafeString(field) {
case "name":
z.Name, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Name")
return
}
case "time":
bts, err = msgp.ReadExtensionBytes(bts, &z.Time)
if err != nil {
err = msgp.WrapError(err, "Time")
return
}
case "tags":
var zb0002 uint32
zb0002, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Tags")
return
}
if z.Tags == nil {
z.Tags = make(map[string]string, zb0002)
} else if len(z.Tags) > 0 {
for key := range z.Tags {
delete(z.Tags, key)
}
}
for zb0002 > 0 {
var za0001 string
var za0002 string
zb0002--
za0001, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Tags")
return
}
za0002, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Tags", za0001)
return
}
z.Tags[za0001] = za0002
}
case "fields":
var zb0003 uint32
zb0003, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Fields")
return
}
if z.Fields == nil {
z.Fields = make(map[string]interface{}, zb0003)
} else if len(z.Fields) > 0 {
for key := range z.Fields {
delete(z.Fields, key)
}
}
for zb0003 > 0 {
var za0003 string
var za0004 interface{}
zb0003--
za0003, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Fields")
return
}
za0004, bts, err = msgp.ReadIntfBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Fields", za0003)
return
}
z.Fields[za0003] = za0004
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
}
}
o = bts
return
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z *Metric) Msgsize() (s int) {
s = 1 + 5 + msgp.StringPrefixSize + len(z.Name) + 5 + msgp.ExtensionPrefixSize + z.Time.Len() + 5 + msgp.MapHeaderSize
if z.Tags != nil {
for za0001, za0002 := range z.Tags {
_ = za0002
s += msgp.StringPrefixSize + len(za0001) + msgp.StringPrefixSize + len(za0002)
}
}
s += 7 + msgp.MapHeaderSize
if z.Fields != nil {
for za0003, za0004 := range z.Fields {
_ = za0004
s += msgp.StringPrefixSize + len(za0003) + msgp.GuessSize(za0004)
}
}
return
}

View file

@ -0,0 +1,236 @@
package msgpack
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
import (
"bytes"
"testing"
"github.com/tinylib/msgp/msgp"
)
func TestMarshalUnmarshalMessagePackTime(t *testing.T) {
v := MessagePackTime{}
bts, err := v.MarshalMsg(nil)
if err != nil {
t.Fatal(err)
}
left, err := v.UnmarshalMsg(bts)
if err != nil {
t.Fatal(err)
}
if len(left) > 0 {
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
}
left, err = msgp.Skip(bts)
if err != nil {
t.Fatal(err)
}
if len(left) > 0 {
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
}
}
func BenchmarkMarshalMsgMessagePackTime(b *testing.B) {
v := MessagePackTime{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsgMessagePackTime(b *testing.B) {
v := MessagePackTime{}
bts := make([]byte, 0, v.Msgsize())
bts, _ = v.MarshalMsg(bts[0:0])
b.SetBytes(int64(len(bts)))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
bts, _ = v.MarshalMsg(bts[0:0])
}
}
func BenchmarkUnmarshalMessagePackTime(b *testing.B) {
v := MessagePackTime{}
bts, _ := v.MarshalMsg(nil)
b.ReportAllocs()
b.SetBytes(int64(len(bts)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := v.UnmarshalMsg(bts)
if err != nil {
b.Fatal(err)
}
}
}
func TestEncodeDecodeMessagePackTime(t *testing.T) {
v := MessagePackTime{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Log("WARNING: TestEncodeDecodeMessagePackTime Msgsize() is inaccurate")
}
vn := MessagePackTime{}
err := msgp.Decode(&buf, &vn)
if err != nil {
t.Error(err)
}
buf.Reset()
msgp.Encode(&buf, &v)
err = msgp.NewReader(&buf).Skip()
if err != nil {
t.Error(err)
}
}
func BenchmarkEncodeMessagePackTime(b *testing.B) {
v := MessagePackTime{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len()))
en := msgp.NewWriter(msgp.Nowhere)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.EncodeMsg(en)
}
en.Flush()
}
func BenchmarkDecodeMessagePackTime(b *testing.B) {
v := MessagePackTime{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len()))
rd := msgp.NewEndlessReader(buf.Bytes(), b)
dc := msgp.NewReader(rd)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := v.DecodeMsg(dc)
if err != nil {
b.Fatal(err)
}
}
}
func TestMarshalUnmarshalMetric(t *testing.T) {
v := Metric{}
bts, err := v.MarshalMsg(nil)
if err != nil {
t.Fatal(err)
}
left, err := v.UnmarshalMsg(bts)
if err != nil {
t.Fatal(err)
}
if len(left) > 0 {
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
}
left, err = msgp.Skip(bts)
if err != nil {
t.Fatal(err)
}
if len(left) > 0 {
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
}
}
func BenchmarkMarshalMsgMetric(b *testing.B) {
v := Metric{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsgMetric(b *testing.B) {
v := Metric{}
bts := make([]byte, 0, v.Msgsize())
bts, _ = v.MarshalMsg(bts[0:0])
b.SetBytes(int64(len(bts)))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
bts, _ = v.MarshalMsg(bts[0:0])
}
}
func BenchmarkUnmarshalMetric(b *testing.B) {
v := Metric{}
bts, _ := v.MarshalMsg(nil)
b.ReportAllocs()
b.SetBytes(int64(len(bts)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := v.UnmarshalMsg(bts)
if err != nil {
b.Fatal(err)
}
}
}
func TestEncodeDecodeMetric(t *testing.T) {
v := Metric{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Log("WARNING: TestEncodeDecodeMetric Msgsize() is inaccurate")
}
vn := Metric{}
err := msgp.Decode(&buf, &vn)
if err != nil {
t.Error(err)
}
buf.Reset()
msgp.Encode(&buf, &v)
err = msgp.NewReader(&buf).Skip()
if err != nil {
t.Error(err)
}
}
func BenchmarkEncodeMetric(b *testing.B) {
v := Metric{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len()))
en := msgp.NewWriter(msgp.Nowhere)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.EncodeMsg(en)
}
en.Flush()
}
func BenchmarkDecodeMetric(b *testing.B) {
v := Metric{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len()))
rd := msgp.NewEndlessReader(buf.Bytes(), b)
dc := msgp.NewReader(rd)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := v.DecodeMsg(dc)
if err != nil {
b.Fatal(err)
}
}
}

View file

@ -0,0 +1,162 @@
package msgpack
import (
"encoding/hex"
"math"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestMsgPackTime32(t *testing.T) {
// Maximum of 4 bytes encodable time
var sec int64 = 0xFFFFFFFF
var nsec int64
t1 := MessagePackTime{time: time.Unix(sec, nsec)}
require.Equal(t, 4, t1.Len())
buf := make([]byte, t1.Len())
require.NoError(t, t1.MarshalBinaryTo(buf))
t2 := new(MessagePackTime)
err := t2.UnmarshalBinary(buf)
require.NoError(t, err)
require.Equal(t, t1.time, t2.time)
}
func TestMsgPackTime64(t *testing.T) {
// Maximum of 8 bytes encodable time
var sec int64 = 0x3FFFFFFFF
var nsec int64 = 999999999
t1 := MessagePackTime{time: time.Unix(sec, nsec)}
require.Equal(t, 8, t1.Len())
buf := make([]byte, t1.Len())
require.NoError(t, t1.MarshalBinaryTo(buf))
t2 := new(MessagePackTime)
err := t2.UnmarshalBinary(buf)
require.NoError(t, err)
require.Equal(t, t1.time, t2.time)
}
func TestMsgPackTime96(t *testing.T) {
// Testing 12 bytes timestamp
var sec int64 = 0x400000001
var nsec int64 = 111111111
t1 := MessagePackTime{time: time.Unix(sec, nsec)}
require.Equal(t, 12, t1.Len())
buf := make([]byte, t1.Len())
require.NoError(t, t1.MarshalBinaryTo(buf))
t2 := new(MessagePackTime)
err := t2.UnmarshalBinary(buf)
require.NoError(t, err)
require.True(t, t1.time.Equal(t2.time))
// Testing the default value: 0001-01-01T00:00:00Z
t1 = MessagePackTime{}
require.Equal(t, 12, t1.Len())
require.NoError(t, t1.MarshalBinaryTo(buf))
t2 = new(MessagePackTime)
err = t2.UnmarshalBinary(buf)
require.NoError(t, err)
require.True(t, t1.time.Equal(t2.time))
}
func TestMsgPackTimeEdgeCases(t *testing.T) {
times := make([]time.Time, 0)
expected := make([][]byte, 0)
// Unix epoch. Begin of 4bytes dates
// Nanoseconds: 0x00000000, Seconds: 0x0000000000000000
ts, err := time.Parse(time.RFC3339, "1970-01-01T00:00:00Z")
require.NoError(t, err)
bs, err := hex.DecodeString("d6ff00000000")
require.NoError(t, err)
times = append(times, ts)
expected = append(expected, bs)
// End of 4bytes dates
// Nanoseconds: 0x00000000, Seconds: 0x00000000ffffffff
ts, err = time.Parse(time.RFC3339, "2106-02-07T06:28:15Z")
require.NoError(t, err)
bs, err = hex.DecodeString("d6ffffffffff")
require.NoError(t, err)
times = append(times, ts)
expected = append(expected, bs)
// Begin of 8bytes dates
// Nanoseconds: 0x00000000, Seconds: 0x0000000100000000
ts, err = time.Parse(time.RFC3339, "2106-02-07T06:28:16Z")
require.NoError(t, err)
bs, err = hex.DecodeString("d7ff0000000100000000")
require.NoError(t, err)
times = append(times, ts)
expected = append(expected, bs)
// Just after Unix epoch. Non zero nanoseconds
// Nanoseconds: 0x00000001, Seconds: 0x0000000000000000
ts, err = time.Parse(time.RFC3339Nano, "1970-01-01T00:00:00.000000001Z")
require.NoError(t, err)
bs, err = hex.DecodeString("d7ff0000000400000000")
require.NoError(t, err)
times = append(times, ts)
expected = append(expected, bs)
// End of 8bytes dates
// Nanoseconds: 0x00000000, Seconds: 0x00000003ffffffff
ts, err = time.Parse(time.RFC3339Nano, "2514-05-30T01:53:03.000000000Z")
require.NoError(t, err)
bs, err = hex.DecodeString("d7ff00000003ffffffff")
require.NoError(t, err)
times = append(times, ts)
expected = append(expected, bs)
// Begin of 12bytes date
// Nanoseconds: 0x00000000, Seconds: 0x0000000400000000
ts, err = time.Parse(time.RFC3339Nano, "2514-05-30T01:53:04.000000000Z")
require.NoError(t, err)
bs, err = hex.DecodeString("c70cff000000000000000400000000")
require.NoError(t, err)
times = append(times, ts)
expected = append(expected, bs)
// Zero value, 0001-01-01T00:00:00Z
// Nanoseconds: 0x00000000, Seconds: 0xfffffff1886e0900
ts = time.Time{}
bs, err = hex.DecodeString("c70cff00000000fffffff1886e0900")
require.NoError(t, err)
times = append(times, ts)
expected = append(expected, bs)
// Max value
// Nanoseconds: 0x3b9ac9ff, Seconds: 0x7fffffffffffffff
ts = time.Unix(math.MaxInt64, 999_999_999).UTC()
bs, err = hex.DecodeString("c70cff3b9ac9ff7fffffffffffffff")
require.NoError(t, err)
times = append(times, ts)
expected = append(expected, bs)
buf := make([]byte, 0)
for i, ts := range times {
t1 := MessagePackTime{time: ts}
m := Metric{Time: t1}
buf = buf[:0]
buf, err = m.MarshalMsg(buf)
require.NoError(t, err)
require.Equal(t, expected[i], buf[12:len(buf)-14])
}
}

View file

@ -0,0 +1,47 @@
package msgpack
import (
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/serializers"
)
// Serializer encodes metrics in MessagePack format
type Serializer struct{}
func marshalMetric(buf []byte, metric telegraf.Metric) ([]byte, error) {
return (&Metric{
Name: metric.Name(),
Time: MessagePackTime{time: metric.Time()},
Tags: metric.Tags(),
Fields: metric.Fields(),
}).MarshalMsg(buf)
}
// Serialize implements serializers.Serializer.Serialize
// github.com/influxdata/telegraf/plugins/serializers/Serializer
func (*Serializer) Serialize(metric telegraf.Metric) ([]byte, error) {
return marshalMetric(nil, metric)
}
// SerializeBatch implements serializers.Serializer.SerializeBatch
// github.com/influxdata/telegraf/plugins/serializers/Serializer
func (*Serializer) SerializeBatch(metrics []telegraf.Metric) ([]byte, error) {
buf := make([]byte, 0)
for _, m := range metrics {
var err error
buf, err = marshalMetric(buf, m)
if err != nil {
return nil, err
}
}
return buf, nil
}
func init() {
serializers.Add("msgpack",
func() telegraf.Serializer {
return &Serializer{}
},
)
}

View file

@ -0,0 +1,154 @@
package msgpack
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/metric"
"github.com/influxdata/telegraf/plugins/serializers"
"github.com/influxdata/telegraf/testutil"
)
func toTelegrafMetric(m Metric) telegraf.Metric {
tm := metric.New(m.Name, m.Tags, m.Fields, m.Time.time)
return tm
}
func TestSerializeMetricInt(t *testing.T) {
m := testutil.TestMetric(int64(90))
s := Serializer{}
var buf []byte
buf, err := s.Serialize(m)
require.NoError(t, err)
m2 := &Metric{}
left, err := m2.UnmarshalMsg(buf)
require.NoError(t, err)
require.Empty(t, left)
testutil.RequireMetricEqual(t, m, toTelegrafMetric(*m2))
}
func TestSerializeMetricString(t *testing.T) {
m := testutil.TestMetric("foobar")
s := Serializer{}
var buf []byte
buf, err := s.Serialize(m)
require.NoError(t, err)
m2 := &Metric{}
left, err := m2.UnmarshalMsg(buf)
require.NoError(t, err)
require.Empty(t, left)
testutil.RequireMetricEqual(t, m, toTelegrafMetric(*m2))
}
func TestSerializeMultiFields(t *testing.T) {
m := testutil.TestMetric(90)
m.AddField("value2", 8559615)
s := Serializer{}
var buf []byte
buf, err := s.Serialize(m)
require.NoError(t, err)
m2 := &Metric{}
left, err := m2.UnmarshalMsg(buf)
require.NoError(t, err)
require.Empty(t, left)
testutil.RequireMetricEqual(t, m, toTelegrafMetric(*m2))
}
func TestSerializeMetricWithEscapes(t *testing.T) {
m := testutil.TestMetric(90)
m.AddField("U,age=Idle", int64(90))
m.AddTag("cpu tag", "cpu0")
s := Serializer{}
var buf []byte
buf, err := s.Serialize(m)
require.NoError(t, err)
m2 := &Metric{}
left, err := m2.UnmarshalMsg(buf)
require.NoError(t, err)
require.Empty(t, left)
testutil.RequireMetricEqual(t, m, toTelegrafMetric(*m2))
}
func TestSerializeMultipleMetric(t *testing.T) {
m := testutil.TestMetric(90)
s := Serializer{}
encoded, err := s.Serialize(m)
require.NoError(t, err)
// Multiple metrics in continuous bytes stream
var buf []byte
buf = append(buf, encoded...)
buf = append(buf, encoded...)
buf = append(buf, encoded...)
buf = append(buf, encoded...)
left := buf
for len(left) > 0 {
decodeM := &Metric{}
left, err = decodeM.UnmarshalMsg(left)
require.NoError(t, err)
testutil.RequireMetricEqual(t, m, toTelegrafMetric(*decodeM))
}
}
func TestSerializeBatch(t *testing.T) {
m := testutil.TestMetric(90)
metrics := []telegraf.Metric{m, m, m, m}
s := Serializer{}
buf, err := s.SerializeBatch(metrics)
require.NoError(t, err)
left := buf
for len(left) > 0 {
decodeM := &Metric{}
left, err = decodeM.UnmarshalMsg(left)
require.NoError(t, err)
testutil.RequireMetricEqual(t, m, toTelegrafMetric(*decodeM))
}
}
func BenchmarkSerialize(b *testing.B) {
s := &Serializer{}
metrics := serializers.BenchmarkMetrics(b)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := s.Serialize(metrics[i%len(metrics)])
require.NoError(b, err)
}
}
func BenchmarkSerializeBatch(b *testing.B) {
s := &Serializer{}
m := serializers.BenchmarkMetrics(b)
metrics := m[:]
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := s.SerializeBatch(metrics)
require.NoError(b, err)
}
}