Use dynatrace-metric-utils (#9295)

This commit is contained in:
Daniel Dyla 2021-06-08 17:27:39 -04:00 committed by GitHub
parent d6ac4abfb8
commit 298670ae18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 315 additions and 235 deletions

View File

@ -63,6 +63,7 @@ following works:
- github.com/docker/docker [Apache License 2.0](https://github.com/docker/docker/blob/master/LICENSE) - github.com/docker/docker [Apache License 2.0](https://github.com/docker/docker/blob/master/LICENSE)
- github.com/docker/go-connections [Apache License 2.0](https://github.com/docker/go-connections/blob/master/LICENSE) - github.com/docker/go-connections [Apache License 2.0](https://github.com/docker/go-connections/blob/master/LICENSE)
- github.com/docker/go-units [Apache License 2.0](https://github.com/docker/go-units/blob/master/LICENSE) - github.com/docker/go-units [Apache License 2.0](https://github.com/docker/go-units/blob/master/LICENSE)
- github.com/dynatrace-oss/dynatrace-metric-utils-go [Apache License 2.0](https://github.com/dynatrace-oss/dynatrace-metric-utils-go/blob/master/LICENSE)
- github.com/eapache/go-resiliency [MIT License](https://github.com/eapache/go-resiliency/blob/master/LICENSE) - github.com/eapache/go-resiliency [MIT License](https://github.com/eapache/go-resiliency/blob/master/LICENSE)
- github.com/eapache/go-xerial-snappy [MIT License](https://github.com/eapache/go-xerial-snappy/blob/master/LICENSE) - github.com/eapache/go-xerial-snappy [MIT License](https://github.com/eapache/go-xerial-snappy/blob/master/LICENSE)
- github.com/eapache/queue [MIT License](https://github.com/eapache/queue/blob/master/LICENSE) - github.com/eapache/queue [MIT License](https://github.com/eapache/queue/blob/master/LICENSE)

1
go.mod
View File

@ -45,6 +45,7 @@ require (
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1
github.com/dimchansky/utfbom v1.1.1 github.com/dimchansky/utfbom v1.1.1
github.com/docker/docker v20.10.5+incompatible github.com/docker/docker v20.10.5+incompatible
github.com/dynatrace-oss/dynatrace-metric-utils-go v0.1.0
github.com/eclipse/paho.mqtt.golang v1.3.0 github.com/eclipse/paho.mqtt.golang v1.3.0
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
github.com/go-logfmt/logfmt v0.5.0 github.com/go-logfmt/logfmt v0.5.0

20
go.sum
View File

@ -239,7 +239,6 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4Yn
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
@ -401,6 +400,8 @@ github.com/dropbox/godropbox v0.0.0-20180512210157-31879d3884b9/go.mod h1:glr97h
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dynatrace-oss/dynatrace-metric-utils-go v0.1.0 h1:ldKn47mFgWCoiJRXA32psdEACPKffX9O1Msh1K8M+f0=
github.com/dynatrace-oss/dynatrace-metric-utils-go v0.1.0/go.mod h1:qw0E9EJ0PnSlhWawDNuqE0zhc1hqOBUCFIAj3dd9DNw=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q=
github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
@ -463,7 +464,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
@ -620,7 +620,6 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
@ -629,7 +628,6 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1 h1:jAbXjIeW2ZSW2AwFxlGTDoc2CjI2XujLkV3ArsZFCvc= github.com/golang/protobuf v1.5.1 h1:jAbXjIeW2ZSW2AwFxlGTDoc2CjI2XujLkV3ArsZFCvc=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
@ -1114,7 +1112,6 @@ github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go
github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
@ -1265,9 +1262,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
@ -1287,7 +1281,6 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@ -1602,8 +1595,6 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1690,10 +1681,6 @@ golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190906203814-12febf440ab1/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190906203814-12febf440ab1/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -1729,7 +1716,6 @@ golang.org/x/tools v0.0.0-20200822203824-307de81be3f4/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1800,7 +1786,6 @@ google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200815001618-f69a88009b70/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200815001618-f69a88009b70/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8=
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
@ -1836,7 +1821,6 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=

View File

@ -1,49 +1,135 @@
# Dynatrace Output Plugin # Dynatrace Output Plugin
This plugin is sending telegraf metrics to [Dynatrace](https://www.dynatrace.com). It has two operational modes. This plugin sends Telegraf metrics to [Dynatrace](https://www.dynatrace.com) via the [Dynatrace Metrics API V2](https://www.dynatrace.com/support/help/dynatrace-api/environment-api/metric-v2/). It may be run alongside the Dynatrace OneAgent for automatic authentication or it may be run standalone on a host without a OneAgent by specifying a URL and API Token.
More information on the plugin can be found in the [Dynatrace documentation](https://www.dynatrace.com/support/help/how-to-use-dynatrace/metrics/metric-ingestion/ingestion-methods/telegraf/).
Telegraf minimum version: Telegraf 1.16 ## Requirements
Plugin minimum tested version: 1.16
## Running alongside Dynatrace OneAgent You will either need a Dynatrace OneAgent (version 1.201 or higher) installed on the same host as Telegraf; or a Dynatrace environment with version 1.202 or higher. Monotonic counters (e.g. `diskio.reads`, `system.uptime`) require Dynatrace 208 or later.
if you run the Telegraf agent on a host or VM that is monitored by the Dynatrace OneAgent then you only need to enable the plugin but need no further configuration. The Dynatrace telegraf output plugin will send all metrics to the OneAgent which will use its secure and load balanced connection to send the metrics to your Dynatrace SaaS or Managed environment. - Telegraf minimum version: Telegraf 1.16
## Getting Started
Setting up Telegraf is explained in the [Telegraf Documentation](https://docs.influxdata.com/telegraf/latest/introduction/getting-started/).
The Dynatrace exporter may be enabled by adding an `[[outputs.dynatrace]]` section to your `telegraf.conf` config file.
All configurations are optional, but if a `url` other than the OneAgent metric ingestion endpoint is specified then an `api_token` is required.
To see all available options, see [Configuration](#configuration) below.
### Running alongside Dynatrace OneAgent
If you run the Telegraf agent on a host or VM that is monitored by the Dynatrace OneAgent then you only need to enable the plugin, but need no further configuration. The Dynatrace Telegraf output plugin will send all metrics to the OneAgent which will use its secure and load balanced connection to send the metrics to your Dynatrace SaaS or Managed environment.
Depending on your environment, you might have to enable metrics ingestion on the OneAgent first as described in the [Dynatrace documentation](https://www.dynatrace.com/support/help/how-to-use-dynatrace/metrics/metric-ingestion/ingestion-methods/telegraf/).
Note: The name and identifier of the host running Telegraf will be added as a dimension to every metric. If this is undesirable, then the output plugin may be used in standalone mode using the directions below.
```toml
[[outputs.dynatrace]]
## No options are required. By default, metrics will be exported via the OneAgent on the local host.
```
## Running standalone ## Running standalone
If you run the Telegraf agent on a host or VM without a OneAgent you will need to configure the environment API endpoint to send the metrics to and an API token for security. If you run the Telegraf agent on a host or VM without a OneAgent you will need to configure the environment API endpoint to send the metrics to and an API token for security.
The endpoint for the Dynatrace Metrics API is You will also need to configure an API token for secure access. Find out how to create a token in the [Dynatrace documentation](https://www.dynatrace.com/support/help/dynatrace-api/basics/dynatrace-api-authentication/) or simply navigate to **Settings > Integration > Dynatrace API** in your Dynatrace environment and create a token with Dynatrace API and create a new token with
'Ingest metrics' (`metrics.ingest`) scope enabled. It is recommended to limit Token scope to only this permission.
* Managed https://{your-domain}/e/{your-environment-id}/api/v2/metrics/ingest The endpoint for the Dynatrace Metrics API v2 is
* SaaS https://{your-environment-id}.live.dynatrace.com/api/v2/metrics/ingest
You can learn more about how to use the Dynatrace API [here](https://www.dynatrace.com/support/help/dynatrace-api/) * on Dynatrace Managed: `https://{your-domain}/e/{your-environment-id}/api/v2/metrics/ingest`
* on Dynatrace SaaS: `https://{your-environment-id}.live.dynatrace.com/api/v2/metrics/ingest`
You will also need to configure an API token for secure access. Find out how to create a token [here](https://www.dynatrace.com/support/help/dynatrace-api/environment-api/tokens/) or simply navigate to **Settings > Integration > Dynatrace API** in your Dynatrace environment and create a token with Dynatrace API and create a new token with ```toml
'Ingest metrics data points' access scope enabled. [[outputs.dynatrace]]
## If no OneAgent is running on the host, url and api_token need to be set
## Dynatrace Metrics Ingest v2 endpoint to receive metrics
url = "https://{your-environment-id}.live.dynatrace.com/api/v2/metrics/ingest"
## API token is required if a URL is specified and should be restricted to the 'Ingest metrics' scope
api_token = "your API token here" // hard-coded for illustration only, should be read from environment
```
You can learn more about how to use the Dynatrace API [here](https://www.dynatrace.com/support/help/dynatrace-api/).
## Configuration ## Configuration
### `url`
*required*: `false`
*default*: Local OneAgent endpoint
Set your Dynatrace environment URL (e.g.: `https://{your-environment-id}.live.dynatrace.com/api/v2/metrics/ingest`) if you do not use a OneAgent or wish to export metrics directly to a Dynatrace metrics v2 endpoint. If a URL is set to anything other than the local OneAgent endpoint, then an API token is required.
```toml ```toml
[[outputs.dynatrace]] [[outputs.dynatrace]]
## Leave empty or use the local ingest endpoint of your OneAgent monitored host (e.g.: http://127.0.0.1:14499/metrics/ingest). ## Leave empty or use the local ingest endpoint of your OneAgent monitored host (e.g.: http://127.0.0.1:14499/metrics/ingest).
## Set Dynatrace environment URL (e.g.: https://YOUR_DOMAIN/api/v2/metrics/ingest) if you do not use a OneAgent ## Set Dynatrace environment URL (e.g.: https://YOUR_DOMAIN/api/v2/metrics/ingest) if you do not use a OneAgent
url = "" url = ""
api_token = "" api_token = ""
## Optional prefix for metric names (e.g.: "telegraf.") ## Optional prefix for metric names (e.g.: "telegraf")
prefix = "telegraf." prefix = "telegraf"
## Flag for skipping the tls certificate check, just for testing purposes, should be false by default ## Flag for skipping the tls certificate check, just for testing purposes, should be false by default
insecure_skip_verify = false insecure_skip_verify = false
## If you want to convert values represented as gauges to counters, add the metric names here ## If you want to convert values represented as gauges to counters, add the metric names here
additional_counters = [ ] additional_counters = [ ]
url = "https://{your-environment-id}.live.dynatrace.com/api/v2/metrics/ingest"
``` ```
## Requirements ### `api_token`
You will either need a Dynatrace OneAgent (version 1.201 or higher) installed on the same host as Telegraf; or a Dynatrace environment with version 1.202 or higher. Monotonic counters (e.g. diskio.reads, system.uptime) require release 208 or later. *required*: `false` unless `url` is specified
You will either need a Dynatrace OneAgent (version 1.201 or higher) installed on the same host as Telegraf; or a Dynatrace environment with version 1.202 or higher
API token is required if a URL other than the OneAgent endpoint is specified and it should be restricted to the 'Ingest metrics' scope.
```toml
api_token = "your API token here"
```
### `prefix`
*required*: `false`
Optional prefix to be prepended to all metric names (will be separated with a `.`).
```toml
prefix = "telegraf"
```
### `insecure_skip_verify`
*required*: `false`
Setting this option to true skips TLS verification for testing or when using self-signed certificates.
```toml
insecure_skip_verify = false
```
### `additional_counters`
*required*: `false`
If you want to convert values represented as gauges to counters, add the metric names here.
```toml
additional_counters = [ ]
```
### `default_dimensions`
*required*: `false`
Default dimensions that will be added to every exported metric.
```toml
default_dimensions = {
key = "value"
}
```
## Limitations ## Limitations
Telegraf measurements which can't be converted to a float64 are skipped.
Telegraf measurements which can't be converted to a number are skipped.

View File

@ -4,11 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math"
"net/http" "net/http"
"regexp"
"sort"
"strconv"
"strings" "strings"
"time" "time"
@ -16,17 +12,10 @@ import (
"github.com/influxdata/telegraf/config" "github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/plugins/common/tls" "github.com/influxdata/telegraf/plugins/common/tls"
"github.com/influxdata/telegraf/plugins/outputs" "github.com/influxdata/telegraf/plugins/outputs"
)
const ( dtMetric "github.com/dynatrace-oss/dynatrace-metric-utils-go/metric"
oneAgentMetricsURL = "http://127.0.0.1:14499/metrics/ingest" "github.com/dynatrace-oss/dynatrace-metric-utils-go/metric/apiconstants"
dtIngestAPILineLimit = 1000 "github.com/dynatrace-oss/dynatrace-metric-utils-go/metric/dimensions"
)
var (
reNameAllowedCharList = regexp.MustCompile("[^A-Za-z0-9.-]+")
maxDimKeyLen = 100
maxMetricKeyLen = 250
) )
// Dynatrace Configuration for the Dynatrace output plugin // Dynatrace Configuration for the Dynatrace output plugin
@ -37,12 +26,12 @@ type Dynatrace struct {
Log telegraf.Logger `toml:"-"` Log telegraf.Logger `toml:"-"`
Timeout config.Duration `toml:"timeout"` Timeout config.Duration `toml:"timeout"`
AddCounterMetrics []string `toml:"additional_counters"` AddCounterMetrics []string `toml:"additional_counters"`
State map[string]string
SendCounter int
tls.ClientConfig tls.ClientConfig
client *http.Client client *http.Client
loggedMetrics map[string]bool // New empty set
} }
const sampleConfig = ` const sampleConfig = `
@ -61,8 +50,8 @@ const sampleConfig = `
## The API token needs data ingest scope permission. When using OneAgent, no API token is required. ## The API token needs data ingest scope permission. When using OneAgent, no API token is required.
api_token = "" api_token = ""
## Optional prefix for metric names (e.g.: "telegraf.") ## Optional prefix for metric names (e.g.: "telegraf")
prefix = "telegraf." prefix = "telegraf"
## Optional TLS Config ## Optional TLS Config
# tls_ca = "/etc/telegraf/ca.pem" # tls_ca = "/etc/telegraf/ca.pem"
@ -101,163 +90,97 @@ func (d *Dynatrace) Description() string {
return "Send telegraf metrics to a Dynatrace environment" return "Send telegraf metrics to a Dynatrace environment"
} }
// Normalizes a metric keys or metric dimension identifiers
// according to Dynatrace format.
func (d *Dynatrace) normalize(s string, max int) (string, error) {
s = reNameAllowedCharList.ReplaceAllString(s, "_")
// Strip Digits and underscores if they are at the beginning of the string
normalizedString := strings.TrimLeft(s, "_0123456789")
for strings.HasPrefix(normalizedString, "_") {
normalizedString = normalizedString[1:]
}
if len(normalizedString) > max {
normalizedString = normalizedString[:max]
}
for strings.HasSuffix(normalizedString, "_") {
normalizedString = normalizedString[:len(normalizedString)-1]
}
normalizedString = strings.ReplaceAll(normalizedString, "..", "_")
if len(normalizedString) == 0 {
return "", fmt.Errorf("error normalizing the string: %s", s)
}
return normalizedString, nil
}
func (d *Dynatrace) escape(v string) string {
return strconv.Quote(v)
}
func (d *Dynatrace) Write(metrics []telegraf.Metric) error { func (d *Dynatrace) Write(metrics []telegraf.Metric) error {
var buf bytes.Buffer
metricCounter := 1
var tagb bytes.Buffer
if len(metrics) == 0 { if len(metrics) == 0 {
return nil return nil
} }
for _, metric := range metrics { lines := []string{}
// first write the tags into a buffer
tagb.Reset()
if len(metric.Tags()) > 0 {
keys := make([]string, 0, len(metric.Tags()))
for k := range metric.Tags() {
keys = append(keys, k)
}
// sort tag keys to expect the same order in ech run
sort.Strings(keys)
for _, k := range keys { for _, tm := range metrics {
tagKey, err := d.normalize(k, maxDimKeyLen) dims := []dimensions.Dimension{}
if err != nil { for _, tag := range tm.TagList() {
// Ignore special tags for histogram and summary types.
switch tm.Type() {
case telegraf.Histogram:
if tag.Key == "le" || tag.Key == "gt" {
continue continue
} }
if len(metric.Tags()[k]) > 0 { case telegraf.Summary:
fmt.Fprintf(&tagb, ",%s=%s", strings.ToLower(tagKey), d.escape(metric.Tags()[k])) if tag.Key == "quantile" {
continue
} }
} }
dims = append(dims, dimensions.NewDimension(tag.Key, tag.Value))
} }
if len(metric.Fields()) > 0 {
for k, v := range metric.Fields() { metricType := tm.Type()
var value string for _, field := range tm.FieldList() {
switch v := v.(type) { metricName := tm.Name() + "." + field.Key
case string: for _, i := range d.AddCounterMetrics {
continue if metricName == i {
case float64: metricType = telegraf.Counter
if !math.IsNaN(v) && !math.IsInf(v, 0) {
value = fmt.Sprintf("%f", v)
} else {
continue
}
case uint64:
value = strconv.FormatUint(v, 10)
case int64:
value = strconv.FormatInt(v, 10)
case bool:
if v {
value = "1"
} else {
value = "0"
}
default:
d.Log.Debugf("Dynatrace type not supported! %s", v)
continue
} }
}
// metric name typeOpt := getTypeOption(metricType, field)
metricKey, err := d.normalize(k, maxMetricKeyLen)
if err != nil { if typeOpt == nil {
continue // Unsupported type. Log only once per unsupported metric name
if !d.loggedMetrics[metricName] {
d.Log.Warnf("Unsupported type for %s", metricName)
d.loggedMetrics[metricName] = true
} }
continue
}
metricID, err := d.normalize(d.Prefix+metric.Name()+"."+metricKey, maxMetricKeyLen) name := tm.Name() + "." + field.Key
// write metric name combined with its field dm, err := dtMetric.NewMetric(
if err != nil { name,
continue dtMetric.WithPrefix(d.Prefix),
} dtMetric.WithDimensions(
// write metric id,tags and value dimensions.MergeLists(
// dimensions.NewNormalizedDimensionList(e.opts.DefaultDimensions...),
dimensions.NewNormalizedDimensionList(dims...),
),
),
typeOpt,
)
metricType := metric.Type() if err != nil {
for _, i := range d.AddCounterMetrics { d.Log.Warn(fmt.Sprintf("failed to normalize metric: %s - %s", name, err.Error()))
if metric.Name()+"."+metricKey == i { continue
metricType = telegraf.Counter }
}
}
switch metricType { line, err := dm.Serialize()
case telegraf.Counter:
var delta float64
// Check if LastValue exists if err != nil {
if lastvalue, ok := d.State[metricID+tagb.String()]; ok { d.Log.Warn(fmt.Sprintf("failed to serialize metric: %s - %s", name, err.Error()))
// Convert Strings to Floats continue
floatLastValue, err := strconv.ParseFloat(lastvalue, 32) }
if err != nil {
d.Log.Debugf("Could not parse last value: %s", lastvalue)
}
floatCurrentValue, err := strconv.ParseFloat(value, 32)
if err != nil {
d.Log.Debugf("Could not parse current value: %s", value)
}
if floatCurrentValue >= floatLastValue {
delta = floatCurrentValue - floatLastValue
fmt.Fprintf(&buf, "%s%s count,delta=%f\n", metricID, tagb.String(), delta)
}
}
d.State[metricID+tagb.String()] = value
default: lines = append(lines, line)
fmt.Fprintf(&buf, "%s%s %v\n", metricID, tagb.String(), value) }
} }
if metricCounter%dtIngestAPILineLimit == 0 { limit := apiconstants.GetPayloadLinesLimit()
err = d.send(buf.Bytes()) for i := 0; i < len(lines); i += limit {
if err != nil { batch := lines[i:min(i+limit, len(lines))]
return err
} output := strings.Join(batch, "\n")
buf.Reset() if output != "" {
} if err := d.send(output); err != nil {
metricCounter++ return fmt.Errorf("error processing data:, %s", err.Error())
} }
} }
} }
d.SendCounter++
// in typical interval of 10s, we will clean the counter state once in 24h which is 8640 iterations
if d.SendCounter%8640 == 0 { return nil
d.State = make(map[string]string)
}
return d.send(buf.Bytes())
} }
func (d *Dynatrace) send(msg []byte) error { func (d *Dynatrace) send(msg string) error {
var err error var err error
req, err := http.NewRequest("POST", d.URL, bytes.NewBuffer(msg)) req, err := http.NewRequest("POST", d.URL, bytes.NewBufferString(msg))
if err != nil { if err != nil {
d.Log.Errorf("Dynatrace error: %s", err.Error()) d.Log.Errorf("Dynatrace error: %s", err.Error())
return fmt.Errorf("error while creating HTTP request:, %s", err.Error()) return fmt.Errorf("error while creating HTTP request:, %s", err.Error())
@ -292,12 +215,11 @@ func (d *Dynatrace) send(msg []byte) error {
} }
func (d *Dynatrace) Init() error { func (d *Dynatrace) Init() error {
d.State = make(map[string]string)
if len(d.URL) == 0 { if len(d.URL) == 0 {
d.Log.Infof("Dynatrace URL is empty, defaulting to OneAgent metrics interface") d.Log.Infof("Dynatrace URL is empty, defaulting to OneAgent metrics interface")
d.URL = oneAgentMetricsURL d.URL = apiconstants.GetDefaultOneAgentEndpoint()
} }
if d.URL != oneAgentMetricsURL && len(d.APIToken) == 0 { if d.URL != apiconstants.GetDefaultOneAgentEndpoint() && len(d.APIToken) == 0 {
d.Log.Errorf("Dynatrace api_token is a required field for Dynatrace output") d.Log.Errorf("Dynatrace api_token is a required field for Dynatrace output")
return fmt.Errorf("api_token is a required field for Dynatrace output") return fmt.Errorf("api_token is a required field for Dynatrace output")
} }
@ -320,8 +242,45 @@ func (d *Dynatrace) Init() error {
func init() { func init() {
outputs.Add("dynatrace", func() telegraf.Output { outputs.Add("dynatrace", func() telegraf.Output {
return &Dynatrace{ return &Dynatrace{
Timeout: config.Duration(time.Second * 5), Timeout: config.Duration(time.Second * 5),
SendCounter: 0,
} }
}) })
} }
func getTypeOption(metricType telegraf.ValueType, field *telegraf.Field) dtMetric.MetricOption {
if metricType == telegraf.Counter {
switch v := field.Value.(type) {
case float64:
return dtMetric.WithFloatCounterValueTotal(v)
case uint64:
return dtMetric.WithIntCounterValueTotal(int64(v))
case int64:
return dtMetric.WithIntCounterValueTotal(v)
default:
return nil
}
}
switch v := field.Value.(type) {
case float64:
return dtMetric.WithFloatGaugeValue(v)
case uint64:
return dtMetric.WithIntGaugeValue(int64(v))
case int64:
return dtMetric.WithIntGaugeValue(32)
case bool:
if v {
return dtMetric.WithIntGaugeValue(1)
}
return dtMetric.WithIntGaugeValue(0)
}
return nil
}
func min(a, b int) int {
if a <= b {
return a
}
return b
}

View File

@ -5,9 +5,11 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"regexp"
"testing" "testing"
"time" "time"
"github.com/dynatrace-oss/dynatrace-metric-utils-go/metric/apiconstants"
"github.com/influxdata/telegraf" "github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config" "github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/metric" "github.com/influxdata/telegraf/metric"
@ -18,7 +20,8 @@ import (
func TestNilMetrics(t *testing.T) { func TestNilMetrics(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(`{"linesOk":10,"linesInvalid":0,"error":null}`) err := json.NewEncoder(w).Encode(`{"linesOk":10,"linesInvalid":0,"error":null}`)
require.NoError(t, err)
})) }))
defer ts.Close() defer ts.Close()
@ -42,7 +45,8 @@ func TestNilMetrics(t *testing.T) {
func TestEmptyMetricsSlice(t *testing.T) { func TestEmptyMetricsSlice(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(`{"linesOk":10,"linesInvalid":0,"error":null}`) err := json.NewEncoder(w).Encode(`{"linesOk":10,"linesInvalid":0,"error":null}`)
require.NoError(t, err)
})) }))
defer ts.Close() defer ts.Close()
@ -65,7 +69,8 @@ func TestEmptyMetricsSlice(t *testing.T) {
func TestMockURL(t *testing.T) { func TestMockURL(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(`{"linesOk":10,"linesInvalid":0,"error":null}`) err := json.NewEncoder(w).Encode(`{"linesOk":10,"linesInvalid":0,"error":null}`)
require.NoError(t, err)
})) }))
defer ts.Close() defer ts.Close()
@ -88,9 +93,10 @@ func TestMissingURL(t *testing.T) {
d.Log = testutil.Logger{} d.Log = testutil.Logger{}
err := d.Init() err := d.Init()
require.Equal(t, oneAgentMetricsURL, d.URL) require.NoError(t, err)
require.Equal(t, apiconstants.GetDefaultOneAgentEndpoint(), d.URL)
err = d.Connect() err = d.Connect()
require.Equal(t, oneAgentMetricsURL, d.URL) require.Equal(t, apiconstants.GetDefaultOneAgentEndpoint(), d.URL)
require.NoError(t, err) require.NoError(t, err)
} }
@ -99,9 +105,10 @@ func TestMissingAPITokenMissingURL(t *testing.T) {
d.Log = testutil.Logger{} d.Log = testutil.Logger{}
err := d.Init() err := d.Init()
require.Equal(t, oneAgentMetricsURL, d.URL) require.NoError(t, err)
require.Equal(t, apiconstants.GetDefaultOneAgentEndpoint(), d.URL)
err = d.Connect() err = d.Connect()
require.Equal(t, oneAgentMetricsURL, d.URL) require.Equal(t, apiconstants.GetDefaultOneAgentEndpoint(), d.URL)
require.NoError(t, err) require.NoError(t, err)
} }
@ -118,16 +125,15 @@ func TestSendMetric(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// check the encoded result // check the encoded result
bodyBytes, err := ioutil.ReadAll(r.Body) bodyBytes, err := ioutil.ReadAll(r.Body)
if err != nil { require.NoError(t, err)
require.NoError(t, err)
}
bodyString := string(bodyBytes) bodyString := string(bodyBytes)
expected := "mymeasurement.myfield,host=\"192.168.0.1\",nix=\"nix\" 3.140000\nmymeasurement.value,host=\"192.168.0.1\" 3.140000\n" expected := "mymeasurement.myfield,host=192.168.0.1 gauge,3.14\nmymeasurement.value,host=192.168.0.2 count,3.14"
if bodyString != expected { if bodyString != expected {
t.Errorf("Metric encoding failed. expected: %s but got: %s", expected, bodyString) t.Errorf("Metric encoding failed. expected: %#v but got: %#v", expected, bodyString)
} }
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(`{"linesOk":10,"linesInvalid":0,"error":null}`) err = json.NewEncoder(w).Encode(`{"linesOk":10,"linesInvalid":0,"error":null}`)
require.NoError(t, err)
})) }))
defer ts.Close() defer ts.Close()
@ -145,16 +151,17 @@ func TestSendMetric(t *testing.T) {
m1 := metric.New( m1 := metric.New(
"mymeasurement", "mymeasurement",
map[string]string{"host": "192.168.0.1", "nix": "nix"}, map[string]string{"host": "192.168.0.1"},
map[string]interface{}{"myfield": float64(3.14)}, map[string]interface{}{"myfield": float64(3.14)},
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC), time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
) )
m2 := metric.New( m2 := metric.New(
"mymeasurement", "mymeasurement",
map[string]string{"host": "192.168.0.1"}, map[string]string{"host": "192.168.0.2"},
map[string]interface{}{"value": float64(3.14)}, map[string]interface{}{"value": float64(3.14)},
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC), time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
telegraf.Counter,
) )
metrics := []telegraf.Metric{m1, m2} metrics := []telegraf.Metric{m1, m2}
@ -167,16 +174,16 @@ func TestSendSingleMetricWithUnorderedTags(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// check the encoded result // check the encoded result
bodyBytes, err := ioutil.ReadAll(r.Body) bodyBytes, err := ioutil.ReadAll(r.Body)
if err != nil { require.NoError(t, err)
require.NoError(t, err)
}
bodyString := string(bodyBytes) bodyString := string(bodyBytes)
expected := "mymeasurement.myfield,a=\"test\",b=\"test\",c=\"test\" 3.140000\n" require.Regexp(t, regexp.MustCompile(`^mymeasurement\.myfield`), bodyString)
if bodyString != expected { require.Regexp(t, regexp.MustCompile(`a=test`), bodyString)
t.Errorf("Metric encoding failed. expected: %s but got: %s", expected, bodyString) require.Regexp(t, regexp.MustCompile(`b=test`), bodyString)
} require.Regexp(t, regexp.MustCompile(`c=test`), bodyString)
require.Regexp(t, regexp.MustCompile(`gauge,3.14$`), bodyString)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(`{"linesOk":1,"linesInvalid":0,"error":null}`) err = json.NewEncoder(w).Encode(`{"linesOk":1,"linesInvalid":0,"error":null}`)
require.NoError(t, err)
})) }))
defer ts.Close() defer ts.Close()
@ -210,15 +217,14 @@ func TestSendMetricWithoutTags(t *testing.T) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
// check the encoded result // check the encoded result
bodyBytes, err := ioutil.ReadAll(r.Body) bodyBytes, err := ioutil.ReadAll(r.Body)
if err != nil { require.NoError(t, err)
require.NoError(t, err)
}
bodyString := string(bodyBytes) bodyString := string(bodyBytes)
expected := "mymeasurement.myfield 3.140000\n" expected := "mymeasurement.myfield gauge,3.14"
if bodyString != expected { if bodyString != expected {
t.Errorf("Metric encoding failed. expected: %s but got: %s", expected, bodyString) t.Errorf("Metric encoding failed. expected: %#v but got: %#v", expected, bodyString)
} }
json.NewEncoder(w).Encode(`{"linesOk":1,"linesInvalid":0,"error":null}`) err = json.NewEncoder(w).Encode(`{"linesOk":1,"linesInvalid":0,"error":null}`)
require.NoError(t, err)
})) }))
defer ts.Close() defer ts.Close()
@ -252,15 +258,19 @@ func TestSendMetricWithUpperCaseTagKeys(t *testing.T) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
// check the encoded result // check the encoded result
bodyBytes, err := ioutil.ReadAll(r.Body) bodyBytes, err := ioutil.ReadAll(r.Body)
if err != nil { require.NoError(t, err)
require.NoError(t, err)
}
bodyString := string(bodyBytes) bodyString := string(bodyBytes)
expected := "mymeasurement.myfield,aaa=\"test\",b_b=\"test\",ccc=\"test\" 3.140000\n"
if bodyString != expected { // expected := "mymeasurement.myfield,b_b=test,ccc=test,aaa=test gauge,3.14"
t.Errorf("Metric encoding failed. expected: %s but got: %s", expected, bodyString) // use regex because dimension order isn't guaranteed
} require.Regexp(t, regexp.MustCompile(`^mymeasurement\.myfield`), bodyString)
json.NewEncoder(w).Encode(`{"linesOk":1,"linesInvalid":0,"error":null}`) require.Regexp(t, regexp.MustCompile(`aaa=test`), bodyString)
require.Regexp(t, regexp.MustCompile(`b_b=test`), bodyString)
require.Regexp(t, regexp.MustCompile(`ccc=test`), bodyString)
require.Regexp(t, regexp.MustCompile(`gauge,3.14$`), bodyString)
err = json.NewEncoder(w).Encode(`{"linesOk":1,"linesInvalid":0,"error":null}`)
require.NoError(t, err)
})) }))
defer ts.Close() defer ts.Close()
@ -294,15 +304,13 @@ func TestSendBooleanMetricWithoutTags(t *testing.T) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
// check the encoded result // check the encoded result
bodyBytes, err := ioutil.ReadAll(r.Body) bodyBytes, err := ioutil.ReadAll(r.Body)
if err != nil { require.NoError(t, err)
require.NoError(t, err)
}
bodyString := string(bodyBytes) bodyString := string(bodyBytes)
expected := "mymeasurement.myfield 1\n" // use regex because field order isn't guaranteed
if bodyString != expected { require.Contains(t, bodyString, "mymeasurement.yes gauge,1")
t.Errorf("Metric encoding failed. expected: %s but got: %s", expected, bodyString) require.Contains(t, bodyString, "mymeasurement.no gauge,0")
} err = json.NewEncoder(w).Encode(`{"linesOk":1,"linesInvalid":0,"error":null}`)
json.NewEncoder(w).Encode(`{"linesOk":1,"linesInvalid":0,"error":null}`) require.NoError(t, err)
})) }))
defer ts.Close() defer ts.Close()
@ -321,7 +329,48 @@ func TestSendBooleanMetricWithoutTags(t *testing.T) {
m1 := metric.New( m1 := metric.New(
"mymeasurement", "mymeasurement",
map[string]string{}, map[string]string{},
map[string]interface{}{"myfield": bool(true)}, map[string]interface{}{"yes": true, "no": false},
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
)
metrics := []telegraf.Metric{m1}
err = d.Write(metrics)
require.NoError(t, err)
}
func TestSendCounterMetricWithoutTags(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
// check the encoded result
bodyBytes, err := ioutil.ReadAll(r.Body)
require.NoError(t, err)
bodyString := string(bodyBytes)
expected := "mymeasurement.value gauge,32"
if bodyString != expected {
t.Errorf("Metric encoding failed. expected: %#v but got: %#v", expected, bodyString)
}
err = json.NewEncoder(w).Encode(`{"linesOk":1,"linesInvalid":0,"error":null}`)
require.NoError(t, err)
}))
defer ts.Close()
d := &Dynatrace{}
d.URL = ts.URL
d.APIToken = "123"
d.Log = testutil.Logger{}
err := d.Init()
require.NoError(t, err)
err = d.Connect()
require.NoError(t, err)
// Init metrics
m1 := metric.New(
"mymeasurement",
map[string]string{},
map[string]interface{}{"value": 32},
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC), time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
) )