From ae443e6c86640a5aabbdc0c4f6f5d9a1df54aba3 Mon Sep 17 00:00:00 2001 From: Sam Park Date: Sun, 10 Feb 2019 14:16:50 -0800 Subject: [PATCH] Add support for Datadog APM tracing Addresses #188 --- weaver/Gopkg.lock | 125 +++++++++++++++++++++++++++++++++++++++-- weaver/Gopkg.toml | 8 +++ weaver/README.md | 2 + weaver/conf/sample.env | 4 ++ weaver/config.go | 31 +++++++--- weaver/config_test.go | 33 +++++++++++ weaver/main.go | 15 +++++ 7 files changed, 204 insertions(+), 14 deletions(-) create mode 100644 weaver/config_test.go diff --git a/weaver/Gopkg.lock b/weaver/Gopkg.lock index 3924606c..4711fdda 100644 --- a/weaver/Gopkg.lock +++ b/weaver/Gopkg.lock @@ -3,11 +3,14 @@ [[projects]] branch = "master" + digest = "1:b763ac7907021d7c87885dd299ae8b57015243f179493b274b3b9af808ecbdcc" name = "github.com/DeanThompson/ginpprof" packages = ["."] + pruneopts = "UT" revision = "8c0e31bfeaa87bd40412ee8a8ba383f5f700ff72" [[projects]] + digest = "1:25788ec126112bf7185f47fae06705d5f9734899dd0a99590849750520e3cae4" name = "github.com/aws/aws-sdk-go" packages = [ "aws", @@ -39,102 +42,175 @@ "private/protocol/restxml", "private/protocol/xml/xmlutil", "service/s3", - "service/sts" + "service/sts", ] + pruneopts = "UT" revision = "fde4ded7becdeae4d26bf1212916aabba79349b4" version = "v1.14.12" [[projects]] + digest = "1:fed1f537c2f1269fe475a8556c393fe466641682d73ef8fd0491cd3aa1e47bad" name = "github.com/certifi/gocertifi" packages = ["."] + pruneopts = "UT" revision = "deb3ae2ef2610fde3330947281941c562861188b" version = "2018.01.18" +[[projects]] + digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" + name = "github.com/davecgh/go-spew" + packages = ["spew"] + pruneopts = "UT" + revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" + version = "v1.1.1" + [[projects]] branch = "master" + digest = "1:d4623fc7bf7e281d9107367cc4a9e76ed3e86b1eec1a4e30630c870bef1fedd0" name = "github.com/getsentry/raven-go" packages = ["."] + pruneopts = "UT" revision = "ed7bcb39ff10f39ab08e317ce16df282845852fa" [[projects]] branch = "master" + digest = "1:36fe9527deed01d2a317617e59304eb2c4ce9f8a24115bcc5c2e37b3aee5bae4" name = "github.com/gin-contrib/sse" packages = ["."] + pruneopts = "UT" revision = "22d885f9ecc78bf4ee5d72b937e4bbcdc58e8cae" [[projects]] branch = "master" + digest = "1:2fbf382837f438b617a8fa20c588303626eb032d85be49eece4827276889a9db" name = "github.com/gin-gonic/contrib" packages = ["sentry"] + pruneopts = "UT" revision = "39cfb9727134fef3120d2458fce5fab14265a46c" [[projects]] + digest = "1:489e108f21464371ebf9cb5c30b1eceb07c6dd772dff073919267493dd9d04ea" name = "github.com/gin-gonic/gin" packages = [ ".", "binding", - "render" + "render", ] + pruneopts = "UT" revision = "d459835d2b077e44f7c9b453505ee29881d5d12d" version = "v1.2" [[projects]] + digest = "1:fb46255681497314debedde38b64be32a75bae50bad107586c22f1662bf2d352" name = "github.com/go-ini/ini" packages = ["."] + pruneopts = "UT" revision = "06f5f3d67269ccec1fe5fe4134ba6e982984f7f5" version = "v1.37.0" [[projects]] + digest = "1:15042ad3498153684d09f393bbaec6b216c8eec6d61f63dff711de7d64ed8861" name = "github.com/golang/protobuf" packages = ["proto"] + pruneopts = "UT" revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" version = "v1.1.0" [[projects]] + digest = "1:e22af8c7518e1eab6f2eab2b7d7558927f816262586cd6ed9f349c97a6c285c4" name = "github.com/jmespath/go-jmespath" packages = ["."] + pruneopts = "UT" revision = "0b12d6b5" [[projects]] + digest = "1:d4d17353dbd05cb52a2a52b7fe1771883b682806f68db442b436294926bbfafb" name = "github.com/mattn/go-isatty" packages = ["."] + pruneopts = "UT" revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" version = "v0.0.3" [[projects]] + digest = "1:5e73b34a27d827212102605789de00bd411b2e434812133c83935fe9897c75e1" + name = "github.com/philhofer/fwd" + packages = ["."] + pruneopts = "UT" + revision = "bb6d471dc95d4fe11e432687f8b70ff496cf3136" + version = "v1.0.0" + +[[projects]] + digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747" name = "github.com/pkg/errors" packages = ["."] + pruneopts = "UT" revision = "645ef00459ed84a119197bfb8d8205042c6df63d" version = "v0.8.0" [[projects]] + digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + pruneopts = "UT" + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + digest = "1:274f67cb6fed9588ea2521ecdac05a6d62a8c51c074c1fccc6a49a40ba80e925" name = "github.com/satori/go.uuid" packages = ["."] + pruneopts = "UT" revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3" version = "v1.2.0" [[projects]] + digest = "1:972c2427413d41a1e06ca4897e8528e5a1622894050e2f527b38ddf0f343f759" + name = "github.com/stretchr/testify" + packages = ["assert"] + pruneopts = "UT" + revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053" + version = "v1.3.0" + +[[projects]] + digest = "1:c97e8a5e5c435c3287f581cdb4441ba34577ec6ead8422bfedafa6269af7abf6" + name = "github.com/tinylib/msgp" + packages = ["msgp"] + pruneopts = "UT" + revision = "af6442a0fcf6e2a1b824f70dd0c734f01e817751" + version = "v1.1.0" + +[[projects]] + digest = "1:03aa6e485e528acb119fb32901cf99582c380225fc7d5a02758e08b180cb56c3" name = "github.com/ugorji/go" packages = ["codec"] + pruneopts = "UT" revision = "b4c50a2b199d93b13dc15e78929cfb23bfdf21ab" version = "v1.1.1" [[projects]] branch = "master" + digest = "1:b59ffa4187993e394496e784dee33e2f80c7404d363b2d704173cc3f2656581b" name = "golang.org/x/net" packages = [ "idna", - "publicsuffix" + "publicsuffix", ] + pruneopts = "UT" revision = "afe8f62b1d6bbd81f31868121a50b06d8188e1f9" [[projects]] branch = "master" + digest = "1:c1fee1a2c739c7b220dc3de939f659dce271fa8d9de155cb8cfcfb99c941cbc3" name = "golang.org/x/sys" - packages = ["unix"] + packages = [ + "unix", + "windows", + ] + pruneopts = "UT" revision = "63fc586f45fe72d95d5240a5d5eb95e6503907d3" [[projects]] + digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" name = "golang.org/x/text" packages = [ "collate", @@ -150,32 +226,69 @@ "unicode/bidi", "unicode/cldr", "unicode/norm", - "unicode/rangetable" + "unicode/rangetable", ] + pruneopts = "UT" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] + digest = "1:3e393cbb715b3f1f7e0e2bbfe1d96a7233a0bb42ef0c98958d8445e0e101c39c" + name = "gopkg.in/DataDog/dd-trace-go.v1" + packages = [ + "contrib/gin-gonic/gin", + "ddtrace", + "ddtrace/ext", + "ddtrace/internal", + "ddtrace/tracer", + ] + pruneopts = "UT" + revision = "823d51722f66a748804943f6fa6be18776073b82" + version = "v1.9.0" + +[[projects]] + digest = "1:38b469493eb173db9c03321d64adcad4c7991ea0a19b5edc5bdc094f0e8c7384" name = "gopkg.in/alexcesaro/statsd.v2" packages = ["."] + pruneopts = "UT" revision = "7fea3f0d2fab1ad973e641e51dba45443a311a90" version = "v2.0.0" [[projects]] + digest = "1:cbc72c4c4886a918d6ab4b95e347ffe259846260f99ebdd8a198c2331cf2b2e9" name = "gopkg.in/go-playground/validator.v8" packages = ["."] + pruneopts = "UT" revision = "5f1438d3fca68893a817e4a66806cea46a9e4ebf" version = "v8.18.2" [[projects]] + digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202" name = "gopkg.in/yaml.v2" packages = ["."] + pruneopts = "UT" revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" version = "v2.2.1" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "76a58c3e480e34d3a82673a7f888aabb1a6edeb541f77bcfd43c80e5558ccc71" + input-imports = [ + "github.com/DeanThompson/ginpprof", + "github.com/aws/aws-sdk-go/aws", + "github.com/aws/aws-sdk-go/aws/awserr", + "github.com/aws/aws-sdk-go/aws/awsutil", + "github.com/aws/aws-sdk-go/aws/credentials", + "github.com/aws/aws-sdk-go/aws/session", + "github.com/aws/aws-sdk-go/service/s3", + "github.com/getsentry/raven-go", + "github.com/gin-gonic/contrib/sentry", + "github.com/gin-gonic/gin", + "github.com/satori/go.uuid", + "github.com/stretchr/testify/assert", + "golang.org/x/net/publicsuffix", + "gopkg.in/DataDog/dd-trace-go.v1/contrib/gin-gonic/gin", + "gopkg.in/alexcesaro/statsd.v2", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/weaver/Gopkg.toml b/weaver/Gopkg.toml index 8d5a8e92..6c8dc265 100644 --- a/weaver/Gopkg.toml +++ b/weaver/Gopkg.toml @@ -57,6 +57,14 @@ name = "gopkg.in/alexcesaro/statsd.v2" version = "2.0.0" +[[constraint]] + name = "github.com/stretchr/testify" + version = "1.3.0" + [prune] go-tests = true unused-packages = true + +[[constraint]] + name = "gopkg.in/DataDog/dd-trace-go.v1" + version = "1.9.0" diff --git a/weaver/README.md b/weaver/README.md index 1c7fa599..1470f6f2 100644 --- a/weaver/README.md +++ b/weaver/README.md @@ -26,6 +26,7 @@ Although it was predominantly designed for generating a PDF from a HTML using [` - Strong service visibility for quality control: - Metrics collection ([statsd]) - Error logging ([Sentry][sentry]) + - APM ([Datadog APM][ddapm]) - Dockerized: - Easy to set up, distribute, and deploy - Runs in headless mode (the display server is handled for you) @@ -52,3 +53,4 @@ See [`docs/building.md`](docs/building.md). [cloudconvert]: https://cloudconvert.com/ [statsd]: https://github.com/etsy/statsd [sentry]: https://getsentry.com/ +[ddapm]: https://www.datadoghq.com/apm/ diff --git a/weaver/conf/sample.env b/weaver/conf/sample.env index d76354d8..d2c05187 100644 --- a/weaver/conf/sample.env +++ b/weaver/conf/sample.env @@ -17,3 +17,7 @@ WEAVER_CONVERSION_FALLBACK=false # STATSD_ADDRESS= # STATSD_PREFIX= # SENTRY_DSN= + +# Datadog APM tracing +# DATADOG_AGENT_ADDRESS= +# DATADOG_APM_SERVICE_NAME= diff --git a/weaver/config.go b/weaver/config.go index 361f79ba..cbea26ac 100644 --- a/weaver/config.go +++ b/weaver/config.go @@ -67,6 +67,12 @@ type Config struct { // The data source name (DSN) for a Sentry server (used for logging errors). // Defaults to none. SentryDSN string + // Hostname (and port) for reporting Datadog APM traces. + // Defaults to none (no trace reporting). + DatadogAgentAddress string + // Service name to report to Datadog APM + // DEfaults to "weaver" + DatadogAPMServiceName string } // NewEnvConfig initialises configuration variables from the environment. @@ -74,14 +80,15 @@ func NewEnvConfig() Config { // Set defaults cloudconvert := CloudConvert{APIUrl: "https://api.cloudconvert.com"} conf := Config{ - CloudConvert: cloudconvert, - HTTPAddr: ":8080", - AuthKey: "arachnys-weaver", - AthenaCMD: "athenapdf -S", - MaxWorkers: 10, - MaxConversionQueue: 50, - WorkerTimeout: 90, - ConversionFallback: false, + CloudConvert: cloudconvert, + HTTPAddr: ":8080", + AuthKey: "arachnys-weaver", + AthenaCMD: "athenapdf -S", + MaxWorkers: 10, + MaxConversionQueue: 50, + WorkerTimeout: 90, + ConversionFallback: false, + DatadogAPMServiceName: "weaver", } if httpAddr := os.Getenv("WEAVER_HTTP_ADDR"); httpAddr != "" { @@ -145,5 +152,13 @@ func NewEnvConfig() Config { conf.SentryDSN = sentryDSN } + if datadogAgentAddress := os.Getenv("DATADOG_AGENT_ADDRESS"); datadogAgentAddress != "" { + conf.DatadogAgentAddress = datadogAgentAddress + } + + if datadogAPMServiceName := os.Getenv("DATADOG_APM_SERVICE_NAME"); datadogAPMServiceName != "" { + conf.DatadogAPMServiceName = datadogAPMServiceName + } + return conf } diff --git a/weaver/config_test.go b/weaver/config_test.go new file mode 100644 index 00000000..97bbc3c2 --- /dev/null +++ b/weaver/config_test.go @@ -0,0 +1,33 @@ +package main + +import ( + "github.com/stretchr/testify/assert" + "os" + "testing" +) + +func TestNewEnvConfig(t *testing.T) { + t.Run("Datadog Agent Address", func(t *testing.T) { + c := NewEnvConfig() + assert.Equal(t, "", c.DatadogAgentAddress) + + expectValue := "123qweasdzxc:12312" + err := os.Setenv("DATADOG_AGENT_ADDRESS", expectValue) + assert.Nil(t, err) + + c = NewEnvConfig() + assert.Equal(t, expectValue, c.DatadogAgentAddress) + }) + + t.Run("Datadog APM Service Name", func(t *testing.T) { + c := NewEnvConfig() + assert.Equal(t, "weaver", c.DatadogAPMServiceName) + + expectValue := "12o38y27345987234695thekgjr" + err := os.Setenv("DATADOG_APM_SERVICE_NAME", expectValue) + assert.Nil(t, err) + + c = NewEnvConfig() + assert.Equal(t, expectValue, c.DatadogAPMServiceName) + }) +} diff --git a/weaver/main.go b/weaver/main.go index 1a8804df..cc10920a 100644 --- a/weaver/main.go +++ b/weaver/main.go @@ -7,6 +7,8 @@ import ( "github.com/getsentry/raven-go" "github.com/gin-gonic/contrib/sentry" "github.com/gin-gonic/gin" + gintrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/gin-gonic/gin" + "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" "gopkg.in/alexcesaro/statsd.v2" "log" "net/http" @@ -58,6 +60,11 @@ func InitMiddleware(router *gin.Engine, conf Config) { router.Use(sentry.Recovery(r, true)) } + // Datadog APM + if conf.DatadogAgentAddress != "" { + router.Use(gintrace.Middleware(conf.DatadogAPMServiceName)) + } + // Error handler router.Use(ErrorMiddleware()) } @@ -99,6 +106,14 @@ func main() { InitSecureRoutes(router, conf) InitSimpleRoutes(router, conf) + if conf.DatadogAgentAddress != "" { + tracer.Start( + tracer.WithAgentAddr(conf.DatadogAgentAddress), + tracer.WithServiceName(conf.DatadogAPMServiceName), + ) + defer tracer.Stop() + } + if conf.HTTPSAddr != "" { if conf.TLSCertFile == "" { log.Fatal("No TLS cert file provided (WEAVER_TLS_CERT_FILE)")