gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }