trace.go (14524B)
1 package pgproto3 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "strconv" 8 "strings" 9 "time" 10 ) 11 12 // tracer traces the messages send to and from a Backend or Frontend. The format it produces roughly mimics the 13 // format produced by the libpq C function PQtrace. 14 type tracer struct { 15 w io.Writer 16 buf *bytes.Buffer 17 TracerOptions 18 } 19 20 // TracerOptions controls tracing behavior. It is roughly equivalent to the libpq function PQsetTraceFlags. 21 type TracerOptions struct { 22 // SuppressTimestamps prevents printing of timestamps. 23 SuppressTimestamps bool 24 25 // RegressMode redacts fields that may be vary between executions. 26 RegressMode bool 27 } 28 29 func (t *tracer) traceMessage(sender byte, encodedLen int32, msg Message) { 30 switch msg := msg.(type) { 31 case *AuthenticationCleartextPassword: 32 t.traceAuthenticationCleartextPassword(sender, encodedLen, msg) 33 case *AuthenticationGSS: 34 t.traceAuthenticationGSS(sender, encodedLen, msg) 35 case *AuthenticationGSSContinue: 36 t.traceAuthenticationGSSContinue(sender, encodedLen, msg) 37 case *AuthenticationMD5Password: 38 t.traceAuthenticationMD5Password(sender, encodedLen, msg) 39 case *AuthenticationOk: 40 t.traceAuthenticationOk(sender, encodedLen, msg) 41 case *AuthenticationSASL: 42 t.traceAuthenticationSASL(sender, encodedLen, msg) 43 case *AuthenticationSASLContinue: 44 t.traceAuthenticationSASLContinue(sender, encodedLen, msg) 45 case *AuthenticationSASLFinal: 46 t.traceAuthenticationSASLFinal(sender, encodedLen, msg) 47 case *BackendKeyData: 48 t.traceBackendKeyData(sender, encodedLen, msg) 49 case *Bind: 50 t.traceBind(sender, encodedLen, msg) 51 case *BindComplete: 52 t.traceBindComplete(sender, encodedLen, msg) 53 case *CancelRequest: 54 t.traceCancelRequest(sender, encodedLen, msg) 55 case *Close: 56 t.traceClose(sender, encodedLen, msg) 57 case *CloseComplete: 58 t.traceCloseComplete(sender, encodedLen, msg) 59 case *CommandComplete: 60 t.traceCommandComplete(sender, encodedLen, msg) 61 case *CopyBothResponse: 62 t.traceCopyBothResponse(sender, encodedLen, msg) 63 case *CopyData: 64 t.traceCopyData(sender, encodedLen, msg) 65 case *CopyDone: 66 t.traceCopyDone(sender, encodedLen, msg) 67 case *CopyFail: 68 t.traceCopyFail(sender, encodedLen, msg) 69 case *CopyInResponse: 70 t.traceCopyInResponse(sender, encodedLen, msg) 71 case *CopyOutResponse: 72 t.traceCopyOutResponse(sender, encodedLen, msg) 73 case *DataRow: 74 t.traceDataRow(sender, encodedLen, msg) 75 case *Describe: 76 t.traceDescribe(sender, encodedLen, msg) 77 case *EmptyQueryResponse: 78 t.traceEmptyQueryResponse(sender, encodedLen, msg) 79 case *ErrorResponse: 80 t.traceErrorResponse(sender, encodedLen, msg) 81 case *Execute: 82 t.TraceQueryute(sender, encodedLen, msg) 83 case *Flush: 84 t.traceFlush(sender, encodedLen, msg) 85 case *FunctionCall: 86 t.traceFunctionCall(sender, encodedLen, msg) 87 case *FunctionCallResponse: 88 t.traceFunctionCallResponse(sender, encodedLen, msg) 89 case *GSSEncRequest: 90 t.traceGSSEncRequest(sender, encodedLen, msg) 91 case *NoData: 92 t.traceNoData(sender, encodedLen, msg) 93 case *NoticeResponse: 94 t.traceNoticeResponse(sender, encodedLen, msg) 95 case *NotificationResponse: 96 t.traceNotificationResponse(sender, encodedLen, msg) 97 case *ParameterDescription: 98 t.traceParameterDescription(sender, encodedLen, msg) 99 case *ParameterStatus: 100 t.traceParameterStatus(sender, encodedLen, msg) 101 case *Parse: 102 t.traceParse(sender, encodedLen, msg) 103 case *ParseComplete: 104 t.traceParseComplete(sender, encodedLen, msg) 105 case *PortalSuspended: 106 t.tracePortalSuspended(sender, encodedLen, msg) 107 case *Query: 108 t.traceQuery(sender, encodedLen, msg) 109 case *ReadyForQuery: 110 t.traceReadyForQuery(sender, encodedLen, msg) 111 case *RowDescription: 112 t.traceRowDescription(sender, encodedLen, msg) 113 case *SSLRequest: 114 t.traceSSLRequest(sender, encodedLen, msg) 115 case *StartupMessage: 116 t.traceStartupMessage(sender, encodedLen, msg) 117 case *Sync: 118 t.traceSync(sender, encodedLen, msg) 119 case *Terminate: 120 t.traceTerminate(sender, encodedLen, msg) 121 default: 122 t.beginTrace(sender, encodedLen, "Unknown") 123 t.finishTrace() 124 } 125 } 126 127 func (t *tracer) traceAuthenticationCleartextPassword(sender byte, encodedLen int32, msg *AuthenticationCleartextPassword) { 128 t.beginTrace(sender, encodedLen, "AuthenticationCleartextPassword") 129 t.finishTrace() 130 } 131 132 func (t *tracer) traceAuthenticationGSS(sender byte, encodedLen int32, msg *AuthenticationGSS) { 133 t.beginTrace(sender, encodedLen, "AuthenticationGSS") 134 t.finishTrace() 135 } 136 137 func (t *tracer) traceAuthenticationGSSContinue(sender byte, encodedLen int32, msg *AuthenticationGSSContinue) { 138 t.beginTrace(sender, encodedLen, "AuthenticationGSSContinue") 139 t.finishTrace() 140 } 141 142 func (t *tracer) traceAuthenticationMD5Password(sender byte, encodedLen int32, msg *AuthenticationMD5Password) { 143 t.beginTrace(sender, encodedLen, "AuthenticationMD5Password") 144 t.finishTrace() 145 } 146 147 func (t *tracer) traceAuthenticationOk(sender byte, encodedLen int32, msg *AuthenticationOk) { 148 t.beginTrace(sender, encodedLen, "AuthenticationOk") 149 t.finishTrace() 150 } 151 152 func (t *tracer) traceAuthenticationSASL(sender byte, encodedLen int32, msg *AuthenticationSASL) { 153 t.beginTrace(sender, encodedLen, "AuthenticationSASL") 154 t.finishTrace() 155 } 156 157 func (t *tracer) traceAuthenticationSASLContinue(sender byte, encodedLen int32, msg *AuthenticationSASLContinue) { 158 t.beginTrace(sender, encodedLen, "AuthenticationSASLContinue") 159 t.finishTrace() 160 } 161 162 func (t *tracer) traceAuthenticationSASLFinal(sender byte, encodedLen int32, msg *AuthenticationSASLFinal) { 163 t.beginTrace(sender, encodedLen, "AuthenticationSASLFinal") 164 t.finishTrace() 165 } 166 167 func (t *tracer) traceBackendKeyData(sender byte, encodedLen int32, msg *BackendKeyData) { 168 t.beginTrace(sender, encodedLen, "BackendKeyData") 169 if t.RegressMode { 170 t.buf.WriteString("\t NNNN NNNN") 171 } else { 172 fmt.Fprintf(t.buf, "\t %d %d", msg.ProcessID, msg.SecretKey) 173 } 174 t.finishTrace() 175 } 176 177 func (t *tracer) traceBind(sender byte, encodedLen int32, msg *Bind) { 178 t.beginTrace(sender, encodedLen, "Bind") 179 fmt.Fprintf(t.buf, "\t %s %s %d", traceDoubleQuotedString([]byte(msg.DestinationPortal)), traceDoubleQuotedString([]byte(msg.PreparedStatement)), len(msg.ParameterFormatCodes)) 180 for _, fc := range msg.ParameterFormatCodes { 181 fmt.Fprintf(t.buf, " %d", fc) 182 } 183 fmt.Fprintf(t.buf, " %d", len(msg.Parameters)) 184 for _, p := range msg.Parameters { 185 fmt.Fprintf(t.buf, " %s", traceSingleQuotedString(p)) 186 } 187 fmt.Fprintf(t.buf, " %d", len(msg.ResultFormatCodes)) 188 for _, fc := range msg.ResultFormatCodes { 189 fmt.Fprintf(t.buf, " %d", fc) 190 } 191 t.finishTrace() 192 } 193 194 func (t *tracer) traceBindComplete(sender byte, encodedLen int32, msg *BindComplete) { 195 t.beginTrace(sender, encodedLen, "BindComplete") 196 t.finishTrace() 197 } 198 199 func (t *tracer) traceCancelRequest(sender byte, encodedLen int32, msg *CancelRequest) { 200 t.beginTrace(sender, encodedLen, "CancelRequest") 201 t.finishTrace() 202 } 203 204 func (t *tracer) traceClose(sender byte, encodedLen int32, msg *Close) { 205 t.beginTrace(sender, encodedLen, "Close") 206 t.finishTrace() 207 } 208 209 func (t *tracer) traceCloseComplete(sender byte, encodedLen int32, msg *CloseComplete) { 210 t.beginTrace(sender, encodedLen, "CloseComplete") 211 t.finishTrace() 212 } 213 214 func (t *tracer) traceCommandComplete(sender byte, encodedLen int32, msg *CommandComplete) { 215 t.beginTrace(sender, encodedLen, "CommandComplete") 216 fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString(msg.CommandTag)) 217 t.finishTrace() 218 } 219 220 func (t *tracer) traceCopyBothResponse(sender byte, encodedLen int32, msg *CopyBothResponse) { 221 t.beginTrace(sender, encodedLen, "CopyBothResponse") 222 t.finishTrace() 223 } 224 225 func (t *tracer) traceCopyData(sender byte, encodedLen int32, msg *CopyData) { 226 t.beginTrace(sender, encodedLen, "CopyData") 227 t.finishTrace() 228 } 229 230 func (t *tracer) traceCopyDone(sender byte, encodedLen int32, msg *CopyDone) { 231 t.beginTrace(sender, encodedLen, "CopyDone") 232 t.finishTrace() 233 } 234 235 func (t *tracer) traceCopyFail(sender byte, encodedLen int32, msg *CopyFail) { 236 t.beginTrace(sender, encodedLen, "CopyFail") 237 fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString([]byte(msg.Message))) 238 t.finishTrace() 239 } 240 241 func (t *tracer) traceCopyInResponse(sender byte, encodedLen int32, msg *CopyInResponse) { 242 t.beginTrace(sender, encodedLen, "CopyInResponse") 243 t.finishTrace() 244 } 245 246 func (t *tracer) traceCopyOutResponse(sender byte, encodedLen int32, msg *CopyOutResponse) { 247 t.beginTrace(sender, encodedLen, "CopyOutResponse") 248 t.finishTrace() 249 } 250 251 func (t *tracer) traceDataRow(sender byte, encodedLen int32, msg *DataRow) { 252 t.beginTrace(sender, encodedLen, "DataRow") 253 fmt.Fprintf(t.buf, "\t %d", len(msg.Values)) 254 for _, v := range msg.Values { 255 if v == nil { 256 t.buf.WriteString(" -1") 257 } else { 258 fmt.Fprintf(t.buf, " %d %s", len(v), traceSingleQuotedString(v)) 259 } 260 } 261 t.finishTrace() 262 } 263 264 func (t *tracer) traceDescribe(sender byte, encodedLen int32, msg *Describe) { 265 t.beginTrace(sender, encodedLen, "Describe") 266 fmt.Fprintf(t.buf, "\t %c %s", msg.ObjectType, traceDoubleQuotedString([]byte(msg.Name))) 267 t.finishTrace() 268 } 269 270 func (t *tracer) traceEmptyQueryResponse(sender byte, encodedLen int32, msg *EmptyQueryResponse) { 271 t.beginTrace(sender, encodedLen, "EmptyQueryResponse") 272 t.finishTrace() 273 } 274 275 func (t *tracer) traceErrorResponse(sender byte, encodedLen int32, msg *ErrorResponse) { 276 t.beginTrace(sender, encodedLen, "ErrorResponse") 277 t.finishTrace() 278 } 279 280 func (t *tracer) TraceQueryute(sender byte, encodedLen int32, msg *Execute) { 281 t.beginTrace(sender, encodedLen, "Execute") 282 fmt.Fprintf(t.buf, "\t %s %d", traceDoubleQuotedString([]byte(msg.Portal)), msg.MaxRows) 283 t.finishTrace() 284 } 285 286 func (t *tracer) traceFlush(sender byte, encodedLen int32, msg *Flush) { 287 t.beginTrace(sender, encodedLen, "Flush") 288 t.finishTrace() 289 } 290 291 func (t *tracer) traceFunctionCall(sender byte, encodedLen int32, msg *FunctionCall) { 292 t.beginTrace(sender, encodedLen, "FunctionCall") 293 t.finishTrace() 294 } 295 296 func (t *tracer) traceFunctionCallResponse(sender byte, encodedLen int32, msg *FunctionCallResponse) { 297 t.beginTrace(sender, encodedLen, "FunctionCallResponse") 298 t.finishTrace() 299 } 300 301 func (t *tracer) traceGSSEncRequest(sender byte, encodedLen int32, msg *GSSEncRequest) { 302 t.beginTrace(sender, encodedLen, "GSSEncRequest") 303 t.finishTrace() 304 } 305 306 func (t *tracer) traceNoData(sender byte, encodedLen int32, msg *NoData) { 307 t.beginTrace(sender, encodedLen, "NoData") 308 t.finishTrace() 309 } 310 311 func (t *tracer) traceNoticeResponse(sender byte, encodedLen int32, msg *NoticeResponse) { 312 t.beginTrace(sender, encodedLen, "NoticeResponse") 313 t.finishTrace() 314 } 315 316 func (t *tracer) traceNotificationResponse(sender byte, encodedLen int32, msg *NotificationResponse) { 317 t.beginTrace(sender, encodedLen, "NotificationResponse") 318 fmt.Fprintf(t.buf, "\t %d %s %s", msg.PID, traceDoubleQuotedString([]byte(msg.Channel)), traceDoubleQuotedString([]byte(msg.Payload))) 319 t.finishTrace() 320 } 321 322 func (t *tracer) traceParameterDescription(sender byte, encodedLen int32, msg *ParameterDescription) { 323 t.beginTrace(sender, encodedLen, "ParameterDescription") 324 t.finishTrace() 325 } 326 327 func (t *tracer) traceParameterStatus(sender byte, encodedLen int32, msg *ParameterStatus) { 328 t.beginTrace(sender, encodedLen, "ParameterStatus") 329 fmt.Fprintf(t.buf, "\t %s %s", traceDoubleQuotedString([]byte(msg.Name)), traceDoubleQuotedString([]byte(msg.Value))) 330 t.finishTrace() 331 } 332 333 func (t *tracer) traceParse(sender byte, encodedLen int32, msg *Parse) { 334 t.beginTrace(sender, encodedLen, "Parse") 335 fmt.Fprintf(t.buf, "\t %s %s %d", traceDoubleQuotedString([]byte(msg.Name)), traceDoubleQuotedString([]byte(msg.Query)), len(msg.ParameterOIDs)) 336 for _, oid := range msg.ParameterOIDs { 337 fmt.Fprintf(t.buf, " %d", oid) 338 } 339 t.finishTrace() 340 } 341 342 func (t *tracer) traceParseComplete(sender byte, encodedLen int32, msg *ParseComplete) { 343 t.beginTrace(sender, encodedLen, "ParseComplete") 344 t.finishTrace() 345 } 346 347 func (t *tracer) tracePortalSuspended(sender byte, encodedLen int32, msg *PortalSuspended) { 348 t.beginTrace(sender, encodedLen, "PortalSuspended") 349 t.finishTrace() 350 } 351 352 func (t *tracer) traceQuery(sender byte, encodedLen int32, msg *Query) { 353 t.beginTrace(sender, encodedLen, "Query") 354 fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString([]byte(msg.String))) 355 t.finishTrace() 356 } 357 358 func (t *tracer) traceReadyForQuery(sender byte, encodedLen int32, msg *ReadyForQuery) { 359 t.beginTrace(sender, encodedLen, "ReadyForQuery") 360 fmt.Fprintf(t.buf, "\t %c", msg.TxStatus) 361 t.finishTrace() 362 } 363 364 func (t *tracer) traceRowDescription(sender byte, encodedLen int32, msg *RowDescription) { 365 t.beginTrace(sender, encodedLen, "RowDescription") 366 fmt.Fprintf(t.buf, "\t %d", len(msg.Fields)) 367 for _, fd := range msg.Fields { 368 fmt.Fprintf(t.buf, ` %s %d %d %d %d %d %d`, traceDoubleQuotedString(fd.Name), fd.TableOID, fd.TableAttributeNumber, fd.DataTypeOID, fd.DataTypeSize, fd.TypeModifier, fd.Format) 369 } 370 t.finishTrace() 371 } 372 373 func (t *tracer) traceSSLRequest(sender byte, encodedLen int32, msg *SSLRequest) { 374 t.beginTrace(sender, encodedLen, "SSLRequest") 375 t.finishTrace() 376 } 377 378 func (t *tracer) traceStartupMessage(sender byte, encodedLen int32, msg *StartupMessage) { 379 t.beginTrace(sender, encodedLen, "StartupMessage") 380 t.finishTrace() 381 } 382 383 func (t *tracer) traceSync(sender byte, encodedLen int32, msg *Sync) { 384 t.beginTrace(sender, encodedLen, "Sync") 385 t.finishTrace() 386 } 387 388 func (t *tracer) traceTerminate(sender byte, encodedLen int32, msg *Terminate) { 389 t.beginTrace(sender, encodedLen, "Terminate") 390 t.finishTrace() 391 } 392 393 func (t *tracer) beginTrace(sender byte, encodedLen int32, msgType string) { 394 if !t.SuppressTimestamps { 395 now := time.Now() 396 t.buf.WriteString(now.Format("2006-01-02 15:04:05.000000")) 397 t.buf.WriteByte('\t') 398 } 399 400 t.buf.WriteByte(sender) 401 t.buf.WriteByte('\t') 402 t.buf.WriteString(msgType) 403 t.buf.WriteByte('\t') 404 t.buf.WriteString(strconv.FormatInt(int64(encodedLen), 10)) 405 } 406 407 func (t *tracer) finishTrace() { 408 t.buf.WriteByte('\n') 409 t.buf.WriteTo(t.w) 410 411 if t.buf.Cap() > 1024 { 412 t.buf = &bytes.Buffer{} 413 } else { 414 t.buf.Reset() 415 } 416 } 417 418 // traceDoubleQuotedString returns t.buf as a double-quoted string without any escaping. It is roughly equivalent to 419 // pqTraceOutputString in libpq. 420 func traceDoubleQuotedString(buf []byte) string { 421 return `"` + string(buf) + `"` 422 } 423 424 // traceSingleQuotedString returns buf as a single-quoted string with non-printable characters hex-escaped. It is 425 // roughly equivalent to pqTraceOutputNchar in libpq. 426 func traceSingleQuotedString(buf []byte) string { 427 sb := &strings.Builder{} 428 429 sb.WriteByte('\'') 430 for _, b := range buf { 431 if b < 32 || b > 126 { 432 fmt.Fprintf(sb, `\x%x`, b) 433 } else { 434 sb.WriteByte(b) 435 } 436 } 437 sb.WriteByte('\'') 438 439 return sb.String() 440 }