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