package jsonlog import ( "bufio" "encoding/json" "fmt" "os" "path/filepath" ) // AppendLine appends a single JSON-encoded line and returns the resulting file size. func AppendLine(path string, value interface{}) (int64, error) { data, err := json.Marshal(value) if err != nil { return 0, err } return AppendRawLine(path, data) } // AppendRawLine appends a raw JSON line and returns the resulting file size. func AppendRawLine(path string, line []byte) (int64, error) { if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { return 0, err } f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) if err != nil { return 0, err } defer f.Close() if _, err := f.Write(append(line, '\n')); err != nil { return 0, err } st, err := f.Stat() if err != nil { return 0, err } return st.Size(), nil } // Scan walks each non-empty JSONL line in order. func Scan(path string, fn func(line []byte) error) error { f, err := os.Open(path) if err != nil { return err } defer f.Close() scanner := bufio.NewScanner(f) scanner.Buffer(make([]byte, 0, 64*1024), 8*1024*1024) for scanner.Scan() { line := append([]byte(nil), scanner.Bytes()...) if len(line) == 0 { continue } if err := fn(line); err != nil { return err } } if err := scanner.Err(); err != nil { return fmt.Errorf("scan %s: %w", path, err) } return nil } // FileSize returns 0 when the file does not exist. func FileSize(path string) (int64, error) { st, err := os.Stat(path) if err != nil { if os.IsNotExist(err) { return 0, nil } return 0, err } return st.Size(), nil } // ReadJSON reads a JSON sidecar file into dst. func ReadJSON(path string, dst interface{}) error { data, err := os.ReadFile(path) if err != nil { return err } return json.Unmarshal(data, dst) } // WriteJSON writes a JSON sidecar file atomically enough for local runtime use. func WriteJSON(path string, value interface{}) error { if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { return err } data, err := json.MarshalIndent(value, "", " ") if err != nil { return err } return os.WriteFile(path, data, 0644) }