Skip to content

Commit d01e30b

Browse files
committed
Add httpclient package and update logger initialization
1 parent 7c93a66 commit d01e30b

File tree

4 files changed

+86
-48
lines changed

4 files changed

+86
-48
lines changed

internal/apihandlers/jamfpro/jamfpro_api_handler.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import (
4949

5050
_ "embed"
5151

52+
"github.com/deploymenttheory/go-api-http-client/internal/httpclient"
5253
"github.com/deploymenttheory/go-api-http-client/internal/logger"
5354
"go.uber.org/zap"
5455
)
@@ -256,8 +257,8 @@ func (u *JamfAPIHandler) UnmarshalResponse(resp *http.Response, out interface{},
256257
// If content type is HTML, extract the error message
257258
if strings.Contains(contentType, "text/html") {
258259
errMsg := ExtractErrorMessageFromHTML(string(bodyBytes))
259-
log.Warn("Received HTML content", "error_message", errMsg, "status_code", resp.StatusCode)
260-
return &APIError{
260+
log.Warn("Received HTML content", zap.String("error_message", errMsg), zap.Int("status_code", resp.StatusCode))
261+
return &httpclient.APIError{
261262
StatusCode: resp.StatusCode,
262263
Message: errMsg,
263264
}

internal/httpclient/http_client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ type Client struct {
7373

7474
// BuildClient creates a new HTTP client with the provided configuration.
7575
func BuildClient(config Config) (*Client, error) {
76-
// Initialize the logger using the NewDefaultLogger function from the logger package.
77-
log := logger.NewDefaultLogger()
76+
// Initialize the zap logger.
77+
log := logger.BuildLogger(config.LogLevel)
7878

7979
// Set the logger's level based on the provided configuration.
8080
log.SetLevel(config.LogLevel)

internal/logger/logger.go

Lines changed: 8 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,19 @@ type LogLevel int
1515

1616
const (
1717
// LogLevelDebug is for messages that are useful during software debugging.
18-
LogLevelDebug LogLevel = iota - 1 // Adjusted value to -1 to follow Zap's convention for DEBUG.
18+
LogLevelDebug LogLevel = -1 // Zap's DEBUG level
1919
// LogLevelInfo is for informational messages, indicating normal operation.
20-
LogLevelInfo
20+
LogLevelInfo LogLevel = 0 // Zap's INFO level
2121
// LogLevelWarn is for messages that highlight potential issues in the system.
22-
LogLevelWarn
22+
LogLevelWarn LogLevel = 1 // Zap's WARN level
2323
// LogLevelError is for messages that highlight errors in the application's execution.
24-
LogLevelError
25-
// LogLevelDPanic is for severe error conditions that are actionable in development. It panics in development and logs as an error in production.
26-
LogLevelDPanic
24+
LogLevelError LogLevel = 2 // Zap's ERROR level
25+
// LogLevelDPanic is for severe error conditions that are actionable in development.
26+
LogLevelDPanic LogLevel = 3 // Zap's DPANIC level
2727
// LogLevelPanic is for severe error conditions that should cause the program to panic.
28-
LogLevelPanic
28+
LogLevelPanic LogLevel = 4 // Zap's PANIC level
2929
// LogLevelFatal is for errors that require immediate program termination.
30-
LogLevelFatal
31-
// LogLevelNone is used to disable logging.
30+
LogLevelFatal LogLevel = 5 // Zap's FATAL level
3231
LogLevelNone
3332
)
3433

@@ -53,41 +52,6 @@ type defaultLogger struct {
5352
logLevel LogLevel // logLevel determines the current logging level (e.g., DEBUG, INFO, WARN).
5453
}
5554

56-
// NewDefaultLogger creates and returns a new logger instance with a default production configuration.
57-
// It uses JSON formatting for log messages and sets the initial log level to Info. If the logger cannot
58-
// be initialized, the function panics to indicate a critical setup failure.
59-
func NewDefaultLogger() Logger {
60-
// Set up custom encoder configuration
61-
encoderCfg := zap.NewProductionEncoderConfig()
62-
encoderCfg.TimeKey = "timestamp"
63-
encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder // Use ISO8601 format for timestamps
64-
65-
// Define the logger configuration
66-
config := zap.Config{
67-
Level: zap.NewAtomicLevelAt(zap.InfoLevel), // Default log level is Info
68-
Development: false, // Set to true if the logger is used in a development environment
69-
Encoding: "json", // Use JSON format for structured logging
70-
EncoderConfig: encoderCfg,
71-
OutputPaths: []string{"stdout"}, // Log to standard output
72-
ErrorOutputPaths: []string{"stderr"}, // Log internal Zap errors to standard error
73-
InitialFields: map[string]interface{}{
74-
"application": "your-application-name", // Customize this field to suit your needs
75-
},
76-
}
77-
78-
// Build the logger from the configuration
79-
logger, err := config.Build()
80-
if err != nil {
81-
panic(err) // Panic if there is an error initializing the logger
82-
}
83-
84-
// Wrap the Zap logger in your defaultLogger struct, which implements your Logger interface
85-
return &defaultLogger{
86-
logger: logger,
87-
logLevel: LogLevelInfo, // Assuming LogLevelInfo maps to zap.InfoLevel
88-
}
89-
}
90-
9155
// SetLevel updates the logging level of the logger. It controls the verbosity of the logs,
9256
// allowing the option to filter out less severe messages based on the specified level.
9357
func (d *defaultLogger) SetLevel(level LogLevel) {

internal/logger/loggerconfig.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// logger.go
2+
package logger
3+
4+
// Ref: https://betterstack.com/community/guides/logging/go/zap/#logging-errors-with-zap
5+
6+
import (
7+
"go.uber.org/zap"
8+
"go.uber.org/zap/zapcore"
9+
)
10+
11+
// BuildLogger creates and returns a new logger instance with a default production configuration.
12+
// It uses JSON formatting for log messages and sets the initial log level to Info. If the logger cannot
13+
// be initialized, the function panics to indicate a critical setup failure.
14+
func BuildLogger(logLevel LogLevel) Logger {
15+
// Set up custom encoder configuration
16+
encoderCfg := zap.NewProductionEncoderConfig()
17+
encoderCfg.TimeKey = "timestamp"
18+
encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder // Use ISO8601 format for timestamps
19+
20+
// Convert the custom LogLevel to zap's logging level
21+
zapLogLevel := convertToZapLevel(logLevel)
22+
23+
// Define the logger configuration
24+
config := zap.Config{
25+
Level: zap.NewAtomicLevelAt(zapLogLevel), // Default log level is Info
26+
Development: false, // Set to true if the logger is used in a development environment
27+
Encoding: "json", // Use JSON format for structured logging
28+
DisableCaller: false,
29+
DisableStacktrace: false,
30+
Sampling: nil,
31+
EncoderConfig: encoderCfg,
32+
OutputPaths: []string{
33+
"stdout", // Log info and above to standard output
34+
},
35+
ErrorOutputPaths: []string{
36+
"stderr", // Log internal Zap errors to standard error
37+
},
38+
InitialFields: map[string]interface{}{
39+
"application": "your-application-name", // Customize this field to suit your needs
40+
},
41+
}
42+
43+
// Build the logger from the configuration
44+
logger := zap.Must(config.Build())
45+
46+
// Wrap the Zap logger in your defaultLogger struct, which implements your Logger interface
47+
return &defaultLogger{
48+
logger: logger,
49+
logLevel: LogLevelInfo, // Assuming LogLevelInfo maps to zap.InfoLevel
50+
}
51+
}
52+
53+
// convertToZapLevel converts the custom LogLevel to a zapcore.Level
54+
func convertToZapLevel(level LogLevel) zapcore.Level {
55+
switch level {
56+
case LogLevelDebug:
57+
return zap.DebugLevel
58+
case LogLevelInfo:
59+
return zap.InfoLevel
60+
case LogLevelWarn:
61+
return zap.WarnLevel
62+
case LogLevelError:
63+
return zap.ErrorLevel
64+
case LogLevelDPanic:
65+
return zap.DPanicLevel
66+
case LogLevelPanic:
67+
return zap.PanicLevel
68+
case LogLevelFatal:
69+
return zap.FatalLevel
70+
default:
71+
return zap.InfoLevel // Default to InfoLevel
72+
}
73+
}

0 commit comments

Comments
 (0)