2026-05-05 21:45:19 +08:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bufio"
|
2026-05-05 22:52:55 +08:00
|
|
|
"flag"
|
2026-05-05 21:45:19 +08:00
|
|
|
"fmt"
|
2026-05-05 22:52:55 +08:00
|
|
|
"io"
|
2026-05-05 21:45:19 +08:00
|
|
|
"os"
|
|
|
|
|
|
|
|
|
|
"apigo.cc/go/log"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func main() {
|
2026-05-05 22:52:55 +08:00
|
|
|
jsonMode := flag.Bool("json", false, "output in JSON format")
|
|
|
|
|
helpMode := flag.Bool("h", false, "show help")
|
|
|
|
|
flag.BoolVar(helpMode, "help", false, "show help")
|
|
|
|
|
|
|
|
|
|
flag.Usage = func() {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "Usage: logv [options] [file1 file2 ...]\n")
|
|
|
|
|
fmt.Fprintf(os.Stderr, "Options:\n")
|
|
|
|
|
flag.PrintDefaults()
|
|
|
|
|
fmt.Fprintf(os.Stderr, "\nExamples:\n")
|
|
|
|
|
fmt.Fprintf(os.Stderr, " 1. 彩色可视化实时日志:\n")
|
|
|
|
|
fmt.Fprintf(os.Stderr, " tail -f app.log | logv\n")
|
|
|
|
|
fmt.Fprintf(os.Stderr, " 2. 格式化查看历史日志文件:\n")
|
|
|
|
|
fmt.Fprintf(os.Stderr, " logv error.log\n")
|
|
|
|
|
fmt.Fprintf(os.Stderr, " 3. 还原为标准 JSON 格式 (供 Filebeat / Logstash 收集):\n")
|
|
|
|
|
fmt.Fprintf(os.Stderr, " tail -f app.log | logv -json\n")
|
|
|
|
|
fmt.Fprintf(os.Stderr, " 4. 批量转换日志文件为 JSON:\n")
|
|
|
|
|
fmt.Fprintf(os.Stderr, " logv -json app.log.2026* > all_logs.json\n")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flag.Parse()
|
2026-05-05 21:45:19 +08:00
|
|
|
|
2026-05-05 22:52:55 +08:00
|
|
|
if *helpMode {
|
|
|
|
|
flag.Usage()
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-05-05 21:45:19 +08:00
|
|
|
|
2026-05-05 22:52:55 +08:00
|
|
|
// Try to load meta file from current directory
|
|
|
|
|
_ = log.LoadMeta(".log.meta.json")
|
2026-05-05 21:45:19 +08:00
|
|
|
|
2026-05-05 22:52:55 +08:00
|
|
|
args := flag.Args()
|
|
|
|
|
if len(args) == 0 {
|
|
|
|
|
// Check if stdin is a terminal
|
|
|
|
|
stat, _ := os.Stdin.Stat()
|
|
|
|
|
if (stat.Mode() & os.ModeCharDevice) != 0 {
|
|
|
|
|
// Stdin is a terminal and no files provided, show usage
|
|
|
|
|
flag.Usage()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
process(os.Stdin, *jsonMode)
|
|
|
|
|
} else {
|
|
|
|
|
for _, arg := range args {
|
|
|
|
|
f, err := os.Open(arg)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "logv: %v\n", err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
process(f, *jsonMode)
|
|
|
|
|
f.Close()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func process(r io.Reader, jsonMode bool) {
|
|
|
|
|
scanner := bufio.NewScanner(r)
|
2026-05-05 21:45:19 +08:00
|
|
|
for scanner.Scan() {
|
|
|
|
|
line := scanner.Text()
|
|
|
|
|
if len(line) == 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-05 22:52:55 +08:00
|
|
|
if jsonMode {
|
|
|
|
|
fmt.Println(log.ToJSON(line))
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Println(log.Viewable(line))
|
|
|
|
|
}
|
2026-05-05 21:45:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := scanner.Err(); err != nil {
|
2026-05-05 22:52:55 +08:00
|
|
|
fmt.Fprintf(os.Stderr, "logv: error reading input: %v\n", err)
|
2026-05-05 21:45:19 +08:00
|
|
|
}
|
|
|
|
|
}
|