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  }