diff options
Diffstat (limited to 'logtail/example/logreprocess')
| -rwxr-xr-x | logtail/example/logreprocess/demo.sh | 172 | ||||
| -rw-r--r-- | logtail/example/logreprocess/logreprocess.go | 230 |
2 files changed, 201 insertions, 201 deletions
diff --git a/logtail/example/logreprocess/demo.sh b/logtail/example/logreprocess/demo.sh index 4ec819a67..eaec706a3 100755 --- a/logtail/example/logreprocess/demo.sh +++ b/logtail/example/logreprocess/demo.sh @@ -1,86 +1,86 @@ -#!/bin/bash -# Copyright (c) Tailscale Inc & AUTHORS -# SPDX-License-Identifier: BSD-3-Clause - -# -# This shell script demonstrates writing logs from machines -# and then reprocessing those logs to amalgamate python tracebacks -# into a single log entry in a new collection. -# -# To run this demo, first install the example applications: -# -# go install tailscale.com/logtail/example/... -# -# Then generate a LOGTAIL_API_KEY and two test collections by visiting: -# -# https://log.tailscale.io -# -# Then set the three variables below. -trap 'rv=$?; [ "$rv" = 0 ] || echo "-- exiting with code $rv"; exit $rv' EXIT -set -e - -LOG_TEXT='server starting -config file loaded -answering queries -Traceback (most recent call last): - File "/Users/crawshaw/junk.py", line 6, in <module> - main() - File "/Users/crawshaw/junk.py", line 4, in main - raise Exception("oops") -Exception: oops' - -die() { - echo "$0: $*" >&2 - exit 1 -} - -msg() { - echo "-- $*" >&2 -} - -if [ -z "$LOGTAIL_API_KEY" ]; then - die "LOGTAIL_API_KEY is not set" -fi - -if [ -z "$COLLECTION_IN" ]; then - die "COLLECTION_IN is not set" -fi - -if [ -z "$COLLECTION_OUT" ]; then - die "COLLECTION_OUT is not set" -fi - -# Private IDs are 32-bytes of random hex. -# Normally you'd keep the same private IDs from one run to the next, but -# this is just an example. -msg "Generating keys..." -privateid1=$(hexdump -n 32 -e '8/4 "%08X"' /dev/urandom) -privateid2=$(hexdump -n 32 -e '8/4 "%08X"' /dev/urandom) -privateid3=$(hexdump -n 32 -e '8/4 "%08X"' /dev/urandom) - -# Public IDs are the SHA-256 of the private ID. -publicid1=$(echo -n $privateid1 | xxd -r -p - | shasum -a 256 | sed 's/ -//') -publicid2=$(echo -n $privateid2 | xxd -r -p - | shasum -a 256 | sed 's/ -//') -publicid3=$(echo -n $privateid3 | xxd -r -p - | shasum -a 256 | sed 's/ -//') - -# Write the machine logs to the input collection. -# Notice that this doesn't require an API key. -msg "Producing new logs..." -echo "$LOG_TEXT" | logtail -c $COLLECTION_IN -k $privateid1 >/dev/null -echo "$LOG_TEXT" | logtail -c $COLLECTION_IN -k $privateid2 >/dev/null - -# Adopt the logs, so they will be kept and are readable. -msg "Adopting logs..." -logadopt -p "$LOGTAIL_API_KEY" -c "$COLLECTION_IN" -m $publicid1 -logadopt -p "$LOGTAIL_API_KEY" -c "$COLLECTION_IN" -m $publicid2 - -# Reprocess the logs, amalgamating python tracebacks. -# -# We'll take that reprocessed output and write it to a separate collection, -# again via logtail. -# -# Time out quickly because all our "interesting" logs (generated -# above) have already been processed. -msg "Reprocessing logs..." -logreprocess -t 3s -c "$COLLECTION_IN" -p "$LOGTAIL_API_KEY" 2>&1 | - logtail -c "$COLLECTION_OUT" -k $privateid3 +#!/bin/bash
+# Copyright (c) Tailscale Inc & AUTHORS
+# SPDX-License-Identifier: BSD-3-Clause
+
+#
+# This shell script demonstrates writing logs from machines
+# and then reprocessing those logs to amalgamate python tracebacks
+# into a single log entry in a new collection.
+#
+# To run this demo, first install the example applications:
+#
+# go install tailscale.com/logtail/example/...
+#
+# Then generate a LOGTAIL_API_KEY and two test collections by visiting:
+#
+# https://log.tailscale.io
+#
+# Then set the three variables below.
+trap 'rv=$?; [ "$rv" = 0 ] || echo "-- exiting with code $rv"; exit $rv' EXIT
+set -e
+
+LOG_TEXT='server starting
+config file loaded
+answering queries
+Traceback (most recent call last):
+ File "/Users/crawshaw/junk.py", line 6, in <module>
+ main()
+ File "/Users/crawshaw/junk.py", line 4, in main
+ raise Exception("oops")
+Exception: oops'
+
+die() {
+ echo "$0: $*" >&2
+ exit 1
+}
+
+msg() {
+ echo "-- $*" >&2
+}
+
+if [ -z "$LOGTAIL_API_KEY" ]; then
+ die "LOGTAIL_API_KEY is not set"
+fi
+
+if [ -z "$COLLECTION_IN" ]; then
+ die "COLLECTION_IN is not set"
+fi
+
+if [ -z "$COLLECTION_OUT" ]; then
+ die "COLLECTION_OUT is not set"
+fi
+
+# Private IDs are 32-bytes of random hex.
+# Normally you'd keep the same private IDs from one run to the next, but
+# this is just an example.
+msg "Generating keys..."
+privateid1=$(hexdump -n 32 -e '8/4 "%08X"' /dev/urandom)
+privateid2=$(hexdump -n 32 -e '8/4 "%08X"' /dev/urandom)
+privateid3=$(hexdump -n 32 -e '8/4 "%08X"' /dev/urandom)
+
+# Public IDs are the SHA-256 of the private ID.
+publicid1=$(echo -n $privateid1 | xxd -r -p - | shasum -a 256 | sed 's/ -//')
+publicid2=$(echo -n $privateid2 | xxd -r -p - | shasum -a 256 | sed 's/ -//')
+publicid3=$(echo -n $privateid3 | xxd -r -p - | shasum -a 256 | sed 's/ -//')
+
+# Write the machine logs to the input collection.
+# Notice that this doesn't require an API key.
+msg "Producing new logs..."
+echo "$LOG_TEXT" | logtail -c $COLLECTION_IN -k $privateid1 >/dev/null
+echo "$LOG_TEXT" | logtail -c $COLLECTION_IN -k $privateid2 >/dev/null
+
+# Adopt the logs, so they will be kept and are readable.
+msg "Adopting logs..."
+logadopt -p "$LOGTAIL_API_KEY" -c "$COLLECTION_IN" -m $publicid1
+logadopt -p "$LOGTAIL_API_KEY" -c "$COLLECTION_IN" -m $publicid2
+
+# Reprocess the logs, amalgamating python tracebacks.
+#
+# We'll take that reprocessed output and write it to a separate collection,
+# again via logtail.
+#
+# Time out quickly because all our "interesting" logs (generated
+# above) have already been processed.
+msg "Reprocessing logs..."
+logreprocess -t 3s -c "$COLLECTION_IN" -p "$LOGTAIL_API_KEY" 2>&1 |
+ logtail -c "$COLLECTION_OUT" -k $privateid3
diff --git a/logtail/example/logreprocess/logreprocess.go b/logtail/example/logreprocess/logreprocess.go index 5dbf76578..e88d5b485 100644 --- a/logtail/example/logreprocess/logreprocess.go +++ b/logtail/example/logreprocess/logreprocess.go @@ -1,115 +1,115 @@ -// Copyright (c) Tailscale Inc & AUTHORS -// SPDX-License-Identifier: BSD-3-Clause - -// The logreprocess program tails a log and reprocesses it. -package main - -import ( - "bufio" - "encoding/json" - "flag" - "io" - "log" - "net/http" - "os" - "strings" - "time" - - "tailscale.com/types/logid" -) - -func main() { - collection := flag.String("c", "", "logtail collection name to read") - apiKey := flag.String("p", "", "logtail API key") - timeout := flag.Duration("t", 0, "timeout after which logreprocess quits") - flag.Parse() - if len(flag.Args()) != 0 { - flag.Usage() - os.Exit(1) - } - log.SetFlags(0) - - if *timeout != 0 { - go func() { - <-time.After(*timeout) - log.Printf("logreprocess: timeout reached, quitting") - os.Exit(1) - }() - } - - req, err := http.NewRequest("GET", "https://log.tailscale.io/c/"+*collection+"?stream=true", nil) - if err != nil { - log.Fatal(err) - } - req.SetBasicAuth(*apiKey, "") - resp, err := http.DefaultClient.Do(req) - if err != nil { - log.Fatal(err) - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - b, err := io.ReadAll(resp.Body) - if err != nil { - log.Fatalf("logreprocess: read error %d: %v", resp.StatusCode, err) - } - log.Fatalf("logreprocess: read error %d: %s", resp.StatusCode, string(b)) - } - - tracebackCache := make(map[logid.PublicID]*ProcessedMsg) - - scanner := bufio.NewScanner(resp.Body) - for scanner.Scan() { - var msg Msg - if err := json.Unmarshal(scanner.Bytes(), &msg); err != nil { - log.Fatalf("logreprocess of %q: %v", string(scanner.Bytes()), err) - } - var pMsg *ProcessedMsg - if pMsg = tracebackCache[msg.Logtail.Instance]; pMsg != nil { - pMsg.Text += "\n" + msg.Text - if strings.HasPrefix(msg.Text, "Exception: ") { - delete(tracebackCache, msg.Logtail.Instance) - } else { - continue // write later - } - } else { - pMsg = &ProcessedMsg{ - OrigInstance: msg.Logtail.Instance, - Text: msg.Text, - } - pMsg.Logtail.ClientTime = msg.Logtail.ClientTime - } - - if strings.HasPrefix(msg.Text, "Traceback (most recent call last):") { - tracebackCache[msg.Logtail.Instance] = pMsg - continue // write later - } - - b, err := json.Marshal(pMsg) - if err != nil { - log.Fatal(err) - } - log.Printf("%s", b) - } - if err := scanner.Err(); err != nil { - log.Fatal(err) - } -} - -type Msg struct { - Logtail struct { - Instance logid.PublicID `json:"instance"` - ClientTime time.Time `json:"client_time"` - } `json:"logtail"` - - Text string `json:"text"` -} - -type ProcessedMsg struct { - Logtail struct { - ClientTime time.Time `json:"client_time"` - } `json:"logtail"` - - OrigInstance logid.PublicID `json:"orig_instance"` - Text string `json:"text"` -} +// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+// The logreprocess program tails a log and reprocesses it.
+package main
+
+import (
+ "bufio"
+ "encoding/json"
+ "flag"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "strings"
+ "time"
+
+ "tailscale.com/types/logid"
+)
+
+func main() {
+ collection := flag.String("c", "", "logtail collection name to read")
+ apiKey := flag.String("p", "", "logtail API key")
+ timeout := flag.Duration("t", 0, "timeout after which logreprocess quits")
+ flag.Parse()
+ if len(flag.Args()) != 0 {
+ flag.Usage()
+ os.Exit(1)
+ }
+ log.SetFlags(0)
+
+ if *timeout != 0 {
+ go func() {
+ <-time.After(*timeout)
+ log.Printf("logreprocess: timeout reached, quitting")
+ os.Exit(1)
+ }()
+ }
+
+ req, err := http.NewRequest("GET", "https://log.tailscale.io/c/"+*collection+"?stream=true", nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+ req.SetBasicAuth(*apiKey, "")
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != 200 {
+ b, err := io.ReadAll(resp.Body)
+ if err != nil {
+ log.Fatalf("logreprocess: read error %d: %v", resp.StatusCode, err)
+ }
+ log.Fatalf("logreprocess: read error %d: %s", resp.StatusCode, string(b))
+ }
+
+ tracebackCache := make(map[logid.PublicID]*ProcessedMsg)
+
+ scanner := bufio.NewScanner(resp.Body)
+ for scanner.Scan() {
+ var msg Msg
+ if err := json.Unmarshal(scanner.Bytes(), &msg); err != nil {
+ log.Fatalf("logreprocess of %q: %v", string(scanner.Bytes()), err)
+ }
+ var pMsg *ProcessedMsg
+ if pMsg = tracebackCache[msg.Logtail.Instance]; pMsg != nil {
+ pMsg.Text += "\n" + msg.Text
+ if strings.HasPrefix(msg.Text, "Exception: ") {
+ delete(tracebackCache, msg.Logtail.Instance)
+ } else {
+ continue // write later
+ }
+ } else {
+ pMsg = &ProcessedMsg{
+ OrigInstance: msg.Logtail.Instance,
+ Text: msg.Text,
+ }
+ pMsg.Logtail.ClientTime = msg.Logtail.ClientTime
+ }
+
+ if strings.HasPrefix(msg.Text, "Traceback (most recent call last):") {
+ tracebackCache[msg.Logtail.Instance] = pMsg
+ continue // write later
+ }
+
+ b, err := json.Marshal(pMsg)
+ if err != nil {
+ log.Fatal(err)
+ }
+ log.Printf("%s", b)
+ }
+ if err := scanner.Err(); err != nil {
+ log.Fatal(err)
+ }
+}
+
+type Msg struct {
+ Logtail struct {
+ Instance logid.PublicID `json:"instance"`
+ ClientTime time.Time `json:"client_time"`
+ } `json:"logtail"`
+
+ Text string `json:"text"`
+}
+
+type ProcessedMsg struct {
+ Logtail struct {
+ ClientTime time.Time `json:"client_time"`
+ } `json:"logtail"`
+
+ OrigInstance logid.PublicID `json:"orig_instance"`
+ Text string `json:"text"`
+}
|
