commit addbf6dbc518ffb46d18e1d10086dd9a63cb611c Author: Colin Date: Mon Jul 22 20:26:18 2024 -0400 baseline diff --git a/README.md b/README.md new file mode 100644 index 0000000..c4dc726 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +You can stream and read files to a sentry DSN glitchtip or sentry itself I was fed up with how brittle sentry-cli was so I made this. + +I might get around to making a whole CI/CD process for this which will upload the executables properly at some point and make this public. +# Go Glitch + +Go Glitch is a command-line utility that reads log messages from a file or stdin and sends them to Glitchtip, a self-hosted Sentry-compatible error tracking system. + +## Installation + +To install the binary locally, you can use the provided installation script. Run the following command in your terminal: + +```sh +curl -sSL https://git.nixc.us/Nixius/go-glitch/raw/branch/master/install.sh | bash +``` + +This will download and install the Go Glitch binary to your local machine. + +## Usage + +You can use Go Glitch by specifying a log file as an argument or by piping input to it. + +### Using a Log File + +```sh +go-glitch /path/to/logfile +``` + +### Using Piped Input + +```sh +cat /path/to/logfile | go-glitch +``` + +## Configuration + +Go Glitch requires the `GLITCHTIP_DSN` environment variable to be set with your Glitchtip DSN. You can set this environment variable in your shell environment, Dockerfile, or `docker-compose.yml` file. + +### Shell Environment + +Add the following line to your `.zshrc` or `.bashrc` file: + +```sh +export GLITCHTIP_DSN="your-glitchtip-dsn" +``` + +After adding the line, reload your shell configuration: + +```sh +source ~/.zshrc # for zsh users +source ~/.bashrc # for bash users +``` + +### Dockerfile + +If you are using a Docker container, add the environment variable in your `Dockerfile`: + +```Dockerfile +ENV GLITCHTIP_DSN=your-glitchtip-dsn +``` + +### docker-compose.yml + +If you are using Docker Compose, add the environment variable in your `docker-compose.yml` file: + +```yaml +version: '3.8' + +services: + go-glitch: + image: your-docker-image + environment: + - GLITCHTIP_DSN=your-glitchtip-dsn +``` diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..03907e4 --- /dev/null +++ b/build.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +ARCHITECTURES=("linux/amd64" "linux/arm64" "darwin/amd64" "darwin/arm64" "windows/amd64") +PROJECT_NAME=$(basename "$(pwd)") + +prepare_build() { + mkdir -p dist build_logs + if [ ! -f go.mod ]; then + go mod init "$PROJECT_NAME" + fi + go mod tidy +} + +build_binary() { + local os=$1 + local arch=$2 + local output="dist/${PROJECT_NAME}_${os}_${arch}" + env GOOS=$os GOARCH=$arch go build -o $output . &> "build_logs/${os}_${arch}.log" + if [ $? -ne 0 ]; then + echo "Build failed for $os/$arch" >> "build_logs/error.log" + else + echo "Build succeeded for $os/$arch" + fi + if [ "$os" == "linux" ]; then + env GOOS=$os GOARCH=$arch CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' -o "${output}_static" . &> "build_logs/${os}_${arch}_static.log" + if [ $? -ne 0 ]; then + echo "Static build failed for $os/$arch" >> "build_logs/error.log" + else + echo "Static build succeeded for $os/$arch" + fi + fi +} + +main() { + prepare_build + for arch in "${ARCHITECTURES[@]}"; do + IFS="/" read -r os arch <<< "$arch" + build_binary $os $arch + done + echo "Build process completed." +} + +main diff --git a/build_logs/darwin_amd64.log b/build_logs/darwin_amd64.log new file mode 100644 index 0000000..0dfad58 --- /dev/null +++ b/build_logs/darwin_amd64.log @@ -0,0 +1,2 @@ +# inotify-glitch +./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value diff --git a/build_logs/darwin_arm64.log b/build_logs/darwin_arm64.log new file mode 100644 index 0000000..0dfad58 --- /dev/null +++ b/build_logs/darwin_arm64.log @@ -0,0 +1,2 @@ +# inotify-glitch +./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value diff --git a/build_logs/error.log b/build_logs/error.log new file mode 100644 index 0000000..4f7d59e --- /dev/null +++ b/build_logs/error.log @@ -0,0 +1,7 @@ +Build failed for linux/amd64 +Static build failed for linux/amd64 +Build failed for linux/arm64 +Static build failed for linux/arm64 +Build failed for darwin/amd64 +Build failed for darwin/arm64 +Build failed for windows/amd64 diff --git a/build_logs/linux_amd64.log b/build_logs/linux_amd64.log new file mode 100644 index 0000000..0dfad58 --- /dev/null +++ b/build_logs/linux_amd64.log @@ -0,0 +1,2 @@ +# inotify-glitch +./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value diff --git a/build_logs/linux_amd64_static.log b/build_logs/linux_amd64_static.log new file mode 100644 index 0000000..0dfad58 --- /dev/null +++ b/build_logs/linux_amd64_static.log @@ -0,0 +1,2 @@ +# inotify-glitch +./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value diff --git a/build_logs/linux_arm64.log b/build_logs/linux_arm64.log new file mode 100644 index 0000000..0dfad58 --- /dev/null +++ b/build_logs/linux_arm64.log @@ -0,0 +1,2 @@ +# inotify-glitch +./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value diff --git a/build_logs/linux_arm64_static.log b/build_logs/linux_arm64_static.log new file mode 100644 index 0000000..0dfad58 --- /dev/null +++ b/build_logs/linux_arm64_static.log @@ -0,0 +1,2 @@ +# inotify-glitch +./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value diff --git a/build_logs/windows_amd64.log b/build_logs/windows_amd64.log new file mode 100644 index 0000000..0dfad58 --- /dev/null +++ b/build_logs/windows_amd64.log @@ -0,0 +1,2 @@ +# inotify-glitch +./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value diff --git a/dist/inotify-glitch_darwin_amd64 b/dist/inotify-glitch_darwin_amd64 new file mode 100755 index 0000000..6594389 Binary files /dev/null and b/dist/inotify-glitch_darwin_amd64 differ diff --git a/dist/inotify-glitch_darwin_arm64 b/dist/inotify-glitch_darwin_arm64 new file mode 100755 index 0000000..9122803 Binary files /dev/null and b/dist/inotify-glitch_darwin_arm64 differ diff --git a/dist/inotify-glitch_linux_amd64 b/dist/inotify-glitch_linux_amd64 new file mode 100755 index 0000000..e8a4f06 Binary files /dev/null and b/dist/inotify-glitch_linux_amd64 differ diff --git a/dist/inotify-glitch_linux_amd64_static b/dist/inotify-glitch_linux_amd64_static new file mode 100755 index 0000000..4db1ef2 Binary files /dev/null and b/dist/inotify-glitch_linux_amd64_static differ diff --git a/dist/inotify-glitch_linux_arm64 b/dist/inotify-glitch_linux_arm64 new file mode 100755 index 0000000..f17d5a1 Binary files /dev/null and b/dist/inotify-glitch_linux_arm64 differ diff --git a/dist/inotify-glitch_linux_arm64_static b/dist/inotify-glitch_linux_arm64_static new file mode 100755 index 0000000..77a4b40 Binary files /dev/null and b/dist/inotify-glitch_linux_arm64_static differ diff --git a/dist/inotify-glitch_windows_amd64 b/dist/inotify-glitch_windows_amd64 new file mode 100755 index 0000000..306512e Binary files /dev/null and b/dist/inotify-glitch_windows_amd64 differ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2451622 --- /dev/null +++ b/go.mod @@ -0,0 +1,13 @@ +module inotify-glitch + +go 1.21.1 + +require ( + github.com/fsnotify/fsnotify v1.7.0 + github.com/getsentry/sentry-go v0.28.1 +) + +require ( + golang.org/x/sys v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..fa5f24d --- /dev/null +++ b/go.sum @@ -0,0 +1,24 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/getsentry/sentry-go v0.28.1 h1:zzaSm/vHmGllRM6Tpx1492r0YDzauArdBfkJRtY6P5k= +github.com/getsentry/sentry-go v0.28.1/go.mod h1:1fQZ+7l7eeJ3wYi82q5Hg8GqAPgefRq+FP/QhafYVgg= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..790547d --- /dev/null +++ b/install.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +INSTALL_DIR="/usr/local/bin" +BINARY_NAME="go-glitch" +BASE_URL="https://git.nixc.us/Nixius/go-glitch/raw/branch/master/dist" + + +# Supported architectures +ARCHITECTURES=("linux/amd64" "linux/arm64" "linux/arm/v7" "darwin/amd64" "darwin/arm64") + +OS="$(uname -s | tr '[:upper:]' '[:lower:]')" +ARCH="$(uname -m)" + +case $ARCH in + x86_64) ARCH="amd64" ;; + arm64 | aarch64) ARCH="arm64" ;; + arm*) ARCH="arm/v7" ;; + *) echo "Unsupported architecture: $ARCH"; exit 1 ;; +esac + +BINARY_URL="${BASE_URL}/${BINARY_NAME}_${OS}_${ARCH}" + +echo "Downloading and installing $BINARY_NAME from $BINARY_URL..." + +# Check if we have write permission to the install directory +if [ -w "${INSTALL_DIR}" ]; then + curl -sSL "$BINARY_URL" -o "${INSTALL_DIR}/${BINARY_NAME}" + chmod +x "${INSTALL_DIR}/${BINARY_NAME}" +else + sudo curl -sSL "$BINARY_URL" -o "${INSTALL_DIR}/${BINARY_NAME}" + sudo chmod +x "${INSTALL_DIR}/${BINARY_NAME}" +fi + +echo "Installed $BINARY_NAME to $INSTALL_DIR" diff --git a/main.go b/main.go new file mode 100644 index 0000000..5c3e462 --- /dev/null +++ b/main.go @@ -0,0 +1,139 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strings" + "time" + + "github.com/fsnotify/fsnotify" + "github.com/getsentry/sentry-go" +) + +var debug bool + +func main() { + // Check if debug mode is enabled + if os.Getenv("DEBUG") == "true" { + debug = true + } + + // Get the DSN from the environment + dsn := os.Getenv("GLITCHTIP_DSN") + if dsn == "" { + fmt.Fprintf(os.Stderr, "Error: GLITCHTIP_DSN environment variable is not set.\n") + os.Exit(1) + } + + // Initialize Sentry + err := sentry.Init(sentry.ClientOptions{ + Dsn: dsn, + }) + if err != nil { + fmt.Fprintf(os.Stderr, "Error initializing GlitchTip: %s\n", err) + os.Exit(1) + } + defer sentry.Flush(2 * time.Second) + + // Get the log files from the environment + logFilesEnv := os.Getenv("LOG_FILES") + if logFilesEnv == "" { + fmt.Fprintf(os.Stderr, "Error: LOG_FILES environment variable is not set.\n") + os.Exit(1) + } + logFiles := strings.Split(logFilesEnv, ",") + + // Create a new file watcher + watcher, err := fsnotify.NewWatcher() + if err != nil { + fmt.Fprintf(os.Stderr, "Error creating watcher: %s\n", err) + os.Exit(1) + } + defer watcher.Close() + + // Add log files to the watcher + for _, logFile := listFiles(logFiles) { + if debug { + fmt.Printf("Adding file to watcher: %s\n", logFile) + } + err = watcher.Add(logFile) + if err != nil { + fmt.Fprintf(os.Stderr, "Error adding file to watcher: %s\n", err) + os.Exit(1) + } + } + + // Watch for file changes + go func() { + for { + select { + case event, ok := <-watcher.Events: + if !ok { + return + } + if event.Op&fsnotify.Write == fsnotify.Write { + if debug { + fmt.Printf("File modified: %s\n", event.Name) + } + processLogFile(event.Name) + } + case err, ok := <-watcher.Errors: + if !ok { + return + } + fmt.Fprintf(os.Stderr, "Watcher error: %s\n", err) + } + } + }() + + // Block forever + select {} +} + +func processLogFile(filePath string) { + if debug { + fmt.Printf("Processing log file: %s\n", filePath) + } + file, err := os.Open(filePath) + if err != nil { + fmt.Fprintf(os.Stderr, "Error opening file: %s\n", err) + return + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + if debug { + fmt.Printf("Read line: %s\n", line) + } + if strings.Contains(strings.ToLower(line), "error") { + sendToSentry(line) + } + } + + if err := scanner.Err(); err != nil { + fmt.Fprintf(os.Stderr, "Error reading file: %s\n", err) + } +} + +func sendToSentry(message string) { + if debug { + fmt.Printf("Sending message to GlitchTip: %s\n", message) + } + sentry.CaptureMessage(message) +} + +// Utility function to list log files +func listFiles(logFiles []string) []string { + var validFiles []string + for _, file := range logFiles { + if _, err := os.Stat(file); err == nil { + validFiles = append(validFiles, file) + } else { + fmt.Fprintf(os.Stderr, "Log file does not exist: %s\n", file) + } + } + return validFiles +} diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..824048b --- /dev/null +++ b/test.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +start_time=$(date +%s) + +# Set environment variables +export GLITCHTIP_DSN="https://d272afa8b4bd4308b3cf99ee74e1dc97@glitch.nixc.us/2" +export LOG_FILES="test_log_1.log,test_log_2.log" + +echo "Using Glitchtip DSN: $GLITCHTIP_DSN" +echo "Monitoring log files: $LOG_FILES" + +# Create test log files +echo "Creating test log files..." +echo "Initial log content" > test_log_1.log +echo "Initial log content" > test_log_2.log + +# Run the Go program in the background +echo "Starting the Go program..." +./dist/inotify-glitch_darwin_arm64 & + +# Capture the PID of the Go program +GO_PID=$! + +# Give the program a moment to start +sleep 2 + +# Append a line with an error to one of the log files +echo "Appending error line to test_log_1.log..." +echo "This is an error line" >> test_log_1.log + +# Give the program some time to process the change +sleep 2 + +# Check if the Go program detected the change (you can enhance this section with more specific checks) +echo "Check the logs to verify the program detected the error line." + +# Capture Go program logs for debugging +ps -p $GO_PID > /dev/null +if [ $? -eq 0 ]; then + echo "The Go program is running." +else + echo "The Go program has terminated unexpectedly." +fi + +# Cleanup: kill the Go program +echo "Terminating the Go program..." +kill $GO_PID + +# Optionally: Remove test log files +echo "Removing test log files..." +rm test_log_1.log test_log_2.log + +end_time=$(date +%s) +execution_time=$((end_time - start_time)) + +# Fix for macOS date command +execution_time_formatted=$(printf '%02d:%02d:%02d' $((execution_time/3600)) $((execution_time%3600/60)) $((execution_time%60))) + +echo "Execution time: $execution_time_formatted"