@@ -1327,22 +1327,17 @@ func (ex *connExecutor) closeWrapper(ctx context.Context, recovered interface{})
1327
1327
if recovered != nil {
1328
1328
panicErr := logcrash .PanicAsError (1 , recovered )
1329
1329
1330
- // If there's a statement currently being executed, we'll report
1331
- // on it.
1332
1330
if ex .curStmtAST != nil {
1333
1331
// A warning header guaranteed to go to stderr.
1334
1332
log .SqlExec .Shoutf (ctx , severity .ERROR ,
1335
1333
"a SQL panic has occurred while executing the following statement:\n %s" ,
1336
1334
// For the log message, the statement is not anonymized.
1337
1335
truncateStatementStringForTelemetry (ex .curStmtAST .String ()))
1338
-
1339
- // Embed the statement in the error object for the telemetry
1340
- // report below. The statement gets anonymized.
1341
- vt := ex .planner .extendedEvalCtx .VirtualSchemas
1342
- panicErr = WithAnonymizedStatement (panicErr , ex .curStmtAST , vt )
1343
1336
}
1344
1337
1345
- // Report the panic to telemetry in any case.
1338
+ // Report the panic to telemetry, annotating the error with the (anonymized)
1339
+ // currently executed statement and its plan gist, if available.
1340
+ panicErr = ex .WithAnonymizedStatementAndGist (panicErr )
1346
1341
logcrash .ReportPanic (ctx , & ex .server .cfg .Settings .SV , panicErr , 1 /* depth */ )
1347
1342
1348
1343
// Close the executor before propagating the panic further.
@@ -1846,9 +1841,13 @@ type connExecutor struct {
1846
1841
}
1847
1842
1848
1843
// curStmtAST is the statement that's currently being prepared or executed, if
1849
- // any. This is printed by high-level panic recovery.
1844
+ // any. This is printed by high-level panic recovery and sentry reports .
1850
1845
curStmtAST tree.Statement
1851
1846
1847
+ // curStmtPlanGist is the plan gist of the statement that's currently being
1848
+ // prepared or executed, if any. This is included in sentry reports.
1849
+ curStmtPlanGist redact.SafeString
1850
+
1852
1851
// queryCancelKey is a 64-bit identifier for the session used by the
1853
1852
// pgwire cancellation protocol.
1854
1853
queryCancelKey pgwirecancel.BackendKeyData
@@ -2279,6 +2278,7 @@ func (ex *connExecutor) run(
2279
2278
2280
2279
for {
2281
2280
ex .curStmtAST = nil
2281
+ ex .curStmtPlanGist = ""
2282
2282
if err := ctx .Err (); err != nil {
2283
2283
return err
2284
2284
}
@@ -2670,9 +2670,17 @@ func (ex *connExecutor) execCmd() (retErr error) {
2670
2670
if ok {
2671
2671
ex .sessionEventf (ctx , "execution error: %s" , pe .errorCause ())
2672
2672
if resErr == nil {
2673
- res .SetError (pe .errorCause ())
2673
+ resErr = pe .errorCause ()
2674
+ res .SetError (resErr )
2674
2675
}
2675
2676
}
2677
+ if resErr != nil &&
2678
+ (pgerror .GetPGCode (resErr ) == pgcode .Internal || errors .HasAssertionFailure (resErr )) {
2679
+ // This is an assertion failure / crash that will lead to a sentry report.
2680
+ // Attempt to annotate the error with the currently executing statement
2681
+ // and its plan gist.
2682
+ res .SetError (ex .WithAnonymizedStatementAndGist (resErr ))
2683
+ }
2676
2684
// For a pausable portal, we don't log the affected rows until we close the
2677
2685
// portal. However, we update the result for each execution. Thus, we need
2678
2686
// to accumulate the number of affected rows before closing the result.
@@ -4091,7 +4099,8 @@ func (ex *connExecutor) txnStateTransitionsApplyWrapper(
4091
4099
errors .Safe (advInfo .txnEvent .eventType .String ()),
4092
4100
res .Err ())
4093
4101
log .Dev .Errorf (ex .Ctx (), "%v" , err )
4094
- sentryutil .SendReport (ex .Ctx (), & ex .server .cfg .Settings .SV , err )
4102
+ sentryErr := ex .WithAnonymizedStatementAndGist (err )
4103
+ sentryutil .SendReport (ex .Ctx (), & ex .server .cfg .Settings .SV , sentryErr )
4095
4104
return advanceInfo {}, err
4096
4105
}
4097
4106
@@ -4889,6 +4898,22 @@ func (ps connExPrepStmtsAccessor) DeleteAll(ctx context.Context) {
4889
4898
)
4890
4899
}
4891
4900
4901
+ // WithAnonymizedStatementAndGist attaches the anonymized form of the currently
4902
+ // executing statement and its query plan gist to an error object, if available.
4903
+ // It can only be called from the same thread that runs the connExecutor.
4904
+ func (ex * connExecutor ) WithAnonymizedStatementAndGist (err error ) error {
4905
+ if ex .curStmtAST != nil {
4906
+ vt := ex .planner .extendedEvalCtx .VirtualSchemas
4907
+ anonStmtStr := anonymizeStmtAndConstants (ex .curStmtAST , vt )
4908
+ anonStmtStr = truncateStatementStringForTelemetry (anonStmtStr )
4909
+ err = errors .WithSafeDetails (err , "while executing: %s" , errors .Safe (anonStmtStr ))
4910
+ }
4911
+ if ex .curStmtPlanGist != "" {
4912
+ err = errors .WithSafeDetails (err , "plan gist: %s" , ex .curStmtPlanGist )
4913
+ }
4914
+ return err
4915
+ }
4916
+
4892
4917
var contextPlanGistKey = ctxutil .RegisterFastValueKey ()
4893
4918
4894
4919
func withPlanGist (ctx context.Context , gist string ) context.Context {
0 commit comments