pulumi/pkg/engine/preview.go
Luke Hoban af5298f4aa
Initial work on tracing support (#521)
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.
2017-11-08 17:08:51 -08:00

68 lines
2.3 KiB
Go

// Copyright 2017, Pulumi Corporation. All rights reserved.
package engine
import (
"github.com/pkg/errors"
"github.com/pulumi/pulumi/pkg/diag"
"github.com/pulumi/pulumi/pkg/tokens"
"github.com/pulumi/pulumi/pkg/util/contract"
)
type PreviewOptions struct {
Package string // the package to compute the preview for
Analyzers []string // an optional set of analyzers to run as part of this deployment.
Parallel int // the degree of parallelism for resource operations (<=1 for serial).
ShowConfig bool // true to show the configuration variables being used.
ShowReplacementSteps bool // true to show the replacement steps in the plan.
ShowSames bool // true to show the resources that aren't updated, in addition to those that are.
Summary bool // true if we should only summarize resources and operations.
}
func (eng *Engine) Preview(stack tokens.QName, events chan<- Event, opts PreviewOptions) error {
contract.Require(stack != tokens.QName(""), "stack")
contract.Require(events != nil, "events")
defer func() { events <- cancelEvent() }()
info, err := eng.planContextFromStack(stack, opts.Package)
if err != nil {
return err
}
defer info.Close()
return eng.previewLatest(info, deployOptions{
Destroy: false,
DryRun: true,
Analyzers: opts.Analyzers,
Parallel: opts.Parallel,
ShowConfig: opts.ShowConfig,
ShowReplacementSteps: opts.ShowReplacementSteps,
ShowSames: opts.ShowSames,
Summary: opts.Summary,
Events: events,
Diag: newEventSink(events, diag.FormatOptions{
Colors: true,
}),
})
}
func (eng *Engine) previewLatest(info *planContext, opts deployOptions) error {
result, err := eng.plan(info, opts)
if err != nil {
return err
}
if result != nil {
defer contract.IgnoreClose(result)
if err := eng.printPlan(result); err != nil {
return err
}
}
if !opts.Diag.Success() {
// If any error occurred while walking the plan, be sure to let the developer know. Otherwise,
// although error messages may have spewed to the output, the final lines of the plan may look fine.
return errors.New("One or more errors occurred during the creation of this preview")
}
return nil
}