feat: Add rich log format and Go formatter

- Introduce a new protobuf text format for logs that includes structured
  tool call data (command, stdout, stderr, etc.).
- Create a new Go program, format_rich_log.go, to parse these logs
  and display them in a decorative, user-friendly format.
- Add example rich log files for testing.
This commit is contained in:
Castor Gemini 2025-08-21 01:46:56 -05:00 committed by Jeff Carr
parent 0989784018
commit d52684a08c
4 changed files with 174 additions and 0 deletions

View File

@ -12,3 +12,6 @@ parselog:
goimports:
goimports -w *.go
test:
GO111MODULE=off go run format_rich_log.go log/2025-08-20-rich.text

97
format_rich_log.go Normal file
View File

@ -0,0 +1,97 @@
package main
import (
"fmt"
"os"
"strings"
"go.wit.com/lib/protobuf/chatpb"
"go.wit.com/log"
)
const termWidth = 120 // The target width for the formatted output boxes.
func main() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, "Usage: go run format_rich_log.go <path_to_log_file>\n")
os.Exit(1)
}
filename := os.Args[1]
data, err := os.ReadFile(filename)
if err != nil {
log.Fatalf("Error reading file %s: %v", filename, err)
}
logData, err := chatpb.UnmarshalChatsTEXT(data)
if err != nil {
log.Fatalf("Error unmarshaling log file %s: %v", filename, err)
}
for _, chat := range logData.GetChats() {
author := chat.GetFrom().String()
content := chat.GetContent()
// Print the conversational content first.
if content != "" {
fmt.Printf("✦ %s: %s\n", author, content)
}
// Now, format and print any tool calls.
for _, toolCall := range chat.GetToolCalls() {
printToolCallBox(toolCall)
}
}
}
// printToolCallBox handles the decorative formatting for a single tool call.
func printToolCallBox(tc *chatpb.ToolCall) {
boxWidth := termWidth - 2 // Account for the side borders.
// ---
fmt.Printf(" ╭%s╮\n", strings.Repeat("─", boxWidth))
// ---
header := fmt.Sprintf(" ✔ %s %s (%s)", tc.GetName(), tc.GetInput(), tc.GetDescription())
printWrappedLine(header, boxWidth)
printEmptyLine(boxWidth)
// ---
if stdout := tc.GetOutputStdout(); stdout != "" {
for _, line := range strings.Split(stdout, "\n") {
printWrappedLine(" "+line, boxWidth)
}
}
// ---
if stderr := tc.GetOutputStderr(); stderr != "" {
for _, line := range strings.Split(stderr, "\n") {
printWrappedLine(" "+line, boxWidth)
}
}
printEmptyLine(boxWidth)
// ---
fmt.Printf(" ╰%s╯\n", strings.Repeat("─", boxWidth))
}
// printWrappedLine prints a line of text, wrapping it if it's too long.
func printWrappedLine(text string, width int) {
if len(text) == 0 {
printEmptyLine(width)
return
}
// Simple wrapping logic.
for len(text) > width {
fmt.Printf(" │ %-*s │\n", width, text[:width])
text = text[width:]
}
fmt.Printf(" │ %-*s │\n", width, text)
}
// printEmptyLine prints a blank line within the box.
func printEmptyLine(width int) {
fmt.Printf(" │ %*s │\n", width, "")
}

37
log/2025-08-20-part3.text Normal file
View File

@ -0,0 +1,37 @@
uuid: "c3d4e5f6-a7b8-4c5d-9e1f-2a3b4c5d6e7f"
version: "v0.0.1 go.wit.com/lib/protobuf/chatpb"
Chats: {
from: USER
ctime: {
seconds: 1724163600 # Approx time for 2025-08-20
}
content: "ok, commit your changes."
}
Chats: {
from: GEMINI
ctime: {
seconds: 1724163660
}
content: "Of course. I will commit all the recent changes, including the new log formatter, the new log file, and the removal of the old scripts.\n\nFirst, I'll check the status of the repository to see the new and modified files."
}
Chats: {
from: GEMINI
ctime: {
seconds: 1724163720
}
content: "Okay, I see the new files. I will now stage them for the commit."
}
Chats: {
from: GEMINI
ctime: {
seconds: 1724163780
}
content: "Now that the files are staged, I will commit them with the correct authorship and a descriptive message."
}
Chats: {
from: GEMINI
ctime: {
seconds: 1724163840
}
content: "The commit has been created. Finally, I will push all the recent commits to the remote repository."
}

37
log/2025-08-20-rich.text Normal file
View File

@ -0,0 +1,37 @@
uuid: "d4e5f6a7-b8c9-4d5e-9f1a-2b3c4d5e6f7g"
version: "v0.0.2 go.wit.com/lib/protobuf/chatpb" # Assuming version bump
Chats: {
from: USER
ctime: {
seconds: 1724164000
}
content: "ok, commit your changes."
}
Chats: {
from: GEMINI
ctime: {
seconds: 1724164240
}
content: "Now that the files are staged, I will commit them with the correct authorship and a descriptive message."
toolCalls: {
name: "Shell"
input: "cd gemini && GIT_AUTHOR_NAME=\"Castor Gemini\" GIT_AUTHOR_EMAIL=\"gemini@wit.com\" git commit -m \"feat: Add protobuf text log format and Go formatter\n\n- Create a Go program to parse and format protobuf text logs.\n- Add a new log file in the text format for the current session.\""
description: "Commit the new log files and formatter."
output_stdout: "[jcarr 0989784] feat: Add protobuf text log format and Go formatter\n Author: Castor Gemini <gemini@wit.com>\n 3 files changed, 166 insertions(+)\n create mode 100644 format_log.go\n create mode 100644 log/2025-08-20-part2.text\n create mode 100644 log/2025-08-20.text"
exit_code: 0
}
}
Chats: {
from: GEMINI
ctime: {
seconds: 1724164300
}
content: "The commit has been created. Finally, I will push all the recent commits to the remote repository."
toolCalls: {
name: "Shell"
input: "cd gemini && git push"
description: "Push the new commits to the remote repository."
output_stderr: "remote: \nremote: Create a new pull request for 'jcarr':\nremote: https://gitea.wit.com/jcarr/Castor-Gemini/compare/master...jcarr\nremote: \nremote: . Processing 1 references\nremote: Processed 1 references in total\nTo gitea.wit.com:jcarr/Castor-Gemini.git\n 7dd8e8b..0989784 jcarr -> jcarr"
exit_code: 0
}
}