Skip to content

add crash-report capabilities #574

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Dec 17, 2020
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ appName = CreateBridge
updateUrl = https://downloads.arduino.cc/
origins = https://local.arduino.cc:8000
#httpProxy = http://your.proxy:port # Proxy server for HTTP requests
crashreport = false # enable crashreport logging
24 changes: 14 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,18 @@ require (
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f
github.com/getlantern/systray v0.0.0-20200109124156-9abdfb6448b3
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7
github.com/gin-gonic/gin v1.3.0
github.com/gin-contrib/sse v0.1.0
github.com/gin-gonic/gin v1.6.3
github.com/go-ini/ini v1.39.0
github.com/go-ole/go-ole v1.2.1
github.com/go-playground/validator/v10 v10.4.1 // indirect
github.com/go-stack/stack v1.8.0
github.com/golang/protobuf v0.0.0-20170601230230-5a0f697c9ed9
github.com/golang/protobuf v1.4.3
github.com/googollee/go-engine.io v0.0.0-20180829091931-e2f255711dcb
github.com/googollee/go-socket.io v0.0.0-20181101151912-c8aeb1ed9b49
github.com/gorilla/websocket v1.4.0
github.com/itsjamie/gin-cors v0.0.0-20160420130702-97b4a9da7933
github.com/json-iterator/go v0.0.0-20170829155851-36b14963da70
github.com/json-iterator/go v1.1.10
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1
github.com/konsorten/go-windows-terminal-sequences v1.0.1
Expand All @@ -37,10 +38,12 @@ require (
github.com/lxn/walk v0.0.0-20191128110447-55ccb3a9f5c1
github.com/lxn/win v0.0.0-20191128105842-2da648fda5b4
github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d
github.com/mattn/go-isatty v0.0.2-0.20170307163044-57fdcb988a5c
github.com/mattn/go-isatty v0.0.12
github.com/mattn/go-shellwords v1.0.3
github.com/miekg/dns v1.0.15
github.com/mitchellh/go-homedir v1.0.0
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/oleksandr/bonjour v0.0.0-20160508152359-5dcf00d8b228
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c
github.com/pkg/errors v0.8.0
Expand All @@ -50,21 +53,22 @@ require (
github.com/sfreiberg/simplessh v0.0.0-20180301191542-495cbb862a9c
github.com/sirupsen/logrus v1.2.0
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c
github.com/stretchr/testify v1.3.0
github.com/ugorji/go v0.0.0-20170215201144-c88ee250d022
github.com/stretchr/testify v1.4.0
github.com/ugorji/go v1.2.0
github.com/xrash/smetrics v0.0.0-20170218160415-a3153f7040e9
github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea
go.bug.st/downloader v0.0.0-20181116113543-9b8976a44d87
go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45
goa.design/goa v1.0.1-0.20190116060309-40843d63b0e4
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
golang.org/x/net v0.0.0-20190620200207-3b0461eec859
golang.org/x/sys v0.0.0-20200107162124-548cf772de50
golang.org/x/sys v0.0.0-20201202213521-69691e467435
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7
google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/Knetic/govaluate.v3 v3.0.0
gopkg.in/go-playground/validator.v8 v8.18.1
gopkg.in/h2non/filetype.v1 v1.0.5
gopkg.in/inconshreveable/go-update.v0 v0.0.0-20150814200126-d8b0b1d421aa
gopkg.in/yaml.v2 v2.2.2
gopkg.in/yaml.v2 v2.4.0
)
120 changes: 120 additions & 0 deletions go.sum

Large diffs are not rendered by default.

23 changes: 22 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ var (
signatureKey = iniConf.String("signatureKey", "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvc0yZr1yUSen7qmE3cxF\nIE12rCksDnqR+Hp7o0nGi9123eCSFcJ7CkIRC8F+8JMhgI3zNqn4cUEn47I3RKD1\nZChPUCMiJCvbLbloxfdJrUi7gcSgUXrlKQStOKF5Iz7xv1M4XOP3JtjXLGo3EnJ1\npFgdWTOyoSrA8/w1rck4c/ISXZSinVAggPxmLwVEAAln6Itj6giIZHKvA2fL2o8z\nCeK057Lu8X6u2CG8tRWSQzVoKIQw/PKK6CNXCAy8vo4EkXudRutnEYHEJlPkVgPn\n2qP06GI+I+9zKE37iqj0k1/wFaCVXHXIvn06YrmjQw6I0dDj/60Wvi500FuRVpn9\ntwIDAQAB\n-----END PUBLIC KEY-----", "Pem-encoded public key to verify signed commandlines")
updateUrl = iniConf.String("updateUrl", "", "")
verbose = iniConf.Bool("v", true, "show debug logging")
crashreport = iniConf.Bool("crashreport", false, "enable crashreport logging")
)

// global clients
Expand Down Expand Up @@ -213,7 +214,7 @@ func loop() {

log.SetLevel(log.InfoLevel)

log.SetOutput(os.Stderr)
log.SetOutput(os.Stdout)

// see if we are supposed to wait 5 seconds
if *isLaunchSelf {
Expand Down Expand Up @@ -288,6 +289,26 @@ func loop() {
log.SetOutput(new(NullWriter)) //route all logging to nullwriter
}

// save crashreport to file
if *crashreport {
logFilename := "crashreport_" + time.Now().Format("20060102150405") + ".log"
currDir, err := osext.ExecutableFolder()
if err != nil {
panic(err)
}
// handle logs directory creation
logsDir := filepath.Join(currDir, "logs")
if _, err := os.Stat(logsDir); os.IsNotExist(err) {
os.Mkdir(logsDir, 0700)
}
logFile, err := os.OpenFile(filepath.Join(logsDir, logFilename), os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_APPEND, 0644)
if err != nil {
log.Print("Cannot create file used for crash-report")
} else {
redirectStderr(logFile)
}
}

// launch the hub routine which is the singleton for the websocket server
go h.run()
// launch our serial port routine
Expand Down
20 changes: 20 additions & 0 deletions redirect_stderr_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Log the panic under unix to the log file

// +build !windows

package main

import (
"log"
"os"

"golang.org/x/sys/unix"
)

// redirectStderr to the file passed in
func redirectStderr(f *os.File) {
err := unix.Dup2(int(f.Fd()), int(os.Stderr.Fd()))
if err != nil {
log.Fatalf("Failed to redirect stderr to file: %v", err)
}
}
41 changes: 41 additions & 0 deletions redirect_stderr_win.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Log the panic under windows to the log file
//
// Code from minix, via
//
// https://play.golang.org/p/kLtct7lSUg

// +build windows

package main

import (
"log"
"os"
"syscall"
)

var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
procSetStdHandle = kernel32.MustFindProc("SetStdHandle")
)

func setStdHandle(stdhandle int32, handle syscall.Handle) error {
r0, _, e1 := syscall.Syscall(procSetStdHandle.Addr(), 2, uintptr(stdhandle), uintptr(handle), 0)
if r0 == 0 {
if e1 != 0 {
return error(e1)
}
return syscall.EINVAL
}
return nil
}

// redirectStderr to the file passed in
func redirectStderr(f *os.File) {
err := setStdHandle(syscall.STD_ERROR_HANDLE, syscall.Handle(f.Fd()))
if err != nil {
log.Fatalf("Failed to redirect stderr to file: %v", err)
}
// SetStdHandle does not affect prior references to stderr
os.Stderr = f
}
2 changes: 1 addition & 1 deletion systray/systray.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (s *Systray) Pause() {
s.Restart()
}

// Pause restarts the program with the hibernate flag set to false
// Resume restarts the program with the hibernate flag set to false
func (s *Systray) Resume() {
s.Hibernate = false
s.Restart()
Expand Down
46 changes: 46 additions & 0 deletions systray/systray_real.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"os"
"path/filepath"

log "github.com/sirupsen/logrus"

"github.com/arduino/arduino-create-agent/icon"
"github.com/getlantern/systray"
"github.com/go-ini/ini"
Expand Down Expand Up @@ -41,6 +43,10 @@ func (s *Systray) start() {
mUrl := systray.AddMenuItem("Go to Arduino Create", "Arduino Create")
mDebug := systray.AddMenuItem("Open Debug Console", "Debug console")

// Remove crash-reports
mRmCrashes := systray.AddMenuItem("Remove crash reports", "")
s.updateMenuItem(mRmCrashes, s.CrashesIsEmpty())

// Add pause/quit
mPause := systray.AddMenuItem("Pause Plugin", "")
systray.AddSeparator()
Expand All @@ -57,6 +63,9 @@ func (s *Systray) start() {
_ = open.Start("https://create.arduino.cc")
case <-mDebug.ClickedCh:
_ = open.Start(s.DebugURL())
case <-mRmCrashes.ClickedCh:
s.RemoveCrashes()
s.updateMenuItem(mRmCrashes, s.CrashesIsEmpty())
case <-mPause.ClickedCh:
s.Pause()
case <-mQuit.ClickedCh:
Expand All @@ -66,6 +75,43 @@ func (s *Systray) start() {
}()
}

// updateMenuItem will enable or disable an item in the tray icon menu id disable is true
func (s *Systray) updateMenuItem(item *systray.MenuItem, disable bool) {
if disable {
item.Disable()
} else {
item.Enable()
}
}

// CrashesIsEmpty checks if the folder containing crash-reports is empty
func (s *Systray) CrashesIsEmpty() bool {
currDir, err := osext.ExecutableFolder()
if err != nil {
log.Error("Cannot determine executable path: ", err)
}
logsDir := filepath.Join(currDir, "logs")
if _, err := os.Stat(string(logsDir)); os.IsNotExist(err) {
return true
}
return false
}

// RemoveCrashes removes the crash-reports from `logs` folder
func (s *Systray) RemoveCrashes() {
currDir, err := osext.ExecutableFolder()
if err != nil {
log.Error("Cannot determine executable path: ", err)
}
logsDir := filepath.Join(currDir, "logs")
pathErr := os.RemoveAll(logsDir)
if pathErr != nil {
log.Error("Cannot remove crashreports: ", pathErr)
} else {
log.Info("Removed crashreports inside: ", logsDir)
}
}

// starthibernate creates a systray icon with menu options to resume/quit the agent
func (s *Systray) startHibernate() {
systray.SetIcon(icon.GetIconHiber())
Expand Down