Improve the presentation of the measurement listing from the CLI
This commit is contained in:
parent
251f136b53
commit
4ed94dfc53
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
// commands
|
// commands
|
||||||
|
|
||||||
|
"github.com/apex/log"
|
||||||
_ "github.com/ooni/probe-cli/internal/cli/geoip"
|
_ "github.com/ooni/probe-cli/internal/cli/geoip"
|
||||||
_ "github.com/ooni/probe-cli/internal/cli/info"
|
_ "github.com/ooni/probe-cli/internal/cli/info"
|
||||||
_ "github.com/ooni/probe-cli/internal/cli/list"
|
_ "github.com/ooni/probe-cli/internal/cli/list"
|
||||||
|
@ -19,5 +20,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
crashreport.CapturePanicAndWait(app.Run, nil)
|
err, _ := crashreport.CapturePanic(app.Run, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err.(error)).Error("panic in app.Run")
|
||||||
|
crashreport.Wait()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,27 +27,41 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
msmtSummary := output.MeasurementSummaryData{
|
msmtSummary := output.MeasurementSummaryData{
|
||||||
TotalCount: 0,
|
TotalCount: 0,
|
||||||
AnomalyCount: 0,
|
AnomalyCount: 0,
|
||||||
DataUsageUp: 0.0,
|
DataUsageUp: 0.0,
|
||||||
DataUsageDown: 0.0,
|
DataUsageDown: 0.0,
|
||||||
TotalRuntime: 0,
|
TotalRuntime: 0,
|
||||||
|
ASN: 0,
|
||||||
|
NetworkName: "",
|
||||||
|
NetworkCountryCode: "ZZ",
|
||||||
}
|
}
|
||||||
for _, msmt := range measurements {
|
isFirst := true
|
||||||
|
isLast := false
|
||||||
|
for idx, msmt := range measurements {
|
||||||
|
if idx > 0 {
|
||||||
|
isFirst = false
|
||||||
|
}
|
||||||
|
if idx == len(measurements)-1 {
|
||||||
|
isLast = true
|
||||||
|
}
|
||||||
|
|
||||||
// We assume that since these are summary level information the first
|
// We assume that since these are summary level information the first
|
||||||
// item will contain the information necessary.
|
// item will contain the information necessary.
|
||||||
if msmtSummary.TotalRuntime == 0 {
|
if isFirst {
|
||||||
msmtSummary.TotalRuntime = msmt.ResultRuntime
|
msmtSummary.TotalRuntime = msmt.ResultRuntime
|
||||||
}
|
|
||||||
if msmtSummary.DataUsageUp == 0 {
|
|
||||||
msmtSummary.DataUsageUp = msmt.DataUsageUp
|
msmtSummary.DataUsageUp = msmt.DataUsageUp
|
||||||
msmtSummary.DataUsageDown = msmt.DataUsageDown
|
msmtSummary.DataUsageDown = msmt.DataUsageDown
|
||||||
|
msmtSummary.NetworkName = msmt.NetworkName
|
||||||
|
msmtSummary.NetworkCountryCode = msmt.NetworkCountryCode
|
||||||
|
msmtSummary.ASN = msmt.ASN
|
||||||
|
msmtSummary.StartTime = msmt.MeasurementStartTime
|
||||||
}
|
}
|
||||||
if msmt.IsAnomaly.Bool == true {
|
if msmt.IsAnomaly.Bool == true {
|
||||||
msmtSummary.AnomalyCount++
|
msmtSummary.AnomalyCount++
|
||||||
}
|
}
|
||||||
msmtSummary.TotalCount++
|
msmtSummary.TotalCount++
|
||||||
output.MeasurementItem(msmt)
|
output.MeasurementItem(msmt, isFirst, isLast)
|
||||||
}
|
}
|
||||||
output.MeasurementSummary(msmtSummary)
|
output.MeasurementSummary(msmtSummary)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package crashreport
|
package crashreport
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/apex/log"
|
||||||
"github.com/getsentry/raven-go"
|
"github.com/getsentry/raven-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,13 +9,15 @@ import (
|
||||||
// crash reporting logic a no-op.
|
// crash reporting logic a no-op.
|
||||||
var Disabled = false
|
var Disabled = false
|
||||||
|
|
||||||
|
var client *raven.Client
|
||||||
|
|
||||||
// CapturePanic is a wrapper around raven.CapturePanic that becomes a noop if
|
// CapturePanic is a wrapper around raven.CapturePanic that becomes a noop if
|
||||||
// `Disabled` is set to true.
|
// `Disabled` is set to true.
|
||||||
func CapturePanic(f func(), tags map[string]string) (interface{}, string) {
|
func CapturePanic(f func(), tags map[string]string) (interface{}, string) {
|
||||||
if Disabled == true {
|
if Disabled == true {
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
return raven.CapturePanic(f, tags)
|
return client.CapturePanic(f, tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CapturePanicAndWait is a wrapper around raven.CapturePanicAndWait that becomes a noop if
|
// CapturePanicAndWait is a wrapper around raven.CapturePanicAndWait that becomes a noop if
|
||||||
|
@ -23,7 +26,7 @@ func CapturePanicAndWait(f func(), tags map[string]string) (interface{}, string)
|
||||||
if Disabled == true {
|
if Disabled == true {
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
return raven.CapturePanicAndWait(f, tags)
|
return client.CapturePanicAndWait(f, tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureError is a wrapper around raven.CaptureError
|
// CaptureError is a wrapper around raven.CaptureError
|
||||||
|
@ -31,7 +34,7 @@ func CaptureError(err error, tags map[string]string) string {
|
||||||
if Disabled == true {
|
if Disabled == true {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return raven.CaptureError(err, tags)
|
return client.CaptureError(err, tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureErrorAndWait is a wrapper around raven.CaptureErrorAndWait
|
// CaptureErrorAndWait is a wrapper around raven.CaptureErrorAndWait
|
||||||
|
@ -39,9 +42,21 @@ func CaptureErrorAndWait(err error, tags map[string]string) string {
|
||||||
if Disabled == true {
|
if Disabled == true {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return raven.CaptureErrorAndWait(err, tags)
|
return client.CaptureErrorAndWait(err, tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait will block on sending messages to the sentry server
|
||||||
|
func Wait() {
|
||||||
|
if Disabled == false {
|
||||||
|
log.Info("sending exception backtrace")
|
||||||
|
client.Wait()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
raven.SetDSN("https://cb4510e090f64382ac371040c19b2258:8448daeebfa643c289ef398f8645980b@sentry.io/1234954")
|
var err error
|
||||||
|
client, err = raven.NewClient("https://cb4510e090f64382ac371040c19b2258:8448daeebfa643c289ef398f8645980b@sentry.io/1234954", nil)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("failed to create a raven client")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,10 @@ func (h *Handler) TypedLog(t string, e *log.Entry) error {
|
||||||
return nil
|
return nil
|
||||||
case "table":
|
case "table":
|
||||||
return logTable(h.Writer, e.Fields)
|
return logTable(h.Writer, e.Fields)
|
||||||
|
case "measurement_item":
|
||||||
|
return logMeasurementItem(h.Writer, e.Fields)
|
||||||
|
case "measurement_summary":
|
||||||
|
return logMeasurementSummary(h.Writer, e.Fields)
|
||||||
case "result_item":
|
case "result_item":
|
||||||
return logResultItem(h.Writer, e.Fields)
|
return logResultItem(h.Writer, e.Fields)
|
||||||
case "result_summary":
|
case "result_summary":
|
||||||
|
|
103
internal/log/handlers/cli/measurements.go
Normal file
103
internal/log/handlers/cli/measurements.go
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/apex/log"
|
||||||
|
"github.com/ooni/probe-cli/internal/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func statusIcon(ok bool) string {
|
||||||
|
if ok {
|
||||||
|
return "✓"
|
||||||
|
}
|
||||||
|
return "❌"
|
||||||
|
}
|
||||||
|
func logMeasurementItem(w io.Writer, f log.Fields) error {
|
||||||
|
colWidth := 24
|
||||||
|
|
||||||
|
rID := f.Get("id").(int64)
|
||||||
|
testName := f.Get("test_name").(string)
|
||||||
|
|
||||||
|
// We currently don't use these fields in the view
|
||||||
|
//testGroupName := f.Get("test_group_name").(string)
|
||||||
|
//networkName := f.Get("network_name").(string)
|
||||||
|
//asn := fmt.Sprintf("AS%d (%s)", f.Get("asn").(uint), f.Get("network_country_code").(string))
|
||||||
|
testKeys := f.Get("test_keys").(string)
|
||||||
|
|
||||||
|
isAnomaly := f.Get("is_anomaly").(bool)
|
||||||
|
isFailed := f.Get("is_failed").(bool)
|
||||||
|
isUploaded := f.Get("is_uploaded").(bool)
|
||||||
|
url := f.Get("url").(string)
|
||||||
|
urlCategoryCode := f.Get("url_category_code").(string)
|
||||||
|
|
||||||
|
isFirst := f.Get("is_first").(bool)
|
||||||
|
isLast := f.Get("is_last").(bool)
|
||||||
|
if isFirst {
|
||||||
|
fmt.Fprintf(w, "┏"+strings.Repeat("━", colWidth*2+2)+"┓\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(w, "┢"+strings.Repeat("━", colWidth*2+2)+"┪\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
anomalyStr := fmt.Sprintf("ok: %s", statusIcon(!isAnomaly))
|
||||||
|
uploadStr := fmt.Sprintf("uploaded: %s", statusIcon(isUploaded))
|
||||||
|
failureStr := fmt.Sprintf("success: %s", statusIcon(!isFailed))
|
||||||
|
|
||||||
|
fmt.Fprintf(w, fmt.Sprintf("│ %s │\n",
|
||||||
|
util.RightPad(
|
||||||
|
fmt.Sprintf("#%d", rID), colWidth*2)))
|
||||||
|
|
||||||
|
if url != "" {
|
||||||
|
fmt.Fprintf(w, fmt.Sprintf("│ %s │\n",
|
||||||
|
util.RightPad(
|
||||||
|
fmt.Sprintf("%s (%s)", url, urlCategoryCode), colWidth*2)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(w, fmt.Sprintf("│ %s %s│\n",
|
||||||
|
util.RightPad(testName, colWidth),
|
||||||
|
util.RightPad(anomalyStr, colWidth)))
|
||||||
|
|
||||||
|
fmt.Fprintf(w, fmt.Sprintf("│ %s │\n",
|
||||||
|
util.RightPad(testKeys, colWidth*2)))
|
||||||
|
fmt.Fprintf(w, fmt.Sprintf("│ %s %s│\n",
|
||||||
|
util.RightPad(failureStr, colWidth),
|
||||||
|
util.RightPad(uploadStr, colWidth)))
|
||||||
|
|
||||||
|
if isLast {
|
||||||
|
fmt.Fprintf(w, "└┬────────────────────────────────────────────────┬┘\n")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func logMeasurementSummary(w io.Writer, f log.Fields) error {
|
||||||
|
colWidth := 12
|
||||||
|
|
||||||
|
totalCount := f.Get("total_count").(int64)
|
||||||
|
anomalyCount := f.Get("anomaly_count").(int64)
|
||||||
|
totalRuntime := f.Get("total_runtime").(float64)
|
||||||
|
dataUp := f.Get("data_usage_up").(float64)
|
||||||
|
dataDown := f.Get("data_usage_down").(float64)
|
||||||
|
|
||||||
|
startTime := f.Get("start_time").(time.Time)
|
||||||
|
|
||||||
|
asn := f.Get("asn").(uint)
|
||||||
|
countryCode := f.Get("network_country_code").(string)
|
||||||
|
networkName := f.Get("network_name").(string)
|
||||||
|
|
||||||
|
fmt.Fprintf(w, " │ %s │\n",
|
||||||
|
util.RightPad(startTime.Format(time.RFC822), (colWidth+3)*3),
|
||||||
|
)
|
||||||
|
fmt.Fprintf(w, " │ %s │\n",
|
||||||
|
util.RightPad(fmt.Sprintf("AS%d, %s (%s)", asn, networkName, countryCode), (colWidth+3)*3),
|
||||||
|
)
|
||||||
|
fmt.Fprintf(w, " │ %s %s %s │\n",
|
||||||
|
util.RightPad(fmt.Sprintf("%.2fs", totalRuntime), colWidth),
|
||||||
|
util.RightPad(fmt.Sprintf("%d/%d anmls", anomalyCount, totalCount), colWidth),
|
||||||
|
util.RightPad(fmt.Sprintf("⬆ %s ⬇ %s", formatSize(dataUp), formatSize(dataDown)), colWidth+4))
|
||||||
|
fmt.Fprintf(w, " └────────────────────────────────────────────────┘\n")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -126,7 +126,7 @@ func Onboarding(config *config.Config) error {
|
||||||
|
|
||||||
config.Lock()
|
config.Lock()
|
||||||
config.InformedConsent = true
|
config.InformedConsent = true
|
||||||
config.Advanced.IncludeCountry = settings.IncludeCountry
|
config.Sharing.IncludeCountry = settings.IncludeCountry
|
||||||
config.Advanced.SendCrashReports = settings.SendCrashReports
|
config.Advanced.SendCrashReports = settings.SendCrashReports
|
||||||
config.Sharing.IncludeIP = settings.IncludeIP
|
config.Sharing.IncludeIP = settings.IncludeIP
|
||||||
config.Sharing.IncludeASN = settings.IncludeNetwork
|
config.Sharing.IncludeASN = settings.IncludeNetwork
|
||||||
|
|
|
@ -21,11 +21,15 @@ func Progress(key string, perc float64, msg string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type MeasurementSummaryData struct {
|
type MeasurementSummaryData struct {
|
||||||
TotalRuntime float64
|
TotalRuntime float64
|
||||||
TotalCount int64
|
TotalCount int64
|
||||||
AnomalyCount int64
|
AnomalyCount int64
|
||||||
DataUsageUp float64
|
DataUsageUp float64
|
||||||
DataUsageDown float64
|
DataUsageDown float64
|
||||||
|
ASN uint
|
||||||
|
NetworkName string
|
||||||
|
NetworkCountryCode string
|
||||||
|
StartTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func MeasurementSummary(msmt MeasurementSummaryData) {
|
func MeasurementSummary(msmt MeasurementSummaryData) {
|
||||||
|
@ -36,13 +40,20 @@ func MeasurementSummary(msmt MeasurementSummaryData) {
|
||||||
"anomaly_count": msmt.AnomalyCount,
|
"anomaly_count": msmt.AnomalyCount,
|
||||||
"data_usage_down": msmt.DataUsageDown,
|
"data_usage_down": msmt.DataUsageDown,
|
||||||
"data_usage_up": msmt.DataUsageUp,
|
"data_usage_up": msmt.DataUsageUp,
|
||||||
|
"asn": msmt.ASN,
|
||||||
|
"network_country_code": msmt.NetworkCountryCode,
|
||||||
|
"network_name": msmt.NetworkName,
|
||||||
|
"start_time": msmt.StartTime,
|
||||||
}).Info("measurement summary")
|
}).Info("measurement summary")
|
||||||
}
|
}
|
||||||
|
|
||||||
// MeasurementItem logs a progress type event
|
// MeasurementItem logs a progress type event
|
||||||
func MeasurementItem(msmt database.MeasurementURLNetwork) {
|
func MeasurementItem(msmt database.MeasurementURLNetwork, isFirst bool, isLast bool) {
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"type": "measurement_item",
|
"type": "measurement_item",
|
||||||
|
"is_first": isFirst,
|
||||||
|
"is_last": isLast,
|
||||||
|
|
||||||
"id": msmt.MsmtTblID,
|
"id": msmt.MsmtTblID,
|
||||||
"test_name": msmt.TestName,
|
"test_name": msmt.TestName,
|
||||||
"test_group_name": msmt.Result.TestGroupName,
|
"test_group_name": msmt.Result.TestGroupName,
|
||||||
|
|
|
@ -120,7 +120,7 @@ func (c *Controller) Init(nt *mk.Nettest) error {
|
||||||
nt.Options = mk.NettestOptions{
|
nt.Options = mk.NettestOptions{
|
||||||
IncludeIP: c.Ctx.Config.Sharing.IncludeIP,
|
IncludeIP: c.Ctx.Config.Sharing.IncludeIP,
|
||||||
IncludeASN: c.Ctx.Config.Sharing.IncludeASN,
|
IncludeASN: c.Ctx.Config.Sharing.IncludeASN,
|
||||||
IncludeCountry: c.Ctx.Config.Advanced.IncludeCountry,
|
IncludeCountry: c.Ctx.Config.Sharing.IncludeCountry,
|
||||||
LogLevel: "DEBUG",
|
LogLevel: "DEBUG",
|
||||||
|
|
||||||
ProbeCC: c.Ctx.Location.CountryCode,
|
ProbeCC: c.Ctx.Location.CountryCode,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user