From: Ant Zucaro Date: Wed, 6 Feb 2013 02:30:12 +0000 (-0500) Subject: Two new utilities written in Go. X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fxonstat.git;a=commitdiff_plain;h=9a2bd083a5df36a119e99c397e603d4f6610f575 Two new utilities written in Go. xs_parselog parses XonStat log and extracts/recreates requests into text files, one request per file. xs_submit takes a XonStat request via a text file and submits it to a user-specified URL. Both of these utlities can be run with "go run [opts]" after having install the Go programming language on your machine. Alternatively, one can build executables with "go build ". --- diff --git a/xonstat/util/xs_parselog.go b/xonstat/util/xs_parselog.go new file mode 100644 index 0000000..c2a1e74 --- /dev/null +++ b/xonstat/util/xs_parselog.go @@ -0,0 +1,89 @@ +package main + +import "bufio" +import "flag" +import "fmt" +import "os" +import "strings" + +/* xs_parselog parses a standard XonStat log and breaks it down into + individual requests which are then saved into files. The file format + is _.txt, so one can easily identify which type + of request the file contains and which one it is (the match_id is the + 'I' line in the actual request). + + There is also the ability to extract a specific match as well as to + anonymize the hashkeys in the requests to prevent exposing player data + unnecessarily. */ +func main() { + var fn = flag.String("file", "xonstat.log", "XonStat log file name") + var target_match_id = flag.String("match", "", "the specific match_id (I line) to extract from the log") + var anonymize = flag.Bool("anonymize", false, "whether or not to anonymize player hashkeys") + flag.Parse() + + f, err := os.Open(*fn) + if err != nil { + fmt.Println("Issue opening file") + os.Exit(1) + } + defer f.Close() + + r := bufio.NewReader(f) + + var inreq bool + var match_id string + var game_type_cd string + lines := make([]string, 0, 100) + hashkeys := make(map[string] int, 500) + max_player_id := 0 + + line, err := r.ReadString('\n') + for err == nil { + switch { + case strings.Contains(line, "BEGIN REQUEST BODY"): + inreq = true + case strings.Contains(line, "END REQUEST BODY"): + if *target_match_id == "" || match_id == *target_match_id { + create_match_file(game_type_cd, match_id, lines) + } + inreq = false + lines = make([]string, 0, 100) + case inreq: + if *anonymize && line[0] == 'P' { + if line[2:5] != "bot" && line[2:8] != "player" { + hashkey := line[2:len(line)-1] + if _, ok := hashkeys[hashkey]; !ok { + hashkeys[hashkey] = max_player_id + max_player_id = max_player_id + 1 + } + line = fmt.Sprintf("P %d\n", hashkeys[hashkey]) + } + } + if line[0] == 'I' { + match_id = line[2:len(line)-1] + } + if line[0] == 'G' { + game_type_cd = line[2:len(line)-1] + } + lines = append(lines, line) + } + + line, err = r.ReadString('\n') + } +} + + +func create_match_file(game_type_cd string, match_id string, body []string) { + fn := fmt.Sprintf("%s_%s.txt", game_type_cd, match_id) + f_raw, err := os.Create(fn) + if err != nil { + fmt.Printf("Error creating match_id %s.\n", match_id) + } + defer f_raw.Close() + + f := bufio.NewWriter(f_raw) + for _, v := range body { + fmt.Fprint(f, v) + } + f.Flush() +} diff --git a/xonstat/util/xs_submit.go b/xonstat/util/xs_submit.go new file mode 100644 index 0000000..652eb85 --- /dev/null +++ b/xonstat/util/xs_submit.go @@ -0,0 +1,32 @@ +package main + +import "bytes" +import "flag" +import "fmt" +import "io/ioutil" +import "net/http" +import "os" + +/* xs_submit takes a file containing a single XonStat request and submits it + to the server URL specified */ +func main() { + var fn = flag.String("file", "xonstat.log", "Logfile from XonStat") + var url = flag.String("url", "http://localhost:6543/stats/submit", "XonStat submission URL") + flag.Parse() + + body, err := ioutil.ReadFile(*fn) + if err != nil { + fmt.Printf("Issue opening file %s\n", *fn) + os.Exit(1) + } + contentlength := int64(len(body)) + + r := bytes.NewReader(body) + + req, _ := http.NewRequest("POST", *url, r) + req.ContentLength = contentlength + res, _ := http.DefaultClient.Do(req) + defer res.Body.Close() + + fmt.Printf("%s: %s\n", *fn, res.Status) +}