Skip to content

Commit

Permalink
⭐️ new panic handler that reports client panics (#2963)
Browse files Browse the repository at this point in the history
* ⭐️ new panic handler that reports client panics
* 🧹 use log.Error instead of lof.Info
  • Loading branch information
chris-rock authored Jan 10, 2024
1 parent 0e7903c commit f264fde
Show file tree
Hide file tree
Showing 5 changed files with 638 additions and 1 deletion.
7 changes: 6 additions & 1 deletion apps/cnquery/cnquery.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@

package main

import "go.mondoo.com/cnquery/v9/apps/cnquery/cmd"
import (
"go.mondoo.com/cnquery/v9"
"go.mondoo.com/cnquery/v9/apps/cnquery/cmd"
"go.mondoo.com/cnquery/v9/providers-sdk/v1/upstream/health"
)

func main() {
defer health.ReportPanic("cnquery", cnquery.Version, cnquery.Build)
cmd.Execute()
}
87 changes: 87 additions & 0 deletions providers-sdk/v1/upstream/health/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package health

import (
"context"
"fmt"
"github.com/rs/zerolog/log"
"go.mondoo.com/cnquery/v9/cli/config"
"go.mondoo.com/cnquery/v9/providers-sdk/v1/upstream"
"go.mondoo.com/ranger-rpc"
"runtime/debug"
)

//go:generate protoc --proto_path=. --go_out=. --go_opt=paths=source_relative --rangerrpc_out=. errors.proto

func ReportPanic(product, version, build string) {
if r := recover(); r != nil {
sendPanic(product, version, build, r, debug.Stack())

// output error to console
panic(r)
}
}

// sendPanic sends a panic to the mondoo platform for further analysis if the
// service account is configured.
// This function does not return an error as it is not critical to send the panic to the platform.
func sendPanic(product, version, build string, r any, stacktrace []byte) {
// 1. read config
opts, err := config.Read()
if err != nil {
log.Error().Err(err).Msg("failed to read config")
return
}

serviceAccount := opts.GetServiceCredential()
if serviceAccount == nil {
log.Error().Msg("no service account configured")
return
}

// 2. create local support bundle
event := &SendErrorReq{
ServiceAccountMrn: opts.ServiceAccountMrn,
AgentMrn: opts.AgentMrn,
Product: &ProductInfo{
Name: product,
Version: version,
Build: build,
},
Error: &ErrorInfo{
Message: "panic: " + fmt.Sprintf("%v", r),
Stacktrace: string(stacktrace),
},
}

// 3. send error to mondoo platform
proxy, err := config.GetAPIProxy()
if err != nil {
log.Error().Err(err).Msg("failed to parse proxy setting")
return
}
httpClient := ranger.NewHttpClient(ranger.WithProxy(proxy))

plugins := []ranger.ClientPlugin{}
certAuth, err := upstream.NewServiceAccountRangerPlugin(serviceAccount)
if err != nil {
return
}
plugins = append(plugins, certAuth)

cl, err := NewErrorReportingClient(serviceAccount.ApiEndpoint, httpClient, plugins...)
if err != nil {
log.Error().Err(err).Msg("failed to create error reporting client")
return
}

_, err = cl.SendError(context.Background(), event)
if err != nil {
log.Error().Err(err).Msg("failed to send error to mondoo platform")
return
}

log.Info().Msg("reported panic to Mondoo platform")
}
Loading

0 comments on commit f264fde

Please sign in to comment.