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  }