github.com/Ingenico-ePayments/connect-sdk-go@v0.0.0-20240318153750-1f8cd329b9c9/logging/ResponseLogMessageBuilder.go (about) 1 package logging 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "strings" 8 "time" 9 10 "github.com/Ingenico-ePayments/connect-sdk-go/logging/obfuscation" 11 ) 12 13 const messageTemplate = `Incoming response (requestId='%s' in '%v'): 14 status-code: '%d' 15 headers: '%s' 16 content-type: '%s' 17 body: '%s'` 18 19 // ResponseLogMessageBuilder represents a utility class to build request log messages. 20 type ResponseLogMessageBuilder struct { 21 responseID string 22 statusCode int 23 duration time.Duration 24 25 body string 26 contentType string 27 28 headers map[string][]string 29 30 headersBuffer bytes.Buffer 31 32 bodyObfuscator obfuscation.BodyObfuscator 33 headerObfuscator obfuscation.HeaderObfuscator 34 } 35 36 // ResponseLogMessage represents a log message about a Response 37 type ResponseLogMessage struct { 38 responseID string 39 statusCode int 40 duration time.Duration 41 42 body string 43 contentType string 44 45 headers map[string][]string 46 47 headersFormatted string 48 49 bodyObfuscator obfuscation.BodyObfuscator 50 headerObfuscator obfuscation.HeaderObfuscator 51 } 52 53 // ResponseID returns the response id 54 func (rl *ResponseLogMessage) ResponseID() string { 55 return rl.responseID 56 } 57 58 // StatusCode returns the response status code 59 func (rl *ResponseLogMessage) StatusCode() int { 60 return rl.statusCode 61 } 62 63 // Duration returns the transport duration 64 func (rl *ResponseLogMessage) Duration() time.Duration { 65 return rl.duration 66 } 67 68 // Body returns the response body 69 func (rl *ResponseLogMessage) Body() string { 70 return rl.body 71 } 72 73 // ContentType returns the response content-type 74 func (rl *ResponseLogMessage) ContentType() string { 75 return rl.contentType 76 } 77 78 // Headers returns the response headers 79 func (rl *ResponseLogMessage) Headers() map[string][]string { 80 return rl.headers 81 } 82 83 // String implements the Stringer interface 84 func (rl *ResponseLogMessage) String() string { 85 return fmt.Sprintf(messageTemplate, rl.responseID, rl.duration, rl.statusCode, rl.headersFormatted, rl.contentType, rl.body) 86 } 87 88 // AddHeader adds a header to the log message using the name and value 89 func (rlm *ResponseLogMessageBuilder) AddHeader(name, value string) error { 90 if rlm.headersBuffer.Len() > 0 { 91 rlm.headersBuffer.WriteString(", ") 92 } 93 94 rlm.headersBuffer.WriteString(name) 95 rlm.headersBuffer.WriteString("=\"") 96 97 if len(value) > 0 { 98 obfuscatedValue := rlm.headerObfuscator.ObfuscateHeader(name, value) 99 100 rlm.headersBuffer.WriteString(obfuscatedValue) 101 102 rlm.headers[name] = append(rlm.headers[name], obfuscatedValue) 103 } 104 rlm.headersBuffer.WriteString("\"") 105 106 return nil 107 } 108 109 // SetBody sets the request body 110 func (rlm *ResponseLogMessageBuilder) SetBody(body, contentType string) error { 111 obfuscatedBody, err := rlm.bodyObfuscator.ObfuscateBody(body) 112 if err != nil { 113 return err 114 } 115 116 rlm.contentType = contentType 117 rlm.body = obfuscatedBody 118 119 return nil 120 } 121 122 // SetBinaryBody sets the binary request body 123 func (rlm *ResponseLogMessageBuilder) SetBinaryBody(contentType string) error { 124 if !isBinaryContent(contentType) { 125 return errors.New("Not a binary content type: " + contentType) 126 } 127 rlm.contentType = contentType 128 rlm.body = "<binary content>" 129 130 return nil 131 } 132 133 func isBinaryContent(contentType string) bool { 134 contentType = strings.ToLower(contentType) 135 136 return !strings.HasPrefix(contentType, "text/") && !strings.Contains(contentType, "json") && !strings.Contains(contentType, "xml") 137 } 138 139 // BuildMessage builds the ResponseLogMessage 140 func (rlm *ResponseLogMessageBuilder) BuildMessage() (*ResponseLogMessage, error) { 141 return &ResponseLogMessage{rlm.responseID, rlm.statusCode, rlm.duration, rlm.body, rlm.contentType, rlm.headers, rlm.headersBuffer.String(), rlm.bodyObfuscator, rlm.headerObfuscator}, nil 142 } 143 144 // NewResponseLogMessageBuilder creates a ResponseLogMessageBuilder with the given responseID, statusCode and duration 145 // 146 // Deprecated: use NewResponseLogMessageBuilderWithObfuscators instead 147 func NewResponseLogMessageBuilder(responseID string, statusCode int, duration time.Duration) (*ResponseLogMessageBuilder, error) { 148 return NewResponseLogMessageBuilderWithObfuscators(responseID, statusCode, duration, obfuscation.DefaultBodyObfuscator(), obfuscation.DefaultHeaderObfuscator()) 149 } 150 151 // NewResponseLogMessageBuilderWithObfuscators creates a ResponseLogMessageBuilder with the given responseID, statusCode, duration and obfuscators 152 func NewResponseLogMessageBuilderWithObfuscators(responseID string, statusCode int, duration time.Duration, bodyObfuscator obfuscation.BodyObfuscator, headerObfuscator obfuscation.HeaderObfuscator) (*ResponseLogMessageBuilder, error) { 153 if len(responseID) < 1 { 154 return nil, errRequestIDEmpty 155 } 156 157 return &ResponseLogMessageBuilder{responseID, statusCode, duration, "", "", map[string][]string{}, bytes.Buffer{}, bodyObfuscator, headerObfuscator}, nil 158 }