Adds OpenTracing in the Pulumi engine and plugin + langhost subprocesses. We currently create a single root span for any `Enging.plan` operation - which is a single `preview`, `update`, `destroy`, etc. The only sub-spans we currently create are at gRPC boundaries, both on the client and server sides and on both the langhost and provider plugin interfaces. We could extend this to include spans for any other semantically meaningful sections of compute inside the engine, though initial examples show we get pretty good granularity of coverage by focusing on the gRPC boundaries. In the future, this should be easily extensible to HTTP boundaries and to track other bulky I/O like datastore read/writes once we hook up to the PPC and Pulumi Cloud. We expose a `--trace <endpoint>` option to enable tracing on the CLI, which we will aim to thread through to subprocesses. We currently support sending tracing data to a Zipkin-compatible endpoint. This has been validated with both Zipkin and Jaeger UIs. We do not yet have any tracing inside the TypeScript side of the JS langhost RPC interface. There is not yet automatic gRPC OpenTracing instrumentation (though it looks like it's in progress now) - so we would need to manually create meaningful spans on that side of the interface.
59 lines
1.5 KiB
Go
59 lines
1.5 KiB
Go
package cmdutil
|
|
|
|
import (
|
|
"io"
|
|
"log"
|
|
|
|
opentracing "github.com/opentracing/opentracing-go"
|
|
"github.com/pulumi/pulumi/pkg/util/contract"
|
|
jaeger "github.com/uber/jaeger-client-go"
|
|
"github.com/uber/jaeger-client-go/transport/zipkin"
|
|
)
|
|
|
|
// TracingEndpoint is the Zipkin-compatible tracing endpoint where tracing data will be sent.
|
|
var TracingEndpoint string
|
|
|
|
var traceCloser io.Closer
|
|
|
|
// InitTracing initializes tracing
|
|
func InitTracing(name string, tracingEndpoint string) {
|
|
|
|
// Store the tracing endpoint
|
|
TracingEndpoint = tracingEndpoint
|
|
|
|
// Create a reporter
|
|
var reporter jaeger.Reporter
|
|
if tracingEndpoint == "" {
|
|
reporter = jaeger.NewInMemoryReporter()
|
|
} else {
|
|
// Jaeger tracer can be initialized with a transport that will
|
|
// report tracing Spans to a Zipkin backend
|
|
transport, err := zipkin.NewHTTPTransport(
|
|
tracingEndpoint,
|
|
zipkin.HTTPBatchSize(1),
|
|
zipkin.HTTPLogger(jaeger.StdLogger),
|
|
)
|
|
if err != nil {
|
|
log.Fatalf("Cannot initialize HTTP transport: %v", err)
|
|
}
|
|
reporter = jaeger.NewRemoteReporter(transport)
|
|
}
|
|
|
|
// create Jaeger tracer
|
|
tracer, closer := jaeger.NewTracer(
|
|
name,
|
|
jaeger.NewConstSampler(true), // sample all traces
|
|
reporter,
|
|
)
|
|
|
|
// Store the closer so that we can flush the Jaeger span cache on process exit
|
|
traceCloser = closer
|
|
|
|
// Set the ambient tracer
|
|
opentracing.SetGlobalTracer(tracer)
|
|
}
|
|
|
|
// CloseTracing ensures that all pending spans have been flushed. It should be called before process exit.
|
|
func CloseTracing() {
|
|
contract.IgnoreClose(traceCloser)
|
|
}
|