baseline
This commit is contained in:
commit
addbf6dbc5
|
@ -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
|
||||||
|
```
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
||||||
|
# inotify-glitch
|
||||||
|
./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value
|
|
@ -0,0 +1,2 @@
|
||||||
|
# inotify-glitch
|
||||||
|
./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
||||||
|
# inotify-glitch
|
||||||
|
./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value
|
|
@ -0,0 +1,2 @@
|
||||||
|
# inotify-glitch
|
||||||
|
./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value
|
|
@ -0,0 +1,2 @@
|
||||||
|
# inotify-glitch
|
||||||
|
./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value
|
|
@ -0,0 +1,2 @@
|
||||||
|
# inotify-glitch
|
||||||
|
./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value
|
|
@ -0,0 +1,2 @@
|
||||||
|
# inotify-glitch
|
||||||
|
./main.go:56:17: syntax error: cannot use _, logFile := listFiles(logFiles) as value
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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
|
||||||
|
)
|
|
@ -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=
|
|
@ -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"
|
|
@ -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
|
||||||
|
}
|
|
@ -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"
|
Loading…
Reference in New Issue