Files
logpile/cmd/logpile/main.go
T
mchusandClaude Sonnet 4.6 57de3ba6eb chore: align codebase with bible engineering contracts
- identifier-normalization: use strings.EqualFold in h3c/parser.go
- import-export: CSV now uses UTF-8 BOM and semicolon delimiter
- go-code-style: translate all Russian source strings to English (ADL-007)
- go-background-tasks: add Type, Message, Result fields to Job struct
- go-api: wrap list endpoints in {items, total_count, page, per_page, total_pages}
- module-structure: rename helpers.go → context_sleep.go
- build-version-display: htmlError renders version footer on error pages
- go-logging: migrate all log.Printf calls to log/slog with structured attrs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 14:35:39 +03:00

125 lines
2.9 KiB
Go

package main
import (
"bufio"
"flag"
"fmt"
"log/slog"
"os"
"os/exec"
"runtime"
"strings"
"time"
"git.mchus.pro/mchus/logpile/internal/parser"
_ "git.mchus.pro/mchus/logpile/internal/parser/vendors" // Register all vendor parsers
"git.mchus.pro/mchus/logpile/internal/server"
"git.mchus.pro/mchus/logpile/web"
)
var (
version = "dev"
commit = "none"
)
func main() {
holdOnCrash := flag.Bool("hold-on-crash", runtime.GOOS == "windows", "Wait for Enter on crash to keep console open")
port := flag.Int("port", 8082, "HTTP server port")
file := flag.String("file", "", "Pre-load archive file")
showVersion := flag.Bool("version", false, "Show version")
noBrowser := flag.Bool("no-browser", false, "Don't open browser automatically")
flag.Parse()
if *showVersion {
fmt.Printf("LOGPile %s (commit: %s)\n", version, commit)
os.Exit(0)
}
// Set embedded web files
server.WebFS = web.FS
cfg := server.Config{
Port: *port,
PreloadFile: *file,
AppVersion: version,
AppCommit: commit,
ChartVersion: detectChartVersion(),
}
srv := server.New(cfg)
url := fmt.Sprintf("http://localhost:%d", *port)
slog.Info("LOGPile starting", "url", url)
slog.Info("registered parsers", "parsers", parser.ListParsers())
// Open browser automatically
if !*noBrowser {
go func() {
time.Sleep(500 * time.Millisecond) // Wait for server to start
openBrowser(url)
}()
}
if err := runServer(srv); err != nil {
slog.Error("fatal error", "err", err)
maybeWaitForCrashInput(*holdOnCrash)
os.Exit(1)
}
}
func runServer(srv *server.Server) (runErr error) {
defer func() {
if recovered := recover(); recovered != nil {
runErr = fmt.Errorf("panic: %v", recovered)
}
}()
return srv.Run()
}
// openBrowser opens the default browser with the given URL
func openBrowser(url string) {
var cmd *exec.Cmd
switch runtime.GOOS {
case "darwin":
cmd = exec.Command("open", url)
case "windows":
cmd = exec.Command("rundll32", "url.dll,FileProtocolHandler", url)
default: // linux and others
cmd = exec.Command("xdg-open", url)
}
if err := cmd.Start(); err != nil {
slog.Warn("failed to open browser", "err", err)
}
}
func detectChartVersion() string {
cmd := exec.Command("git", "-C", "internal/chart", "describe", "--tags", "--always", "--dirty", "--abbrev=7")
out, err := cmd.Output()
if err != nil {
return ""
}
return strings.TrimSpace(string(out))
}
func maybeWaitForCrashInput(enabled bool) {
if !enabled || !isInteractiveConsole() {
return
}
fmt.Fprintln(os.Stderr, "\nApplication crashed. Press Enter to close...")
_, _ = bufio.NewReader(os.Stdin).ReadString('\n')
}
func isInteractiveConsole() bool {
stdinInfo, err := os.Stdin.Stat()
if err != nil {
return false
}
stderrInfo, err := os.Stderr.Stat()
if err != nil {
return false
}
return (stdinInfo.Mode()&os.ModeCharDevice) != 0 && (stderrInfo.Mode()&os.ModeCharDevice) != 0
}