Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(os/glog): #3200 empty content in glog handler after structure logging feature supported #3475

Merged
merged 9 commits into from
Apr 25, 2024
1 change: 1 addition & 0 deletions contrib/rpc/grpcx/grpcx_unit_z_grpc_server_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ func Test_Grpcx_Grpc_Server_Config_Logger(t *testing.T) {
logFilePath = fmt.Sprintf("/tmp/log/%s.log", gtime.Now().Format("Y-m-d"))
logFileContent = gfile.GetContents(logFilePath)
)
defer gfile.Remove(logFilePath)
t.Assert(gfile.Exists(logFilePath), true)
t.Assert(gstr.Contains(logFileContent, "TestLogger "), true)
})
Expand Down
4 changes: 2 additions & 2 deletions os/gfsnotify/gfsnotify_watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ func (w *Watcher) addWithCallbackFunc(name, path string, callbackFunc func(event

// Close closes the watcher.
func (w *Watcher) Close() {
close(w.closeChan)
w.events.Close()
if err := w.watcher.Close(); err != nil {
intlog.Errorf(context.TODO(), `%+v`, err)
}
w.events.Close()
close(w.closeChan)
}

// Remove removes monitor and all callbacks associated with the `path` recursively.
Expand Down
127 changes: 91 additions & 36 deletions os/glog/glog_logger_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,69 @@ import (
type Handler func(ctx context.Context, in *HandlerInput)

// HandlerInput is the input parameter struct for logging Handler.
//
// The logging content is consisted in:
// TimeFormat [LevelFormat] {TraceId} {CtxStr} Prefix CallerFunc CallerPath Content Values Stack
//
// The header in the logging content is:
// TimeFormat [LevelFormat] {TraceId} {CtxStr} Prefix CallerFunc CallerPath
type HandlerInput struct {
internalHandlerInfo
Logger *Logger // Current Logger object.
Buffer *bytes.Buffer // Buffer for logging content outputs.
Time time.Time // Logging time, which is the time that logging triggers.
TimeFormat string // Formatted time string, like "2016-01-09 12:00:00".
Color int // Using color, like COLOR_RED, COLOR_BLUE, etc. Eg: 34
Level int // Using level, like LEVEL_INFO, LEVEL_ERRO, etc. Eg: 256
LevelFormat string // Formatted level string, like "DEBU", "ERRO", etc. Eg: ERRO
CallerFunc string // The source function name that calls logging, only available if F_CALLER_FN set.
CallerPath string // The source file path and its line number that calls logging, only available if F_FILE_SHORT or F_FILE_LONG set.
CtxStr string // The retrieved context value string from context, only available if Config.CtxKeys configured.
TraceId string // Trace id, only available if OpenTelemetry is enabled.
Prefix string // Custom prefix string for logging content.
Content string // Content is the main logging content without error stack string produced by logger.
Values []any // The passed un-formatted values array to logger.
Stack string // Stack string produced by logger, only available if Config.StStatus configured.
IsAsync bool // IsAsync marks it is in asynchronous logging.

// Current Logger object.
Logger *Logger

// Buffer for logging content outputs.
Buffer *bytes.Buffer

// (ReadOnly) Logging time, which is the time that logging triggers.
Time time.Time

// Formatted time string for output, like "2016-01-09 12:00:00".
TimeFormat string

// (ReadOnly) Using color constant value, like COLOR_RED, COLOR_BLUE, etc.
// Example: 34
Color int

// (ReadOnly) Using level, like LEVEL_INFO, LEVEL_ERRO, etc.
// Example: 256
Level int

// Formatted level string for output, like "DEBU", "ERRO", etc.
// Example: ERRO
LevelFormat string

// The source function name that calls logging, only available if F_CALLER_FN set.
CallerFunc string

// The source file path and its line number that calls logging,
// only available if F_FILE_SHORT or F_FILE_LONG set.
CallerPath string

// The retrieved context value string from context, only available if Config.CtxKeys configured.
// It's empty if no Config.CtxKeys configured.
CtxStr string

// Trace id, only available if OpenTelemetry is enabled, or else it's an empty string.
TraceId string

// Custom prefix string in logging content header part.
// Note that, it takes no effect if HeaderPrint is disabled.
Prefix string

// Custom logging content for logging.
Content string

// The passed un-formatted values array to logger.
Values []any

// Stack string produced by logger, only available if Config.StStatus configured.
// Note that there are usually multiple lines in stack content.
Stack string

// IsAsync marks it is in asynchronous logging.
IsAsync bool
}

type internalHandlerInfo struct {
Expand Down Expand Up @@ -82,6 +127,34 @@ func (in *HandlerInput) String(withColor ...bool) string {
return in.getDefaultBuffer(formatWithColor).String()
}

// ValuesContent converts and returns values as string content.
func (in *HandlerInput) ValuesContent() string {
var (
buffer = bytes.NewBuffer(nil)
valueContent string
)
for _, v := range in.Values {
valueContent = gconv.String(v)
if len(valueContent) == 0 {
continue
}
if buffer.Len() == 0 {
buffer.WriteString(valueContent)
continue
}
if buffer.Bytes()[buffer.Len()-1] != '\n' {
buffer.WriteString(" " + valueContent)
continue
}
// Remove one blank line(\n\n).
if valueContent[0] == '\n' {
valueContent = valueContent[1:]
}
buffer.WriteString(valueContent)
}
return buffer.String()
}

func (in *HandlerInput) getDefaultBuffer(withColor bool) *bytes.Buffer {
buffer := bytes.NewBuffer(nil)
if in.Logger.config.HeaderPrint {
Expand Down Expand Up @@ -121,26 +194,8 @@ func (in *HandlerInput) getDefaultBuffer(withColor bool) *bytes.Buffer {
in.addStringToBuffer(buffer, in.Content)
}

// Convert values string content.
var valueContent string
for _, v := range in.Values {
valueContent = gconv.String(v)
if len(valueContent) == 0 {
continue
}
if buffer.Len() > 0 {
if buffer.Bytes()[buffer.Len()-1] == '\n' {
// Remove one blank line(\n\n).
if valueContent[0] == '\n' {
valueContent = valueContent[1:]
}
buffer.WriteString(valueContent)
} else {
buffer.WriteString(" " + valueContent)
}
} else {
buffer.WriteString(valueContent)
}
if len(in.Values) > 0 {
in.addStringToBuffer(buffer, in.ValuesContent())
}

if in.Stack != "" {
Expand Down
24 changes: 4 additions & 20 deletions os/glog/glog_logger_handler_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"context"

"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/util/gconv"
)

// HandlerOutputJson is the structure outputting logging content as single json.
Expand Down Expand Up @@ -39,26 +38,11 @@ func HandlerJson(ctx context.Context, in *HandlerInput) {
Content: in.Content,
Stack: in.Stack,
}
// Convert values string content.
var valueContent string
for _, v := range in.Values {
valueContent = gconv.String(v)
if len(valueContent) == 0 {
continue
}
if len(output.Content) > 0 {
if output.Content[len(output.Content)-1] == '\n' {
// Remove one blank line(\n\n).
if valueContent[0] == '\n' {
valueContent = valueContent[1:]
}
output.Content += valueContent
} else {
output.Content += " " + valueContent
}
} else {
output.Content += valueContent
if len(in.Values) > 0 {
if output.Content != "" {
output.Content += " "
}
output.Content += in.ValuesContent()
}
// Output json content.
jsonBytes, err := json.Marshal(output)
Expand Down
7 changes: 3 additions & 4 deletions os/glog/glog_z_unit_logger_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,9 @@ func TestLogger_SetHandlers_HandlerJson(t *testing.T) {
ctx = context.WithValue(ctx, "Span-Id", "abcdefg")

l.Debug(ctx, 1, 2, 3)
t.Assert(gstr.Count(w.String(), "1234567890"), 1)
t.Assert(gstr.Count(w.String(), "abcdefg"), 1)
t.Assert(gstr.Count(w.String(), `"1 2 3"`), 1)
t.Assert(gstr.Count(w.String(), `"DEBU"`), 1)
t.Assert(gstr.Count(w.String(), `"CtxStr":"1234567890, abcdefg"`), 1)
t.Assert(gstr.Count(w.String(), `"Content":"1 2 3"`), 1)
t.Assert(gstr.Count(w.String(), `"Level":"DEBU"`), 1)
})
}

Expand Down
Loading