Skip to content

Commit 1a8ff40

Browse files
Add error_message field to bundle deploy telemetry
Track the first error diagnostic summary encountered during bundle deploy in telemetry. Move telemetry logging into a defer so it's always captured, even when deploy fails. Co-authored-by: Isaac
1 parent 1560aae commit 1a8ff40

File tree

5 files changed

+41
-6
lines changed

5 files changed

+41
-6
lines changed

bundle/phases/deploy.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,6 @@ func Deploy(ctx context.Context, b *bundle.Bundle, outputHandler sync.OutputHand
208208
return
209209
}
210210

211-
logDeployTelemetry(ctx, b)
212211
bundle.ApplyContext(ctx, b, scripts.Execute(config.ScriptPostDeploy))
213212
}
214213

bundle/phases/telemetry.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ func getExecutionTimes(b *bundle.Bundle) []protos.IntMapEntry {
3333
return executionTimes
3434
}
3535

36-
func logDeployTelemetry(ctx context.Context, b *bundle.Bundle) {
36+
// LogDeployTelemetry logs a telemetry event for a bundle deploy command.
37+
func LogDeployTelemetry(ctx context.Context, b *bundle.Bundle, errMsg string) {
3738
resourcesCount := int64(0)
3839
_, err := dyn.MapByPattern(b.Config.Value(), dyn.NewPattern(dyn.Key("resources"), dyn.AnyKey(), dyn.AnyKey()), func(p dyn.Path, v dyn.Value) (dyn.Value, error) {
3940
resourcesCount++
@@ -149,6 +150,7 @@ func logDeployTelemetry(ctx context.Context, b *bundle.Bundle) {
149150
BundleDeployEvent: &protos.BundleDeployEvent{
150151
BundleUuid: bundleUuid,
151152
DeploymentId: b.Metrics.DeploymentId.String(),
153+
ErrorMessage: errMsg,
152154

153155
ResourceCount: resourcesCount,
154156
ResourceJobCount: int64(len(b.Config.Resources.Jobs)),

cmd/bundle/utils/process.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func ProcessBundle(cmd *cobra.Command, opts ProcessOptions) (*bundle.Bundle, err
8080
return b, err
8181
}
8282

83-
func ProcessBundleRet(cmd *cobra.Command, opts ProcessOptions) (*bundle.Bundle, *statemgmt.StateDesc, error) {
83+
func ProcessBundleRet(cmd *cobra.Command, opts ProcessOptions) (b *bundle.Bundle, stateDesc *statemgmt.StateDesc, retErr error) {
8484
var err error
8585
ctx := cmd.Context()
8686
if opts.SkipInitContext {
@@ -93,7 +93,24 @@ func ProcessBundleRet(cmd *cobra.Command, opts ProcessOptions) (*bundle.Bundle,
9393
}
9494

9595
// Load bundle config and apply target
96-
b := root.MustConfigureBundle(cmd)
96+
b = root.MustConfigureBundle(cmd)
97+
98+
// Log deploy telemetry on all exit paths. This is a defer to ensure
99+
// telemetry is logged even when the deploy command fails, for both
100+
// diagnostic errors and regular Go errors.
101+
if opts.Deploy {
102+
defer func() {
103+
if b == nil {
104+
return
105+
}
106+
errMsg := logdiag.GetFirstErrorSummary(ctx)
107+
if errMsg == "" && retErr != nil && !errors.Is(retErr, root.ErrAlreadyPrinted) {
108+
errMsg = retErr.Error()
109+
}
110+
phases.LogDeployTelemetry(ctx, b, errMsg)
111+
}()
112+
}
113+
97114
if logdiag.HasError(ctx) {
98115
return b, nil, root.ErrAlreadyPrinted
99116
}
@@ -147,8 +164,6 @@ func ProcessBundleRet(cmd *cobra.Command, opts ProcessOptions) (*bundle.Bundle,
147164
}
148165
}
149166

150-
var stateDesc *statemgmt.StateDesc
151-
152167
shouldReadState := opts.ReadState || opts.AlwaysPull || opts.InitIDs || opts.ErrorOnEmptyState || opts.PreDeployChecks || opts.Deploy || opts.ReadPlanPath != ""
153168

154169
if shouldReadState {

libs/logdiag/logdiag.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ type LogDiagData struct {
3030
// If Collect is true, diagnostics are appended to Collected. Use SetCollected() to set.
3131
Collect bool
3232
Collected []diag.Diagnostic
33+
34+
// Summary of the first error diagnostic logged, if any.
35+
FirstErrorSummary string
3336
}
3437

3538
// IsSetup returns whether InitContext() was already called.
@@ -117,6 +120,16 @@ func FlushCollected(ctx context.Context) diag.Diagnostics {
117120
return result
118121
}
119122

123+
// GetFirstErrorSummary returns the summary of the first error diagnostic
124+
// logged, or an empty string if no errors have been logged.
125+
func GetFirstErrorSummary(ctx context.Context) string {
126+
val := read(ctx)
127+
val.mu.Lock()
128+
defer val.mu.Unlock()
129+
130+
return val.FirstErrorSummary
131+
}
132+
120133
func LogDiag(ctx context.Context, d diag.Diagnostic) {
121134
val := read(ctx)
122135
val.mu.Lock()
@@ -125,6 +138,9 @@ func LogDiag(ctx context.Context, d diag.Diagnostic) {
125138
switch d.Severity {
126139
case diag.Error:
127140
val.Errors += 1
141+
if val.FirstErrorSummary == "" {
142+
val.FirstErrorSummary = d.Summary
143+
}
128144
case diag.Warning:
129145
val.Warnings += 1
130146
case diag.Recommendation:

libs/telemetry/protos/bundle_deploy.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ type BundleDeployEvent struct {
77
// UUID associated with the deployment.
88
DeploymentId string `json:"deployment_id,omitempty"`
99

10+
// Error message encountered during the bundle deploy command, if any.
11+
ErrorMessage string `json:"error_message,omitempty"`
12+
1013
ResourceCount int64 `json:"resource_count"`
1114
ResourceJobCount int64 `json:"resource_job_count"`
1215
ResourcePipelineCount int64 `json:"resource_pipeline_count"`

0 commit comments

Comments
 (0)