lib/ur: Implement crash (panic) reporting (fixes #959) (#5702)

* lib/ur: Implement crash (panic) reporting (fixes #959)

This implements a simple crash reporting method. It piggybacks on the
panic log files created by the monitor process, picking these up and
uploading them from the usage reporting routine.

A new config value points to the crash receiver base URL, which defaults
to "https://crash.syncthing.net/newcrash" (following the pattern of
"https://data.syncthing.net/newdata" for usage reports, but allowing us
to separate the service as required).
This commit is contained in:
Jakob Borg
2019-06-11 08:19:11 +02:00
committed by GitHub
parent 93e57bd357
commit 42ce6be9b9
19 changed files with 1925 additions and 19 deletions

View File

@@ -29,7 +29,7 @@ import (
const (
OldestHandledVersion = 10
CurrentVersion = 28
CurrentVersion = 29
MaxRescanIntervalS = 365 * 24 * 60 * 60
)

View File

@@ -69,6 +69,8 @@ func TestDefaultValues(t *testing.T) {
UnackedNotificationIDs: []string{},
DefaultFolderPath: "~",
SetLowPriority: true,
CRURL: "https://crash.syncthing.net/newcrash",
CREnabled: true,
StunKeepaliveStartS: 180,
StunKeepaliveMinS: 20,
StunServers: []string{"default"},
@@ -203,7 +205,8 @@ func TestOverriddenValues(t *testing.T) {
ProgressUpdateIntervalS: 10,
LimitBandwidthInLan: true,
MinHomeDiskFree: Size{5.2, "%"},
URSeen: 2,
URSeen: 8,
URAccepted: 4,
URURL: "https://localhost/newdata",
URInitialDelayS: 800,
URPostInsecurely: true,
@@ -211,15 +214,14 @@ func TestOverriddenValues(t *testing.T) {
AlwaysLocalNets: []string{},
OverwriteRemoteDevNames: true,
TempIndexMinBlocks: 100,
UnackedNotificationIDs: []string{
"channelNotification", // added in 17->18 migration
"fsWatcherNotification", // added in 27->28 migration
},
DefaultFolderPath: "/media/syncthing",
SetLowPriority: false,
StunKeepaliveStartS: 9000,
StunKeepaliveMinS: 900,
StunServers: []string{"foo"},
UnackedNotificationIDs: []string{"asdfasdf"},
DefaultFolderPath: "/media/syncthing",
SetLowPriority: false,
CRURL: "https://localhost/newcrash",
CREnabled: false,
StunKeepaliveStartS: 9000,
StunKeepaliveMinS: 900,
StunServers: []string{"foo"},
}
os.Unsetenv("STNOUPGRADE")

View File

@@ -25,6 +25,7 @@ import (
// update the config version. The order of migrations doesn't matter here,
// put the newest on top for readability.
var migrations = migrationSet{
{29, migrateToConfigV29},
{28, migrateToConfigV28},
{27, migrateToConfigV27},
{26, nil}, // triggers database update
@@ -83,6 +84,19 @@ func (m migration) apply(cfg *Configuration) {
cfg.Version = m.targetVersion
}
func migrateToConfigV29(cfg *Configuration) {
// The new crash reporting option should follow the state of global
// discovery / usage reporting, and we should display an appropriate
// notification.
if cfg.Options.GlobalAnnEnabled || cfg.Options.URAccepted > 0 {
cfg.Options.CREnabled = true
cfg.Options.UnackedNotificationIDs = append(cfg.Options.UnackedNotificationIDs, "crAutoEnabled")
} else {
cfg.Options.CREnabled = false
cfg.Options.UnackedNotificationIDs = append(cfg.Options.UnackedNotificationIDs, "crAutoDisabled")
}
}
func migrateToConfigV28(cfg *Configuration) {
// Show a notification about enabling filesystem watching
cfg.Options.UnackedNotificationIDs = append(cfg.Options.UnackedNotificationIDs, "fsWatcherNotification")

View File

@@ -0,0 +1,34 @@
// Copyright (C) 2019 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package config
import "testing"
func TestMigrateCrashReporting(t *testing.T) {
// When migrating from pre-crash-reporting configs, crash reporting is
// enabled if global discovery is enabled or if usage reporting is
// enabled (not just undecided).
cases := []struct {
opts OptionsConfiguration
enabled bool
}{
{opts: OptionsConfiguration{URAccepted: 0, GlobalAnnEnabled: true}, enabled: true},
{opts: OptionsConfiguration{URAccepted: -1, GlobalAnnEnabled: true}, enabled: true},
{opts: OptionsConfiguration{URAccepted: 1, GlobalAnnEnabled: true}, enabled: true},
{opts: OptionsConfiguration{URAccepted: 0, GlobalAnnEnabled: false}, enabled: false},
{opts: OptionsConfiguration{URAccepted: -1, GlobalAnnEnabled: false}, enabled: false},
{opts: OptionsConfiguration{URAccepted: 1, GlobalAnnEnabled: false}, enabled: true},
}
for i, tc := range cases {
cfg := Configuration{Version: 28, Options: tc.opts}
migrations.apply(&cfg)
if cfg.Options.CREnabled != tc.enabled {
t.Errorf("%d: unexpected result, CREnabled: %v != %v", i, cfg.Options.CREnabled, tc.enabled)
}
}
}

View File

@@ -29,11 +29,11 @@ type OptionsConfiguration struct {
NATLeaseM int `xml:"natLeaseMinutes" json:"natLeaseMinutes" default:"60"`
NATRenewalM int `xml:"natRenewalMinutes" json:"natRenewalMinutes" default:"30"`
NATTimeoutS int `xml:"natTimeoutSeconds" json:"natTimeoutSeconds" default:"10"`
URAccepted int `xml:"urAccepted" json:"urAccepted"` // Accepted usage reporting version; 0 for off (undecided), -1 for off (permanently)
URSeen int `xml:"urSeen" json:"urSeen"` // Report which the user has been prompted for.
URUniqueID string `xml:"urUniqueID" json:"urUniqueId"` // Unique ID for reporting purposes, regenerated when UR is turned on.
URURL string `xml:"urURL" json:"urURL" default:"https://data.syncthing.net/newdata"`
URPostInsecurely bool `xml:"urPostInsecurely" json:"urPostInsecurely" default:"false"` // For testing
URAccepted int `xml:"urAccepted" json:"urAccepted"` // Accepted usage reporting version; 0 for off (undecided), -1 for off (permanently)
URSeen int `xml:"urSeen" json:"urSeen"` // Report which the user has been prompted for.
URUniqueID string `xml:"urUniqueID" json:"urUniqueId"` // Unique ID for reporting purposes, regenerated when UR is turned on.
URURL string `xml:"urURL" json:"urURL" default:"https://data.syncthing.net/newdata"` // usage reporting URL
URPostInsecurely bool `xml:"urPostInsecurely" json:"urPostInsecurely" default:"false"` // For testing
URInitialDelayS int `xml:"urInitialDelayS" json:"urInitialDelayS" default:"1800"`
RestartOnWakeup bool `xml:"restartOnWakeup" json:"restartOnWakeup" default:"true" restart:"true"`
AutoUpgradeIntervalH int `xml:"autoUpgradeIntervalH" json:"autoUpgradeIntervalH" default:"12" restart:"true"` // 0 for off
@@ -52,6 +52,8 @@ type OptionsConfiguration struct {
DefaultFolderPath string `xml:"defaultFolderPath" json:"defaultFolderPath" default:"~"`
SetLowPriority bool `xml:"setLowPriority" json:"setLowPriority" default:"true"`
MaxConcurrentScans int `xml:"maxConcurrentScans" json:"maxConcurrentScans"`
CRURL string `xml:"crashReportingURL" json:"crURL" default:"https://crash.syncthing.net/newcrash"` // crash reporting URL
CREnabled bool `xml:"crashReportingEnabled" json:"crashReportingEnabled" default:"true" restart:"true"`
StunKeepaliveStartS int `xml:"stunKeepaliveStartS" json:"stunKeepaliveStartS" default:"180"` // 0 for off
StunKeepaliveMinS int `xml:"stunKeepaliveMinS" json:"stunKeepaliveMinS" default:"20"` // 0 for off
StunServers []string `xml:"stunServer" json:"stunServers" default:"default"`

View File

@@ -1,4 +1,4 @@
<configuration version="14">
<configuration version="29">
<options>
<listenAddress>tcp://:23000</listenAddress>
<allowDelete>false</allowDelete>
@@ -27,8 +27,10 @@
<symlinksEnabled>false</symlinksEnabled>
<limitBandwidthInLan>true</limitBandwidthInLan>
<databaseBlockCacheMiB>42</databaseBlockCacheMiB>
<minHomeDiskFreePct>5.2</minHomeDiskFreePct>
<minHomeDiskFree unit="%">5.2</minHomeDiskFree>
<urURL>https://localhost/newdata</urURL>
<urSeen>8</urSeen>
<urAccepted>4</urAccepted>
<urInitialDelayS>800</urInitialDelayS>
<urPostInsecurely>true</urPostInsecurely>
<releasesURL>https://localhost/releases</releasesURL>
@@ -36,8 +38,11 @@
<tempIndexMinBlocks>100</tempIndexMinBlocks>
<defaultFolderPath>/media/syncthing</defaultFolderPath>
<setLowPriority>false</setLowPriority>
<crashReportingURL>https://localhost/newcrash</crashReportingURL>
<crashReportingEnabled>false</crashReportingEnabled>
<stunKeepaliveStartS>9000</stunKeepaliveStartS>
<stunKeepaliveMinS>900</stunKeepaliveMinS>
<stunServer>foo</stunServer>
<unackedNotificationID>asdfasdf</unackedNotificationID>
</options>
</configuration>

16
lib/config/testdata/v29.xml vendored Normal file
View File

@@ -0,0 +1,16 @@
<configuration version="28">
<folder id="test" path="testdata" type="readonly" ignorePerms="false" rescanIntervalS="600" fsWatcherEnabled="false" fsWatcherDelayS="10" autoNormalize="true">
<filesystemType>basic</filesystemType>
<device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR"></device>
<device id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2"></device>
<minDiskFree unit="%">1</minDiskFree>
<maxConflicts>-1</maxConflicts>
<fsync>true</fsync>
</folder>
<device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR" name="node one" compression="metadata">
<address>tcp://a</address>
</device>
<device id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2" name="node two" compression="metadata">
<address>tcp://b</address>
</device>
</configuration>