Skip to content

Commit 994f0c7

Browse files
authored
Merge pull request #16 from deploymenttheory/dev
Dev
2 parents 4cd3a9c + c495895 commit 994f0c7

File tree

6 files changed

+135
-143
lines changed

6 files changed

+135
-143
lines changed

httpclient/httpclient_client.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ type AuthConfig struct {
5959
// ClientOptions holds optional configuration options for the HTTP Client.
6060
type ClientOptions struct {
6161
LogLevel string // Field for defining tiered logging level.
62+
LogOutputFormat string // Field for defining the output format of the logs. Use "LogOutputJSON" for JSON format, "LogOutputHumanReadable" for human-readable format
6263
HideSensitiveData bool // Field for defining whether sensitive fields should be hidden in logs.
6364
MaxRetryAttempts int // Config item defines the max number of retry request attempts for retryable HTTP methods.
6465
EnableDynamicRateLimiting bool // Field for defining whether dynamic rate limiting should be enabled.
@@ -84,8 +85,8 @@ func BuildClient(config ClientConfig) (*Client, error) {
8485
// Parse the log level string to logger.LogLevel
8586
parsedLogLevel := logger.ParseLogLevelFromString(config.ClientOptions.LogLevel)
8687

87-
// Initialize the logger with the parsed log level
88-
log := logger.BuildLogger(parsedLogLevel)
88+
// Initialize the logger with the parsed log level and log output format
89+
log := logger.BuildLogger(parsedLogLevel, config.ClientOptions.LogOutputFormat)
8990

9091
// Set the logger's level (optional if BuildLogger already sets the level based on the input)
9192
log.SetLevel(parsedLogLevel)
@@ -165,6 +166,7 @@ func BuildClient(config ClientConfig) (*Client, error) {
165166
zap.String("Override Base Domain", config.Environment.OverrideBaseDomain),
166167
zap.String("Authentication Method", authMethod),
167168
zap.String("Logging Level", config.ClientOptions.LogLevel),
169+
zap.String("Log Output Format", config.ClientOptions.LogOutputFormat),
168170
zap.Bool("Hide Sensitive Data In Logs", config.ClientOptions.HideSensitiveData),
169171
zap.Int("Max Retry Attempts", config.ClientOptions.MaxRetryAttempts),
170172
zap.Int("Max Concurrent Requests", config.ClientOptions.MaxConcurrentRequests),

httpclient/httpclient_helpers.go

Lines changed: 2 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ func RedactSensitiveData(client *Client, key string, value string) string {
3131
if client.clientConfig.ClientOptions.HideSensitiveData {
3232
// Define sensitive data keys that should be redacted.
3333
sensitiveKeys := map[string]bool{
34-
"AccessToken": true,
35-
// Add more sensitive keys as necessary.
34+
"AccessToken": true,
35+
"Authorization": true,
3636
}
3737

3838
if _, found := sensitiveKeys[key]; found {
@@ -41,74 +41,3 @@ func RedactSensitiveData(client *Client, key string, value string) string {
4141
}
4242
return value
4343
}
44-
45-
/*
46-
// EnsureHTTPScheme prefixes a URL with "http://" it defaults to "https://" doesn't already have an "https://".
47-
func EnsureHTTPScheme(url string) string {
48-
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
49-
return fmt.Sprintf("https://%s", url)
50-
}
51-
return url
52-
}
53-
*/
54-
55-
/*
56-
// SetAuthenticationCredentials interprets and sets the credentials for the Client.
57-
func (c *Client) SetAuthenticationCredentials(creds map[string]string) {
58-
// Check for OAuth credentials
59-
if clientID, ok := creds["clientID"]; ok {
60-
if clientSecret, ok := creds["clientSecret"]; ok {
61-
c.OAuthCredentials = OAuthCredentials{
62-
ClientID: clientID,
63-
ClientSecret: clientSecret,
64-
}
65-
c.AuthMethod = "oauth"
66-
return
67-
}
68-
}
69-
70-
// Check for Bearer Token credentials
71-
if username, ok := creds["username"]; ok {
72-
if password, ok := creds["password"]; ok {
73-
c.BearerTokenAuthCredentials = BearerTokenAuthCredentials{
74-
Username: username,
75-
Password: password,
76-
}
77-
c.AuthMethod = "bearer"
78-
return
79-
}
80-
}
81-
}
82-
83-
// GetOAuthCredentials retrieves the current OAuth credentials (Client ID and Client Secret)
84-
// set for the client instance. Used for test cases.
85-
func (c *Client) GetOAuthCredentials() OAuthCredentials {
86-
return c.OAuthCredentials
87-
}
88-
89-
// GetBearerAuthCredentials retrieves the current bearer auth credentials (Username and Password)
90-
// set for the client instance. Used for test cases.
91-
func (c *Client) GetBearerAuthCredentials() BearerTokenAuthCredentials {
92-
return c.BearerTokenAuthCredentials
93-
}
94-
*/
95-
/*
96-
// LoadAuthConfig reads a JSON configuration file and decodes it into a ClientAuthConfig struct.
97-
// It is used to retrieve authentication details like BaseURL, Username, and Password for the client.
98-
func LoadAuthConfig(filename string) (*AuthConfig, error) {
99-
file, err := os.Open(filename)
100-
if err != nil {
101-
return nil, err
102-
}
103-
defer file.Close()
104-
105-
config := &AuthConfig{}
106-
decoder := json.NewDecoder(file)
107-
err = decoder.Decode(config)
108-
if err != nil {
109-
return nil, err
110-
}
111-
112-
return config, nil
113-
}
114-
*/

httpclient/httpclient_request.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,19 @@ func (c *Client) DoRequest(method, endpoint string, body, out interface{}, log l
112112
"*/*;q=0.05"
113113

114114
// Set Headers
115-
req.Header.Add("Authorization", "Bearer "+c.Token)
115+
req.Header.Add("Authorization", c.Token)
116116
req.Header.Add("Content-Type", contentType)
117117
req.Header.Add("Accept", acceptHeader)
118118
req.Header.Set("User-Agent", GetUserAgentHeader())
119119

120-
// Debug: Print request headers if in debug mode
121-
headersStr := HeadersToString(req.Header)
122-
log.Debug("HTTP Multipart Request Headers:", zap.String("headers", headersStr))
120+
// Debug: Print request headers
121+
redactedAuthorization := RedactSensitiveData(c, "Authorization", req.Header.Get("Authorization"))
122+
c.Logger.Debug("HTTP Request Headers",
123+
zap.String("Authorization", redactedAuthorization),
124+
zap.String("Content-Type", req.Header.Get("Content-Type")),
125+
zap.String("Accept", req.Header.Get("Accept")),
126+
zap.String("User-Agent", req.Header.Get("User-Agent")),
127+
)
123128

124129
// Define if request is retryable
125130
retryableHTTPMethods := map[string]bool{
@@ -383,9 +388,14 @@ func (c *Client) DoMultipartRequest(method, endpoint string, fields map[string]s
383388
req.Header.Set("Content-Type", contentType)
384389
req.Header.Set("User-Agent", GetUserAgentHeader())
385390

386-
// Debug: Print request headers if in debug mode
387-
headersStr := HeadersToString(req.Header)
388-
log.Debug("HTTP Multipart Request Headers:", zap.String("headers", headersStr))
391+
// Debug: Print request headers
392+
redactedAuthorization := RedactSensitiveData(c, "Authorization", req.Header.Get("Authorization"))
393+
c.Logger.Debug("HTTP Request Headers",
394+
zap.String("Authorization", redactedAuthorization),
395+
zap.String("Content-Type", req.Header.Get("Content-Type")),
396+
zap.String("Accept", req.Header.Get("Accept")),
397+
zap.String("User-Agent", req.Header.Get("User-Agent")),
398+
)
389399

390400
// Execute the request
391401
resp, err := c.httpClient.Do(req)

logger/format.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// logger.go
2+
package logger
3+
4+
import (
5+
"encoding/json"
6+
"fmt"
7+
"log"
8+
"reflect"
9+
)
10+
11+
// LogEntry represents the structure of a log entry.
12+
type LogEntry struct {
13+
Level string `json:"level"`
14+
Timestamp string `json:"timestamp"`
15+
Message string `json:"msg"`
16+
Additional map[string]interface{} `json:"-"`
17+
}
18+
19+
// UnmarshalJSONLog customizes the unmarshalling of LogEntry to handle arbitrary key-value pairs.
20+
func (le *LogEntry) UnmarshalJSONLog(data []byte) error {
21+
// Unmarshal fixed fields first
22+
type Alias LogEntry
23+
aux := &struct {
24+
*Alias
25+
}{
26+
Alias: (*Alias)(le),
27+
}
28+
if err := json.Unmarshal(data, &aux); err != nil {
29+
return err
30+
}
31+
32+
// Unmarshal additional fields into a map
33+
var additionalFields map[string]interface{}
34+
if err := json.Unmarshal(data, &additionalFields); err != nil {
35+
return err
36+
}
37+
38+
// Remove fixed fields from the map
39+
delete(additionalFields, "level")
40+
delete(additionalFields, "timestamp")
41+
delete(additionalFields, "msg")
42+
43+
le.Additional = additionalFields
44+
return nil
45+
}
46+
47+
// ProcessLogs parses and outputs the log entries in a human-readable form.
48+
func ProcessLogs(logEntries []string) {
49+
for _, logEntryStr := range logEntries {
50+
var logEntry LogEntry
51+
if err := json.Unmarshal([]byte(logEntryStr), &logEntry); err != nil {
52+
log.Printf("Failed to parse log entry: %v", err)
53+
continue
54+
}
55+
56+
fmt.Printf("[%s] %s: %s\n", logEntry.Timestamp, logEntry.Level, logEntry.Message)
57+
for key, value := range logEntry.Additional {
58+
valueStr := formatValue(value)
59+
fmt.Printf(" %s: %s\n", key, valueStr)
60+
}
61+
fmt.Println()
62+
}
63+
}
64+
65+
// formatValue returns a string representation of the value, considering its type.
66+
func formatValue(value interface{}) string {
67+
if value == nil {
68+
return "null"
69+
}
70+
val := reflect.ValueOf(value)
71+
switch val.Kind() {
72+
case reflect.String:
73+
return fmt.Sprintf("%q", value)
74+
case reflect.Int, reflect.Int64, reflect.Float64:
75+
return fmt.Sprintf("%v", value)
76+
case reflect.Bool:
77+
return fmt.Sprintf("%t", value)
78+
case reflect.Map, reflect.Slice, reflect.Array:
79+
bytes, err := json.Marshal(value)
80+
if err != nil {
81+
return "error"
82+
}
83+
return string(bytes)
84+
default:
85+
return fmt.Sprintf("%v", value)
86+
}
87+
}

logger/loggerconfig.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,21 @@ package logger
44
// Ref: https://betterstack.com/community/guides/logging/go/zap/#logging-errors-with-zap
55

66
import (
7+
"fmt"
8+
79
"go.uber.org/zap"
810
"go.uber.org/zap/zapcore"
911
)
1012

13+
const (
14+
LogOutputJSON = "json"
15+
LogOutputHumanReadable = "human-readable"
16+
)
17+
1118
// BuildLogger creates and returns a new zap logger instance.
1219
// It configures the logger with JSON formatting and a custom encoder to ensure the 'pid', 'application', and 'timestamp' fields
1320
// appear at the end of each log message. The function panics if the logger cannot be initialized.
14-
func BuildLogger(logLevel LogLevel) Logger {
21+
func BuildLogger(logLevel LogLevel, logOutputFormat string) Logger {
1522

1623
// Set up custom encoder configuration
1724
encoderCfg := zap.NewProductionEncoderConfig()
@@ -21,6 +28,11 @@ func BuildLogger(logLevel LogLevel) Logger {
2128
// Convert the custom LogLevel to zap's logging level
2229
zapLogLevel := convertToZapLevel(logLevel)
2330

31+
// Select the appropriate encoder based on the logOutputFormat
32+
if logOutputFormat == LogOutputHumanReadable {
33+
encoderCfg.EncodeLevel = zapcore.CapitalColorLevelEncoder // For human-readable output, use colored level encoder
34+
}
35+
2436
// Define the logger configuration
2537
config := zap.Config{
2638
Level: zap.NewAtomicLevelAt(zapLogLevel), // Default log level is Info
@@ -41,9 +53,20 @@ func BuildLogger(logLevel LogLevel) Logger {
4153
//"application": version.GetAppName(),
4254
},
4355
}
56+
/*
57+
// Build the logger from the configuration
58+
logger := zap.Must(config.Build())
59+
*/
60+
// Override Encoding for human-readable format
61+
if logOutputFormat == LogOutputHumanReadable {
62+
config.Encoding = "console"
63+
}
4464

4565
// Build the logger from the configuration
46-
logger := zap.Must(config.Build())
66+
logger, err := config.Build()
67+
if err != nil {
68+
panic(fmt.Sprintf("Failed to build logger: %v", err))
69+
}
4770

4871
// Wrap the original core with the custom core
4972
wrappedCore := &customCore{logger.Core()}

logger/sensitive_values.go.fixme

Lines changed: 0 additions & 59 deletions
This file was deleted.

0 commit comments

Comments
 (0)