Skip to content

Commit

Permalink
feat: The trace of log can be clicked as a link (#735)
Browse files Browse the repository at this point in the history
* make logs filename clickable

* separate logic of formatStack

* add test cases
  • Loading branch information
kkumar-gcc authored Nov 29, 2024
1 parent d873424 commit 65c6a08
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 11 deletions.
15 changes: 14 additions & 1 deletion log/formatter/general.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,26 @@ func (general *General) formatStackTraces(stackTraces any) (string, error) {
root := traces.Root
if len(root.Stack) > 0 {
for _, stackStr := range root.Stack {
formattedTraces.WriteString(fmt.Sprintf("\t%s\n", stackStr))
formattedTraces.WriteString(formatStackTrace(stackStr))
}
}

return formattedTraces.String(), nil
}

func formatStackTrace(stackStr string) string {
lastColon := strings.LastIndex(stackStr, ":")
if lastColon > 0 && lastColon < len(stackStr)-1 {
secondLastColon := strings.LastIndex(stackStr[:lastColon], ":")
if secondLastColon > 0 {
fileLine := stackStr[secondLastColon+1:]
method := stackStr[:secondLastColon]
return fmt.Sprintf("\t%s [%s]\n", fileLine, method)
}
}
return fmt.Sprintf("\t%s\n", stackStr)
}

func deleteKey(data logrus.Fields, keyToDelete string) logrus.Fields {
dataCopy := make(logrus.Fields)
for key, value := range data {
Expand Down
81 changes: 71 additions & 10 deletions log/formatter/general_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,16 +200,16 @@ func (s *GeneralTestSuite) TestFormatStackTraces() {
"root": map[string]any{
"message": "error bad request", // root cause
"stack": []string{
"main.main:/dummy/examples/logging/example.go:143", // original calling method
"main.ProcessResource:/dummy/examples/logging/example.go:71",
"main.(*Request).Validate:/dummy/examples/logging/example.go:29", // location of Wrap call
"main.(*Request).Validate:/dummy/examples/logging/example.go:28", // location of the root
"/dummy/examples/logging/example.go:143 [main.main]", // original calling method
"/dummy/examples/logging/example.go:71 [main.ProcessResource]",
"/dummy/examples/logging/example.go:29 [main.(*Request).Validate]", // location of Wrap call
"/dummy/examples/logging/example.go:28 [main.(*Request).Validate]", // location of the root
},
},
"wrap": []map[string]any{
{
"message": "received a request with no ID", // additional context
"stack": "main.(*Request).Validate:/dummy/examples/logging/example.go:29", // location of Wrap call
"message": "received a request with no ID", // additional context
"stack": "/dummy/examples/logging/example.go:29 [main.(*Request).Validate]", // location of Wrap call
},
},
}
Expand All @@ -218,10 +218,10 @@ func (s *GeneralTestSuite) TestFormatStackTraces() {
traces, err := general.formatStackTraces(stackTraces)
s.Nil(err)
stackTraces := []string{
"main.main:/dummy/examples/logging/example.go:143",
"main.ProcessResource:/dummy/examples/logging/example.go:71",
"main.(*Request).Validate:/dummy/examples/logging/example.go:29",
"main.(*Request).Validate:/dummy/examples/logging/example.go:28",
"/dummy/examples/logging/example.go:143 [main.main]",
"/dummy/examples/logging/example.go:71 [main.ProcessResource]",
"/dummy/examples/logging/example.go:29 [main.(*Request).Validate]",
"/dummy/examples/logging/example.go:28 [main.(*Request).Validate]",
}
formattedStackTraces := "trace:\n\t" + strings.Join(stackTraces, "\n\t") + "\n"

Expand All @@ -238,6 +238,67 @@ func (s *GeneralTestSuite) TestFormatStackTraces() {
}
}

func TestFormatStackTrace(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{
name: "Valid stack trace with file and method",
input: "main.functionName:/path/to/file.go:42",
expected: "\t/path/to/file.go:42 [main.functionName]\n",
},
{
name: "Valid stack trace without method",
input: "/path/to/file.go:42",
expected: "\t/path/to/file.go:42\n",
},
{
name: "No colons in stack trace",
input: "invalidstacktrace",
expected: "\tinvalidstacktrace\n",
},
{
name: "Single colon in stack trace",
input: "file.go:42",
expected: "\tfile.go:42\n",
},
{
name: "Edge case: Empty string",
input: "",
expected: "\t\n",
},
{
name: "Edge case: Colon at the end",
input: "file.go:",
expected: "\tfile.go:\n",
},
{
name: "Edge case: Colon at the beginning",
input: ":file.go",
expected: "\t:file.go\n",
},
{
name: "Edge case: Multiple colons with no method",
input: "/path/to/file.go:100:200",
expected: "\t100:200 [/path/to/file.go]\n",
},
{
name: "Valid stack trace with nested method and line",
input: "pkg.subpkg.functionName:/path/to/file.go:55",
expected: "\t/path/to/file.go:55 [pkg.subpkg.functionName]\n",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := formatStackTrace(tt.input)
assert.Equal(t, tt.expected, result)
})
}
}

func TestDeleteKey(t *testing.T) {
tests := []struct {
name string
Expand Down

0 comments on commit 65c6a08

Please sign in to comment.