This commit is contained in:
Colin 2024-07-22 20:26:18 -04:00
commit addbf6dbc5
22 changed files with 406 additions and 0 deletions

73
README.md Normal file
View File

@ -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
```

43
build.sh Executable file
View File

@ -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

View File

@ -0,0 +1,2 @@
# inotify-glitch
./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value

View File

@ -0,0 +1,2 @@
# inotify-glitch
./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value

7
build_logs/error.log Normal file
View File

@ -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

View File

@ -0,0 +1,2 @@
# inotify-glitch
./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value

View File

@ -0,0 +1,2 @@
# inotify-glitch
./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value

View File

@ -0,0 +1,2 @@
# inotify-glitch
./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value

View File

@ -0,0 +1,2 @@
# inotify-glitch
./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value

View File

@ -0,0 +1,2 @@
# inotify-glitch
./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value

BIN
dist/inotify-glitch_darwin_amd64 vendored Executable file

Binary file not shown.

BIN
dist/inotify-glitch_darwin_arm64 vendored Executable file

Binary file not shown.

BIN
dist/inotify-glitch_linux_amd64 vendored Executable file

Binary file not shown.

BIN
dist/inotify-glitch_linux_amd64_static vendored Executable file

Binary file not shown.

BIN
dist/inotify-glitch_linux_arm64 vendored Executable file

Binary file not shown.

BIN
dist/inotify-glitch_linux_arm64_static vendored Executable file

Binary file not shown.

BIN
dist/inotify-glitch_windows_amd64 vendored Executable file

Binary file not shown.

13
go.mod Normal file
View File

@ -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
)

24
go.sum Normal file
View File

@ -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=

34
install.sh Normal file
View File

@ -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"

139
main.go Normal file
View File

@ -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
}

59
test.sh Executable file
View File

@ -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"