Skip to content

Commit

Permalink
Merge pull request #14 from cronitorio/ship-logs
Browse files Browse the repository at this point in the history
Ship full log output to Cronitor
  • Loading branch information
shaneharter authored May 3, 2022
2 parents b665920 + 46dd7d6 commit a725fd4
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 143 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,5 @@ cronitor
*.key
ctab
cronitor-cli

local.md
84 changes: 60 additions & 24 deletions cmd/exec.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package cmd

import (
"errors"
"fmt"
"github.com/cronitorio/cronitor-cli/lib"
"github.com/kballard/go-shellquote"
"github.com/pkg/errors"
"github.com/spf13/cobra"
flag "github.com/spf13/pflag"
"io"
Expand Down Expand Up @@ -43,11 +44,11 @@ Example with no command output send to Cronitor:

// We need to know all of the flags so we can properly identify the monitor code.
allFlags := map[string]bool{
"--": true, // seed with the argument separator
"--": true, // seed with the argument separator
}
cmd.Flags().VisitAll(func(flag *flag.Flag) {
allFlags["--" + flag.Name] = true
allFlags["-" + flag.Shorthand] = true
allFlags["--"+flag.Name] = true
allFlags["-"+flag.Shorthand] = true
})

for _, arg := range os.Args {
Expand Down Expand Up @@ -107,11 +108,11 @@ func RunCommand(subcommand string, withEnvironment bool, withMonitoring bool) in
var monitoringWaitGroup sync.WaitGroup

startTime := makeStamp()
formattedStartTime := formatStamp(startTime)
series := formatStamp(startTime)

if withMonitoring {
monitoringWaitGroup.Add(1)
go sendPing("run", monitorCode, subcommand, formattedStartTime, startTime, nil, nil, &monitoringWaitGroup)
go sendPing("run", monitorCode, subcommand, series, startTime, nil, nil, nil, &monitoringWaitGroup)
}

log(fmt.Sprintf("Running subcommand: %s", subcommand))
Expand Down Expand Up @@ -176,7 +177,15 @@ func RunCommand(subcommand string, withEnvironment bool, withMonitoring bool) in
case err := <-waitCh:

// Send output to Cronitor and clean up after the temp file
outputForPing := gatherOutput(tempFile)
outputForPing := gatherOutput(tempFile, true)
var metrics map[string]int = nil
logLengthForPing, err2 := getFileSize(tempFile)
if err2 == nil {
metrics = map[string]int{
"length": int(logLengthForPing),
}
}

defer func() {
if tempFile != nil {
tempFile.Close()
Expand All @@ -187,10 +196,13 @@ func RunCommand(subcommand string, withEnvironment bool, withMonitoring bool) in
endTime := makeStamp()
duration := endTime - startTime
exitCode := 0

if err == nil {
if withMonitoring {
monitoringWaitGroup.Add(1)
go sendPing("complete", monitorCode, string(outputForPing), formattedStartTime, endTime, &duration, &exitCode, &monitoringWaitGroup)
go sendPing("complete", monitorCode, string(outputForPing), series, endTime, &duration, &exitCode, metrics, &monitoringWaitGroup)
monitoringWaitGroup.Add(1)
go shipLogData(tempFile, series, &monitoringWaitGroup)
}
} else {
message := strings.TrimSpace(fmt.Sprintf("[%s] %s", err.Error(), outputForPing))
Expand All @@ -208,7 +220,9 @@ func RunCommand(subcommand string, withEnvironment bool, withMonitoring bool) in

if withMonitoring {
monitoringWaitGroup.Add(1)
go sendPing("fail", monitorCode, message, formattedStartTime, endTime, &duration, &exitCode, &monitoringWaitGroup)
go sendPing("fail", monitorCode, message, series, endTime, &duration, &exitCode, metrics, &monitoringWaitGroup)
monitoringWaitGroup.Add(1)
go shipLogData(tempFile, series, &monitoringWaitGroup)
}
}

Expand Down Expand Up @@ -273,28 +287,41 @@ func getTempFile() (*os.File, error) {
}
}

func gatherOutput(tempFile *os.File) []byte {
var outputForPing []byte
var outputForPingMaxLen int64 = 2000
func getFileSize(tempFile *os.File) (int64, error) {
// Known reasons stat could fail here:
// 1. temp file was removed by an external process
// 2. filesystem is no longer available

stat, err := os.Stat(tempFile.Name())
return stat.Size(), err
}

func gatherOutput(tempFile *os.File, truncateForPingOutput bool) []byte {
var outputBytes []byte
const outputForPingMaxLen int64 = 2000
const outputForLogUploadMaxLen int64 = 100000000
if noStdoutPassthru || tempFile == nil {
outputForPing = []byte{}
outputBytes = []byte{}
} else {
// Known reasons stat could fail here:
// 1. temp file was removed by an external process
// 2. filesystem is no longer available
if stat, err := os.Stat(tempFile.Name()); err == nil {
if size := stat.Size(); size < outputForPingMaxLen {
outputForPing = make([]byte, size)
tempFile.Seek(0, 0)
} else {
outputForPing = make([]byte, outputForPingMaxLen)

if size, err := getFileSize(tempFile); err == nil {
// In all cases, if we have to truncate, we want to read the END
// of the log file, because it is more informative.
if truncateForPingOutput && size > outputForPingMaxLen {
outputBytes = make([]byte, outputForPingMaxLen)
tempFile.Seek(outputForPingMaxLen*-1, 2)
} else if !truncateForPingOutput && size > outputForLogUploadMaxLen {
outputBytes = make([]byte, outputForLogUploadMaxLen)
tempFile.Seek(outputForLogUploadMaxLen*-1, 2)
} else {
outputBytes = make([]byte, size)
tempFile.Seek(0, 0)
}
tempFile.Read(outputForPing)
tempFile.Read(outputBytes)
}
}

return outputForPing
return outputBytes
}

func isStaleFile(file os.FileInfo) bool {
Expand All @@ -306,3 +333,12 @@ func isStaleFile(file os.FileInfo) bool {

return time.Now().Sub(file.ModTime()) > timeLimit
}

func shipLogData(tempFile *os.File, series string, wg *sync.WaitGroup) {
outputForLogs := gatherOutput(tempFile, false)
_, err := lib.SendLogData(apiKey, monitorCode, series, string(outputForLogs))
if err != nil {
log(fmt.Sprintf("%v", err))
}
wg.Done()
}
2 changes: 1 addition & 1 deletion cmd/ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Example when using authenticated ping requests:
var wg sync.WaitGroup

wg.Add(1)
go sendPing(getEndpointFromFlag(), args[0], msg, series, makeStamp(), nil, nil, &wg)
go sendPing(getEndpointFromFlag(), args[0], msg, series, makeStamp(), nil, nil, nil, &wg)
wg.Wait()
},
}
Expand Down
19 changes: 14 additions & 5 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package cmd

import (
"github.com/cronitorio/cronitor-cli/lib"
"errors"
"fmt"
"github.com/cronitorio/cronitor-cli/lib"
"io/ioutil"
"math/rand"
"net/http"
Expand All @@ -23,7 +23,7 @@ import (
"github.com/spf13/viper"
)

var Version string = "29"
var Version string = "30.0"

var cfgFile string
var userAgent string
Expand Down Expand Up @@ -112,7 +112,7 @@ func initConfig() {
}
}

func sendPing(endpoint string, uniqueIdentifier string, message string, series string, timestamp float64, duration *float64, exitCode *int, group *sync.WaitGroup) {
func sendPing(endpoint string, uniqueIdentifier string, message string, series string, timestamp float64, duration *float64, exitCode *int, metrics map[string]int, group *sync.WaitGroup) {
defer group.Done()

Client := &http.Client{
Expand All @@ -128,6 +128,7 @@ func sendPing(endpoint string, uniqueIdentifier string, message string, series s
formattedStamp := ""
formattedDuration := ""
formattedStatusCode := ""
formattedMetrics := ""

if timestamp > 0 {
formattedStamp = fmt.Sprintf("&stamp=%s", formatStamp(timestamp))
Expand Down Expand Up @@ -160,6 +161,14 @@ func sendPing(endpoint string, uniqueIdentifier string, message string, series s
series = fmt.Sprintf("&series=%s", series)
}

if metrics != nil && len(metrics) > 0 {
values := url.Values{}
for key, element := range metrics {
values.Add("metric", fmt.Sprintf("%s:%d", key, element))
}
formattedMetrics = "&" + values.Encode()
}

// If a user has set a key specifically for pings, use it.
if len(pingApiAuthKey) > 0 {
authenticationKey = pingApiAuthKey
Expand Down Expand Up @@ -195,10 +204,10 @@ func sendPing(endpoint string, uniqueIdentifier string, message string, series s

if len(authenticationKey) > 0 {
// Authenticated pings when available
uri = fmt.Sprintf("%s/ping/%s/%s?state=%s&try=%d%s%s%s%s%s%s%s", pingApiHost, authenticationKey, uniqueIdentifier, endpoint, i, formattedStamp, message, hostname, formattedDuration, series, formattedStatusCode, env)
uri = fmt.Sprintf("%s/ping/%s/%s?state=%s&try=%d%s%s%s%s%s%s%s%s", pingApiHost, authenticationKey, uniqueIdentifier, endpoint, i, formattedStamp, message, hostname, formattedDuration, series, formattedStatusCode, formattedMetrics, env)
} else {
// Fallback to sending an unauthenticated ping
uri = fmt.Sprintf("%s/%s/%s?try=%d%s%s%s%s%s%s%s", pingApiHost, uniqueIdentifier, endpoint, i, formattedStamp, message, hostname, formattedDuration, series, formattedStatusCode, env)
uri = fmt.Sprintf("%s/%s/%s?try=%d%s%s%s%s%s%s%s%s", pingApiHost, uniqueIdentifier, endpoint, i, formattedStamp, message, hostname, formattedDuration, series, formattedStatusCode, formattedMetrics, env)
}

log("Sending ping " + uri)
Expand Down
Binary file added cronitor-cli copy.exe
Binary file not shown.
Binary file added cronitor-cli.exe
Binary file not shown.
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ module github.com/cronitorio/cronitor-cli
go 1.14

require (
github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894 // indirect
github.com/fatih/color v1.9.0
github.com/getsentry/raven-go v0.2.0
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
Expand All @@ -13,3 +12,8 @@ require (
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.9.0
)

require (
github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894 // indirect
github.com/pkg/errors v0.8.1
)
Loading

0 comments on commit a725fd4

Please sign in to comment.