DEV Community

Sheng-Lin Yang
Sheng-Lin Yang

Posted on

A log system for the CLI tool

Repository: CLImanga
Issue: create LOG system (file based) for CLImanga
PR: feat: add log system

The first issue I chose to work on for CLImanga was surprisingly simple at first glance:
"Create a logging system for the project."

Before opening this PR, I had never built a logging system in Go.
I mainly relied on:

  • printf in C
  • console.log
  • console.error

And honestly, I believed those were enough for most programs.

But as I began exploring the issue, I realized a real project requires far more like:

  • Persistent logs
  • Structured messages
  • Error-level separation
  • Execution tracing
  • Debug-friendly information (file, line, timestamp)

This PR became my first deep dive into designing a custom, project-specific logging system.

Based on the issue and discussions with the project owner, the logging system needed to:

  • Write logs to a fixed file: logs/latest.log

  • Provide INFO and ERROR loggers

  • Include metadata:

    • date
    • time
    • file name
    • line number
  • Support helper utilities to easily log:

    • the current function name
    • the start/end of wrapped functions
  • Overwrite the log file on each program run to avoid unlimited growth

These requirements guided my design choices.

The final implementation is located in the log package and uses four Go standard libraries:
I used several libraries like: log, os, runtime, and time:

log:

Info  = log.New(logFile, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
Error = log.New(logFile, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
Enter fullscreen mode Exit fullscreen mode

The flags ensure each log entry includes:

  • date
  • time
  • short file name + line number

os:

Used to manage file and directory operations:

  • Create logs/ directory
  • Open or create latest.log
  • Truncate the file at every startup so the log doesn’t grow forever
os.MkdirAll("logs", 0755)
os.OpenFile("logs/latest.log", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
Enter fullscreen mode Exit fullscreen mode

runtime:

This was the most interesting part.

I learned to use runtime.Caller to retrieve information about the function that called the logger helper:

pc, _, _, _ := runtime.Caller(1)
runtime.FuncForPC(pc).Name()
Enter fullscreen mode Exit fullscreen mode

tip: if switch the number 1 as different number, it means how deeper layer want to know

This allowed me to:

  • Dynamically capture function names
  • Generate messages like:
INFO: Starting function main.DownloadManga
Enter fullscreen mode Exit fullscreen mode

time:

Used to mark program start time in the log:

time.Now().Format(time.RFC3339)
Enter fullscreen mode Exit fullscreen mode

This makes every run easy to identify when debugging.

When implementation, the following is the overall workflow of the logging system:

Initialization (Init())

When the program starts:

  1. Ensure the log directory exists
  2. Create or overwrite latest.log
  3. Create two loggers: Info and Error
  4. Write a startup banner with timestamp
func main() {
  log.Init()
  log.Info.Println("Application Started.")
  catchProgramExit()
  fmt.Println("Welcome to CLImanga!")
  ...
}
Enter fullscreen mode Exit fullscreen mode

Function Wrapping (WrapFunction())

This helper automatically logs:

  • When a function starts
  • When it finishes Example:
func WrapFunction(fn func()) func() {
  return func() {
    Info.Printf("Starting function: %s", functionName)
    fn()
    Info.Printf("Finished function: %s", functionName)
  }
}
Enter fullscreen mode Exit fullscreen mode

This instantly improved debugging readability.

Logging caller function name (LogFunctionName())

This helper logs whichever function invoked it like:

func readChapter(mangaName *string, selectedChapter *manga.ChapterSelect, chapterList *[]manga.ChapterSelect, appInstance fyne.App, appWindow fyne.Window) {
  log.LogFunctionName()
  ui.DisplayChapter(appWindow, 'r', *mangaName, selectedChapter, chapterList)

  appInstance.Run()
}
Enter fullscreen mode Exit fullscreen mode

This was especially helpful during development, when tracing flow across multiple files.

Conclusion

Although this was a "small" feature, it became one of the most educational PRs I have worked on.

It taught me real-world logging techniques, improved my Go skills, and helped me contribute meaningful infrastructure to the CLImanga project.

This logging system will support future development and debugging — including my own future PRs.

Top comments (0)