Last active
January 9, 2020 23:20
-
-
Save Miguel-Dorta/11bfdf577dbaa835e02bb51082ff393d to your computer and use it in GitHub Desktop.
Simple script for concatenating minecraft log files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"compress/gzip" | |
"fmt" | |
"io" | |
"io/ioutil" | |
"os" | |
"path/filepath" | |
"regexp" | |
"sort" | |
"strconv" | |
) | |
// Represents the filename used by Minecraft for the log files | |
var logFileRegex = regexp.MustCompile("^\\d{4}-\\d{2}-\\d{2}-(\\d+)\\.log\\.gz$") | |
// Check for invalid of help args | |
func checkArgs() { | |
if len(os.Args) > 2 { | |
printError("invalid number of arguments") | |
os.Exit(1) | |
} | |
if len(os.Args) < 2 || os.Args[1] == "--help" || os.Args[1] == "-h" { | |
fmt.Println("Usage: mc-log <logs-path>") | |
os.Exit(0) | |
} | |
} | |
func main() { | |
checkArgs() | |
path := os.Args[1] | |
logs, err := getLogMap(path) | |
if err != nil { | |
printError("error getting logs list: %s", err) | |
os.Exit(1) | |
} | |
for dateStr, logFileNumbers := range logs { | |
if err := appendAndRemove(path, dateStr, logFileNumbers); err != nil { | |
printError("error appending logs from %s: %s", dateStr, err) | |
continue | |
} | |
} | |
} | |
// getLogMap returns a map that represents the logs in the path provided. | |
// In this map, a string of the date like this "YYYY-MM-DD" is used as the key, | |
// and a slice of ints that represent each log file in order is the value. | |
// The ints of the value are got from the number represented by $ in the string "YYYY-MM-DD-$.log.gz" | |
func getLogMap(path string) (map[string][]int, error) { | |
logFiles, err := ioutil.ReadDir(path) | |
if err != nil { | |
return nil, fmt.Errorf("error listing logs directory: %s", err) | |
} | |
logMap := make(map[string][]int, len(logFiles)) | |
for _, logFile := range logFiles { | |
if !logFileRegex.MatchString(logFile.Name()) { | |
continue | |
} | |
n, err := strconv.Atoi(logFileRegex.FindStringSubmatch(logFile.Name())[1]) | |
if err != nil { | |
return nil, fmt.Errorf("cannot parse log number in file %s: %s", logFile.Name(), err) | |
} | |
logMap[logFile.Name()[:10]] = append(logMap[logFile.Name()[:10]], n) | |
} | |
return logMap, nil | |
} | |
// appendAndRemove takes the path to the log files, a string of the date of the logs (YYYY-MM-DD) and | |
// a slice of the log numbers (the one marked by the $ symbol in "YYYY-MM-DD-$.log.gz"), and | |
// appends all the logs to a file named YYYY-MM-DD.log | |
func appendAndRemove(logsPath, dateStr string, logNumbers []int) error { | |
destination := filepath.Join(logsPath, dateStr+".log") | |
fDestination, err := os.OpenFile(destination, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644) | |
if err != nil { | |
return fmt.Errorf("error opening or creating file %s: %s", destination, err) | |
} | |
defer fDestination.Close() | |
bufFDestination := bufio.NewWriterSize(fDestination, 128*1024) | |
sort.Ints(logNumbers) | |
for _, logNumber := range logNumbers { | |
originPath := filepath.Join(logsPath, fmt.Sprintf("%s-%d.log.gz", dateStr, logNumber)) | |
if err = decompressTo(originPath, bufFDestination); err != nil { | |
return err | |
} | |
if err = os.Remove(originPath); err != nil { | |
return fmt.Errorf("error removing file already saved (%s): %s", originPath, err) | |
} | |
} | |
if err = bufFDestination.Flush(); err != nil { | |
return fmt.Errorf("error flushing writer buffer in file %s: %s", destination, err) | |
} | |
if err = fDestination.Close(); err != nil { | |
return fmt.Errorf("error closing file %s: %s", destination, err) | |
} | |
return nil | |
} | |
// decompressTo decompress the file in the path provided and writes it to the writer provided. | |
func decompressTo(path string, w io.Writer) error { | |
fOrigin, err := os.Open(path) | |
if err != nil { | |
return fmt.Errorf("error opening file %s: %s", path, err) | |
} | |
defer fOrigin.Close() | |
bufFOrigin, err := gzip.NewReader(bufio.NewReaderSize(fOrigin, 128*1024)) | |
if _, err = io.Copy(w, bufFOrigin); err != nil { | |
return fmt.Errorf("error decompressing and copying file %s: %s", path, err) | |
} | |
return nil | |
} | |
func printError(format string, a ...interface{}) { | |
_, _ = fmt.Fprintf(os.Stderr, format+"\n", a...) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment