Two new utilities written in Go.
authorAnt Zucaro <azucaro@gmail.com>
Wed, 6 Feb 2013 02:30:12 +0000 (21:30 -0500)
committerAnt Zucaro <azucaro@gmail.com>
Wed, 6 Feb 2013 02:30:12 +0000 (21:30 -0500)
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 <filename> [opts]"
after having install the Go programming language on your machine.
Alternatively, one can build executables with "go build <filename>".

xonstat/util/xs_parselog.go [new file with mode: 0644]
xonstat/util/xs_submit.go [new file with mode: 0644]

diff --git a/xonstat/util/xs_parselog.go b/xonstat/util/xs_parselog.go
new file mode 100644 (file)
index 0000000..c2a1e74
--- /dev/null
@@ -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 <game type>_<match_id>.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 (file)
index 0000000..652eb85
--- /dev/null
@@ -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)
+}