Browse Source

added sentry logging

pull/4/head
Vladimir Smagin 1 year ago
parent
commit
0f7b9291f0
16 changed files with 6155 additions and 41 deletions
  1. +49
    -31
      Gopkg.lock
  2. +1
    -0
      Gopkg.toml
  3. +29
    -7
      pkg/controller/rabbitmq/rabbitmq_controller.go
  4. +8
    -1
      pkg/controller/rabbitmq/rabbitmq_policies.go
  5. +9
    -2
      pkg/controller/rabbitmq/rabbitmq_users.go
  6. +3
    -0
      vendor/github.com/certifi/gocertifi/LICENSE
  7. +4454
    -0
      vendor/github.com/certifi/gocertifi/certifi.go
  8. +28
    -0
      vendor/github.com/getsentry/raven-go/LICENSE
  9. +977
    -0
      vendor/github.com/getsentry/raven-go/client.go
  10. +60
    -0
      vendor/github.com/getsentry/raven-go/errors.go
  11. +42
    -0
      vendor/github.com/getsentry/raven-go/example/example.go
  12. +50
    -0
      vendor/github.com/getsentry/raven-go/exception.go
  13. +99
    -0
      vendor/github.com/getsentry/raven-go/http.go
  14. +49
    -0
      vendor/github.com/getsentry/raven-go/interfaces.go
  15. +277
    -0
      vendor/github.com/getsentry/raven-go/stacktrace.go
  16. +20
    -0
      vendor/github.com/getsentry/raven-go/writer.go

+ 49
- 31
Gopkg.lock View File

@@ -41,6 +41,14 @@
pruneopts = "NT"
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"

[[projects]]
digest = "1:65d39e3a7e262416eb6f855d213954282921a3506125ce88e59514ae396dd690"
name = "github.com/certifi/gocertifi"
packages = ["."]
pruneopts = "NT"
revision = "deb3ae2ef2610fde3330947281941c562861188b"
version = "2018.01.18"

[[projects]]
digest = "1:c61f4f97321a37adcb5b4fd4fd61209cd553e46c99ee606c465553541b12a229"
name = "github.com/coreos/prometheus-operator"
@@ -48,7 +56,7 @@
"pkg/apis/monitoring",
"pkg/apis/monitoring/v1",
"pkg/client/versioned/scheme",
"pkg/client/versioned/typed/monitoring/v1"
"pkg/client/versioned/typed/monitoring/v1",
]
pruneopts = "NT"
revision = "72ec4b9b16ef11700724dc71fec77112536eed40"
@@ -67,12 +75,20 @@
name = "github.com/emicklei/go-restful"
packages = [
".",
"log"
"log",
]
pruneopts = "NT"
revision = "85d198d05a92d31823b852b4a5928114912e8949"
version = "v2.9.0"

[[projects]]
digest = "1:bd1b9cbca8127056a93ebacb5ff7c7ceb8f5694b16399daeb242510cce3eae70"
name = "github.com/getsentry/raven-go"
packages = ["."]
pruneopts = "NT"
revision = "f04e7487e9a6b9d9837d52743fb5f40576c56411"
version = "v0.2.0"

[[projects]]
digest = "1:81466b4218bf6adddac2572a30ac733a9255919bc2f470b4827a317bd4ee1756"
name = "github.com/ghodss/yaml"
@@ -142,7 +158,7 @@
name = "github.com/gogo/protobuf"
packages = [
"proto",
"sortkeys"
"sortkeys",
]
pruneopts = "NT"
revision = "ba06b47c162d49f2af050fb4c75bcbc86a159d5c"
@@ -172,7 +188,7 @@
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/timestamp"
"ptypes/timestamp",
]
pruneopts = "NT"
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
@@ -208,7 +224,7 @@
packages = [
"OpenAPIv2",
"compiler",
"extensions"
"extensions",
]
pruneopts = "NT"
revision = "7c663266750e7d82587642f65e60bc4083f1f84e"
@@ -220,7 +236,7 @@
name = "github.com/gregjones/httpcache"
packages = [
".",
"diskcache"
"diskcache",
]
pruneopts = "NT"
revision = "3befbb6ad0cc97d4c25d851e9528915809e1a22f"
@@ -230,7 +246,7 @@
name = "github.com/hashicorp/golang-lru"
packages = [
".",
"simplelru"
"simplelru",
]
pruneopts = "NT"
revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768"
@@ -275,7 +291,7 @@
packages = [
"buffer",
"jlexer",
"jwriter"
"jwriter",
]
pruneopts = "NT"
revision = "6243d8e04c3f819e79757e8bc3faa15c3cb27003"
@@ -321,7 +337,7 @@
"pkg/leader",
"pkg/log/zap",
"pkg/metrics",
"version"
"version",
]
pruneopts = "NT"
revision = "a882a84f8520dc8dcabaf03c0f1c7f55460eeafd"
@@ -364,7 +380,7 @@
packages = [
"prometheus",
"prometheus/internal",
"prometheus/promhttp"
"prometheus/promhttp",
]
pruneopts = "NT"
revision = "505eaef017263e299324067d40ca2c48f6a2cf50"
@@ -384,7 +400,7 @@
packages = [
"expfmt",
"internal/bitbucket.org/ww/goautoneg",
"model"
"model",
]
pruneopts = "NT"
revision = "cfeb6f9992ffa54aaa4f2170ade4067ee478b250"
@@ -399,7 +415,7 @@
"internal/util",
"iostats",
"nfs",
"xfs"
"xfs",
]
pruneopts = "NT"
revision = "e4d4a2206da023361ed100d85c5f2cf9c8364e9f"
@@ -410,7 +426,7 @@
packages = [
"modfile",
"module",
"semver"
"semver",
]
pruneopts = "NT"
revision = "1cf9852c553c5b7da2d5a4a091129a7822fed0c9"
@@ -421,7 +437,7 @@
name = "github.com/spf13/afero"
packages = [
".",
"mem"
"mem",
]
pruneopts = "NT"
revision = "f4711e4db9e9a1d3887343acb72b2bbfc2f686f5"
@@ -460,7 +476,7 @@
"internal/bufferpool",
"internal/color",
"internal/exit",
"zapcore"
"zapcore",
]
pruneopts = "NT"
revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982"
@@ -484,7 +500,7 @@
"http/httpguts",
"http2",
"http2/hpack",
"idna"
"idna",
]
pruneopts = "NT"
revision = "3a22650c66bd7f4fb6d1e8072ffd7b75c8a27898"
@@ -498,7 +514,7 @@
"google",
"internal",
"jws",
"jwt"
"jwt",
]
pruneopts = "NT"
revision = "9b3c75971fc92dd27c6436a37c05c831498658f1"
@@ -509,7 +525,7 @@
name = "golang.org/x/sys"
packages = [
"unix",
"windows"
"windows",
]
pruneopts = "NT"
revision = "a9d3bda3a223baa6bba6ef412cb273f0fd163c05"
@@ -532,7 +548,7 @@
"unicode/cldr",
"unicode/norm",
"unicode/rangetable",
"width"
"width",
]
pruneopts = "NT"
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
@@ -562,7 +578,7 @@
"internal/fastwalk",
"internal/gopathwalk",
"internal/module",
"internal/semver"
"internal/semver",
]
pruneopts = "NT"
revision = "83362c3779f5f48611068d488a03ea7bbaddc81e"
@@ -580,7 +596,7 @@
"internal/modules",
"internal/remote_api",
"internal/urlfetch",
"urlfetch"
"urlfetch",
]
pruneopts = "NT"
revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1"
@@ -638,7 +654,7 @@
"settings/v1alpha1",
"storage/v1",
"storage/v1alpha1",
"storage/v1beta1"
"storage/v1beta1",
]
pruneopts = "NT"
revision = "05914d821849570fba9eacfb29466f2d8d3cd229"
@@ -648,7 +664,7 @@
name = "k8s.io/apiextensions-apiserver"
packages = [
"pkg/apis/apiextensions",
"pkg/apis/apiextensions/v1beta1"
"pkg/apis/apiextensions/v1beta1",
]
pruneopts = "NT"
revision = "0fe22c71c47604641d9aa352c785b7912c200562"
@@ -699,7 +715,7 @@
"pkg/version",
"pkg/watch",
"third_party/forked/golang/json",
"third_party/forked/golang/reflect"
"third_party/forked/golang/reflect",
]
pruneopts = "NT"
revision = "2b1284ed4c93a43499e781493253e2ac5959c4fd"
@@ -775,7 +791,7 @@
"util/integer",
"util/jsonpath",
"util/retry",
"util/workqueue"
"util/workqueue",
]
pruneopts = "NT"
revision = "8d9ed539ba3134352c586810e749e58df4e94e4f"
@@ -805,7 +821,7 @@
"cmd/lister-gen",
"cmd/lister-gen/args",
"cmd/lister-gen/generators",
"pkg/util"
"pkg/util",
]
pruneopts = "T"
revision = "c2090bec4d9b1fb25de3812f868accc2bc9ecbae"
@@ -822,7 +838,7 @@
"generator",
"namer",
"parser",
"types"
"types",
]
pruneopts = "T"
revision = "0689ccc1d7d65d9dd1bedcc3b0b1ed7df91ba266"
@@ -845,7 +861,7 @@
"pkg/generators",
"pkg/generators/rules",
"pkg/util/proto",
"pkg/util/sets"
"pkg/util/sets",
]
pruneopts = "NT"
revision = "0cf8f7e6ed1d2e3d47d02e3b6e559369af24d803"
@@ -882,7 +898,7 @@
"pkg/webhook/admission",
"pkg/webhook/admission/types",
"pkg/webhook/internal/metrics",
"pkg/webhook/types"
"pkg/webhook/types",
]
pruneopts = "NT"
revision = "12d98582e72927b6cd0123e2b4e819f9341ce62c"
@@ -897,7 +913,7 @@
"pkg/internal/codegen",
"pkg/internal/codegen/parse",
"pkg/internal/general",
"pkg/util"
"pkg/util",
]
pruneopts = "NT"
revision = "950a0e88e4effb864253b3c7504b326cc83b9d11"
@@ -915,6 +931,8 @@
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1",
"github.com/getsentry/raven-go",
"github.com/go-logr/logr",
"github.com/go-openapi/spec",
"github.com/leekchan/gtf",
@@ -955,7 +973,7 @@
"sigs.k8s.io/controller-runtime/pkg/runtime/scheme",
"sigs.k8s.io/controller-runtime/pkg/runtime/signals",
"sigs.k8s.io/controller-runtime/pkg/source",
"sigs.k8s.io/controller-tools/pkg/crd/generator"
"sigs.k8s.io/controller-tools/pkg/crd/generator",
]
solver-name = "gps-cdcl"
solver-version = 1

+ 1
- 0
Gopkg.toml View File

@@ -10,6 +10,7 @@ required = [
"k8s.io/gengo/args",
"sigs.k8s.io/controller-tools/pkg/crd/generator",
"github.com/leekchan/gtf",
"github.com/getsentry/raven-go",
]

[[override]]


+ 29
- 7
pkg/controller/rabbitmq/rabbitmq_controller.go View File

@@ -5,6 +5,7 @@ import (
"strconv"
"time"

"github.com/getsentry/raven-go"
rabbitmqv1 "github.com/tekliner/rabbitmq-operator/pkg/apis/rabbitmq/v1"
v1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
@@ -24,6 +25,10 @@ import (
"sigs.k8s.io/controller-runtime/pkg/source"
)

func init() {
raven.SetDSN("https://983d2bf5d8f247e98b89d179b737a48d:f3133ece803044fa8491775da2d56cf5@sentry.tools.improvado.io/37")
}

var log = logf.Log.WithName("controller_rabbitmq")

/**
@@ -47,12 +52,14 @@ func add(mgr manager.Manager, reconciler reconcile.Reconciler) error {
// Create a new controller
c, err := controller.New("rabbitmq-controller", mgr, controller.Options{Reconciler: reconciler})
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return err
}

// Watch for changes to primary resource Rabbitmq
err = c.Watch(&source.Kind{Type: &rabbitmqv1.Rabbitmq{}}, &handler.EnqueueRequestForObject{})
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return err
}

@@ -63,6 +70,7 @@ func add(mgr manager.Manager, reconciler reconcile.Reconciler) error {
OwnerType: &rabbitmqv1.Rabbitmq{},
})
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return err
}

@@ -71,6 +79,7 @@ func add(mgr manager.Manager, reconciler reconcile.Reconciler) error {
OwnerType: &rabbitmqv1.Rabbitmq{},
})
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return err
}

@@ -103,6 +112,7 @@ func add(mgr manager.Manager, reconciler reconcile.Reconciler) error {
}, p)

if err != nil {
raven.CaptureErrorAndWait(err, nil)
return err
}

@@ -139,8 +149,8 @@ func mergeMaps(itermaps ...map[string]string) map[string]string {

func returnLabels(cr *rabbitmqv1.Rabbitmq) map[string]string {
labels := map[string]string{
"application": "rabbitmq",
"instance": cr.Name,
"application": "rabbitmq",
"instance": cr.Name,
}
return labels
}
@@ -148,7 +158,7 @@ func returnLabels(cr *rabbitmqv1.Rabbitmq) map[string]string {
func returnAnnotationsPrometheus(cr *rabbitmqv1.Rabbitmq) map[string]string {
return map[string]string{
"prometheus.io/scrape": "true",
"prometheus.io/port": strconv.Itoa(int(cr.Spec.RabbitmqPrometheusExporterPort)),
"prometheus.io/port": strconv.Itoa(int(cr.Spec.RabbitmqPrometheusExporterPort)),
}
}

@@ -176,6 +186,7 @@ func (r *ReconcileRabbitmq) Reconcile(request reconcile.Request) (reconcile.Resu
return reconcile.Result{}, nil
}
// Error reading the object - requeue the request.
raven.CaptureErrorAndWait(err, nil)
return reconcile.Result{}, err
}

@@ -183,11 +194,13 @@ func (r *ReconcileRabbitmq) Reconcile(request reconcile.Request) (reconcile.Resu
reqLogger.Info("Reconciling secrets")
secretNames, err := r.reconcileSecrets(reqLogger, instance)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return reconcile.Result{}, err
}

statefulset := newStatefulSet(instance, secretNames)
if err := controllerutil.SetControllerReference(instance, statefulset, r.scheme); err != nil {
raven.CaptureErrorAndWait(err, nil)
return reconcile.Result{}, err
}

@@ -197,18 +210,21 @@ func (r *ReconcileRabbitmq) Reconcile(request reconcile.Request) (reconcile.Resu
reqLogger.Info("Creating a new statefulset", "statefulset.Namespace", statefulset.Namespace, "statefulset.Name", statefulset.Name)
err = r.client.Create(context.TODO(), statefulset)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return reconcile.Result{}, err
}

// statefulset created successfully - don't requeue
return reconcile.Result{}, nil
} else if err != nil {
raven.CaptureErrorAndWait(err, nil)
return reconcile.Result{}, err
}

reqLogger.Info("Reconcile statefulset", "statefulset.Namespace", found.Namespace, "statefulset.Name", found.Name)
if err = r.client.Update(context.TODO(), statefulset); err != nil {
reqLogger.Info("Reconcile statefulset error", "statefulset.Namespace", found.Namespace, "statefulset.Name", found.Name)
raven.CaptureErrorAndWait(err, nil)
return reconcile.Result{}, err
}

@@ -217,17 +233,20 @@ func (r *ReconcileRabbitmq) Reconcile(request reconcile.Request) (reconcile.Resu

_, err = r.reconcileHTTPService(reqLogger, instance)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return reconcile.Result{}, err
}

// all-in-one service
_, err = r.reconcileHAService(reqLogger, instance)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return reconcile.Result{}, err
}

_, err = r.reconcileDiscoveryService(reqLogger, instance)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return reconcile.Result{}, err
}

@@ -236,6 +255,7 @@ func (r *ReconcileRabbitmq) Reconcile(request reconcile.Request) (reconcile.Resu

_, err = r.reconcileConfigMap(reqLogger, instance, secretNames)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return reconcile.Result{}, err
}

@@ -243,10 +263,12 @@ func (r *ReconcileRabbitmq) Reconcile(request reconcile.Request) (reconcile.Resu
if instance.Spec.RabbitmqPrometheusExporterPort > 0 {
_, err = r.reconcilePrometheusExporterService(reqLogger, instance)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return reconcile.Result{}, err
}
_, err = r.reconcilePrometheusExporterServiceMonitor(reqLogger, instance)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return reconcile.Result{}, err
}
}
@@ -362,8 +384,8 @@ func newStatefulSet(cr *rabbitmqv1.Rabbitmq, secretNames secretResouces) *v1.Sta
}

exporterContainer := corev1.Container{
Name: "prometheus-exporter",
Image: exporterImageAndTag,
Name: "prometheus-exporter",
Image: exporterImageAndTag,
ImagePullPolicy: corev1.PullIfNotPresent,
Env: []corev1.EnvVar{
{
@@ -377,8 +399,8 @@ func newStatefulSet(cr *rabbitmqv1.Rabbitmq, secretNames secretResouces) *v1.Sta
},
Ports: []corev1.ContainerPort{
{
Name: "exporter",
Protocol: corev1.ProtocolTCP,
Name: "exporter",
Protocol: corev1.ProtocolTCP,
ContainerPort: cr.Spec.RabbitmqPrometheusExporterPort,
},
},


+ 8
- 1
pkg/controller/rabbitmq/rabbitmq_policies.go View File

@@ -5,6 +5,7 @@ import (
"net"
"time"

"github.com/getsentry/raven-go"
"github.com/go-logr/logr"
rabbitmqv1 "github.com/tekliner/rabbitmq-operator/pkg/apis/rabbitmq/v1"
)
@@ -19,6 +20,7 @@ func (r *ReconcileRabbitmq) setPolicies(ctx context.Context, reqLogger logr.Logg
serviceAccount.username = username
if err != nil {
reqLogger.Info("Users: auth username not found")
raven.CaptureErrorAndWait(err, nil)
return err
}

@@ -26,6 +28,7 @@ func (r *ReconcileRabbitmq) setPolicies(ctx context.Context, reqLogger logr.Logg
serviceAccount.password = password
if err != nil {
reqLogger.Info("Users: auth password not found")
raven.CaptureErrorAndWait(err, nil)
return err
}

@@ -35,6 +38,7 @@ func (r *ReconcileRabbitmq) setPolicies(ctx context.Context, reqLogger logr.Logg
_, err = net.DialTimeout("tcp", r.apiServiceHostname(cr), timeout)
if err != nil {
reqLogger.Info("Rabbitmq API service failed", "Service name", r.apiServiceHostname(cr), "Error", err.Error())
raven.CaptureErrorAndWait(err, nil)
return err
}
reqLogger.Info("Policies: Using API service: "+r.apiServiceAddress(cr), "username", serviceAccount.username, "password", serviceAccount.password)
@@ -47,6 +51,7 @@ func (r *ReconcileRabbitmq) setPolicies(ctx context.Context, reqLogger logr.Logg
policiesRabbit, err := r.apiPolicyList(reqLogger, cr, serviceAccount)
if err != nil {
reqLogger.Info("Error while receiving policies list", "Error", err.Error())
raven.CaptureErrorAndWait(err, nil)
return err
}

@@ -84,7 +89,7 @@ func (r *ReconcileRabbitmq) setPolicies(ctx context.Context, reqLogger logr.Logg
policyFound := false
for _, policyCR := range policiesCR {
if policyCR.Name == policyRabbit.Name {
policyFound =true
policyFound = true
}
}

@@ -92,6 +97,7 @@ func (r *ReconcileRabbitmq) setPolicies(ctx context.Context, reqLogger logr.Logg
reqLogger.Info("Removing " + policyRabbit.Name)
err = r.apiPolicyRemove(reqLogger, cr, serviceAccount, policyRabbit.Vhost, policyRabbit.Name)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return err
}
}
@@ -104,6 +110,7 @@ func (r *ReconcileRabbitmq) setPolicies(ctx context.Context, reqLogger logr.Logg
err = r.apiPolicyAdd(reqLogger, cr, serviceAccount, policyCR.Vhost, policyCR)
if err != nil {
reqLogger.Info("Error adding policy "+policyCR.Name+" to vhost "+policyCR.Vhost, "Error", err)
raven.CaptureErrorAndWait(err, nil)
return err
}
}


+ 9
- 2
pkg/controller/rabbitmq/rabbitmq_users.go View File

@@ -5,6 +5,7 @@ import (
"net"
"time"

"github.com/getsentry/raven-go"
"github.com/go-logr/logr"
rabbitmqv1 "github.com/tekliner/rabbitmq-operator/pkg/apis/rabbitmq/v1"
)
@@ -20,6 +21,7 @@ func (r *ReconcileRabbitmq) syncUsersCredentials(ctx context.Context, reqLogger
serviceAccount.username = username
if err != nil {
reqLogger.Info("Users: auth username not found")
raven.CaptureErrorAndWait(err, nil)
return err
}

@@ -27,6 +29,7 @@ func (r *ReconcileRabbitmq) syncUsersCredentials(ctx context.Context, reqLogger
serviceAccount.password = password
if err != nil {
reqLogger.Info("Users: auth password not found")
raven.CaptureErrorAndWait(err, nil)
return err
}

@@ -36,19 +39,21 @@ func (r *ReconcileRabbitmq) syncUsersCredentials(ctx context.Context, reqLogger
_, err = net.DialTimeout("tcp", r.apiServiceHostname(cr), timeout)
if err != nil {
reqLogger.Info("Rabbitmq API service failed", "Service name", r.apiServiceHostname(cr), "Error", err.Error())
raven.CaptureErrorAndWait(err, nil)
return err
}
reqLogger.Info("Users: Using API service: "+r.apiServiceAddress(cr), "username", serviceAccount.username)

// get user from secret
usersSecret, err := r.getSecret(secretNames.Credentials, cr.Namespace)
reqLogger.Info("Users from secret", "CRD", cr.Name , "SecretNames", secretNames, "Users", usersSecret, "ServiceAccount", serviceAccount.username)
reqLogger.Info("Users from secret", "CRD", cr.Name, "SecretNames", secretNames, "Users", usersSecret, "ServiceAccount", serviceAccount.username)

// get users from rabbit api
reqLogger.Info("Reading all users from rabbitmq")
usersRabbit, err := r.apiUserList(reqLogger, cr, serviceAccount)
if err != nil {
reqLogger.Info("Error while receiving users list", "Error", err.Error())
raven.CaptureErrorAndWait(err, nil)
return err
}

@@ -68,8 +73,9 @@ func (r *ReconcileRabbitmq) syncUsersCredentials(ctx context.Context, reqLogger
// user from RabbitMQ not found in secret resource, so add to remove list
if (!userFound) && (userRabbitName.Name != serviceAccount.username) {
reqLogger.Info("Removing " + userRabbitName.Name)
err = r.apiUserRemove(reqLogger, cr, serviceAccount, rabbitmqUserStruct{Name:userRabbitName.Name})
err = r.apiUserRemove(reqLogger, cr, serviceAccount, rabbitmqUserStruct{Name: userRabbitName.Name})
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return err
}
}
@@ -84,6 +90,7 @@ func (r *ReconcileRabbitmq) syncUsersCredentials(ctx context.Context, reqLogger
err = r.apiUserAdd(reqLogger, cr, serviceAccount, rabbitmqUserStruct{Name: userName, Password: string(userPassword), Tags: "management"})
if err != nil {
reqLogger.Info("Error adding user "+userName, "Error", err)
raven.CaptureErrorAndWait(err, nil)
return err
}
}


+ 3
- 0
vendor/github.com/certifi/gocertifi/LICENSE View File

@@ -0,0 +1,3 @@
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 http://mozilla.org/MPL/2.0/.

+ 4454
- 0
vendor/github.com/certifi/gocertifi/certifi.go
File diff suppressed because it is too large
View File


+ 28
- 0
vendor/github.com/getsentry/raven-go/LICENSE View File

@@ -0,0 +1,28 @@
Copyright (c) 2013 Apollic Software, LLC. All rights reserved.
Copyright (c) 2015 Functional Software, Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Apollic Software, LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 977
- 0
vendor/github.com/getsentry/raven-go/client.go View File

@@ -0,0 +1,977 @@
// Package raven implements a client for the Sentry error logging service.
package raven

import (
"bytes"
"compress/zlib"
"crypto/rand"
"crypto/tls"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
mrand "math/rand"
"net/http"
"net/url"
"os"
"regexp"
"runtime"
"strings"
"sync"
"time"

"github.com/certifi/gocertifi"
pkgErrors "github.com/pkg/errors"
)

const (
userAgent = "raven-go/1.0"
timestampFormat = `"2006-01-02T15:04:05.00"`
)

var (
ErrPacketDropped = errors.New("raven: packet dropped")
ErrUnableToUnmarshalJSON = errors.New("raven: unable to unmarshal JSON")
ErrMissingUser = errors.New("raven: dsn missing public key and/or password")
ErrMissingProjectID = errors.New("raven: dsn missing project id")
ErrInvalidSampleRate = errors.New("raven: sample rate should be between 0 and 1")
)

type Severity string

// http://docs.python.org/2/howto/logging.html#logging-levels
const (
DEBUG = Severity("debug")
INFO = Severity("info")
WARNING = Severity("warning")
ERROR = Severity("error")
FATAL = Severity("fatal")
)

type Timestamp time.Time

func (t Timestamp) MarshalJSON() ([]byte, error) {
return []byte(time.Time(t).UTC().Format(timestampFormat)), nil
}

func (timestamp *Timestamp) UnmarshalJSON(data []byte) error {
t, err := time.Parse(timestampFormat, string(data))
if err != nil {
return err
}

*timestamp = Timestamp(t)
return nil
}

func (timestamp Timestamp) Format(format string) string {
t := time.Time(timestamp)
return t.Format(format)
}

// An Interface is a Sentry interface that will be serialized as JSON.
// It must implement json.Marshaler or use json struct tags.
type Interface interface {
// The Sentry class name. Example: sentry.interfaces.Stacktrace
Class() string
}

type Culpriter interface {
Culprit() string
}

type Transport interface {
Send(url, authHeader string, packet *Packet) error
}

type Extra map[string]interface{}

type outgoingPacket struct {
packet *Packet
ch chan error
}

type Tag struct {
Key string
Value string
}

type Tags []Tag

func (tag *Tag) MarshalJSON() ([]byte, error) {
return json.Marshal([2]string{tag.Key, tag.Value})
}

func (t *Tag) UnmarshalJSON(data []byte) error {
var tag [2]string
if err := json.Unmarshal(data, &tag); err != nil {
return err
}
*t = Tag{tag[0], tag[1]}
return nil
}

func (t *Tags) UnmarshalJSON(data []byte) error {
var tags []Tag

switch data[0] {
case '[':
// Unmarshal into []Tag
if err := json.Unmarshal(data, &tags); err != nil {
return err
}
case '{':
// Unmarshal into map[string]string
tagMap := make(map[string]string)
if err := json.Unmarshal(data, &tagMap); err != nil {
return err
}

// Convert to []Tag
for k, v := range tagMap {
tags = append(tags, Tag{k, v})
}
default:
return ErrUnableToUnmarshalJSON
}

*t = tags
return nil
}

// https://docs.getsentry.com/hosted/clientdev/#building-the-json-packet
type Packet struct {
// Required
Message string `json:"message"`

// Required, set automatically by Client.Send/Report via Packet.Init if blank
EventID string `json:"event_id"`
Project string `json:"project"`
Timestamp Timestamp `json:"timestamp"`
Level Severity `json:"level"`
Logger string `json:"logger"`

// Optional
Platform string `json:"platform,omitempty"`
Culprit string `json:"culprit,omitempty"`
ServerName string `json:"server_name,omitempty"`
Release string `json:"release,omitempty"`
Environment string `json:"environment,omitempty"`
Tags Tags `json:"tags,omitempty"`
Modules map[string]string `json:"modules,omitempty"`
Fingerprint []string `json:"fingerprint,omitempty"`
Extra Extra `json:"extra,omitempty"`

Interfaces []Interface `json:"-"`
}

// NewPacket constructs a packet with the specified message and interfaces.
func NewPacket(message string, interfaces ...Interface) *Packet {
extra := Extra{}
setExtraDefaults(extra)
return &Packet{
Message: message,
Interfaces: interfaces,
Extra: extra,
}
}

// NewPacketWithExtra constructs a packet with the specified message, extra information, and interfaces.
func NewPacketWithExtra(message string, extra Extra, interfaces ...Interface) *Packet {
if extra == nil {
extra = Extra{}
}
setExtraDefaults(extra)

return &Packet{
Message: message,
Interfaces: interfaces,
Extra: extra,
}
}

func setExtraDefaults(extra Extra) Extra {
extra["runtime.Version"] = runtime.Version()
extra["runtime.NumCPU"] = runtime.NumCPU()
extra["runtime.GOMAXPROCS"] = runtime.GOMAXPROCS(0) // 0 just returns the current value
extra["runtime.NumGoroutine"] = runtime.NumGoroutine()
return extra
}

// Init initializes required fields in a packet. It is typically called by
// Client.Send/Report automatically.
func (packet *Packet) Init(project string) error {
if packet.Project == "" {
packet.Project = project
}
if packet.EventID == "" {
var err error
packet.EventID, err = uuid()
if err != nil {
return err
}
}
if time.Time(packet.Timestamp).IsZero() {
packet.Timestamp = Timestamp(time.Now())
}
if packet.Level == "" {
packet.Level = ERROR
}
if packet.Logger == "" {
packet.Logger = "root"
}
if packet.ServerName == "" {
packet.ServerName = hostname
}
if packet.Platform == "" {
packet.Platform = "go"
}

if packet.Culprit == "" {
for _, inter := range packet.Interfaces {
if c, ok := inter.(Culpriter); ok {
packet.Culprit = c.Culprit()
if packet.Culprit != "" {
break
}
}
}
}

return nil
}

func (packet *Packet) AddTags(tags map[string]string) {
for k, v := range tags {
packet.Tags = append(packet.Tags, Tag{k, v})
}
}

func uuid() (string, error) {
id := make([]byte, 16)
_, err := io.ReadFull(rand.Reader, id)
if err != nil {
return "", err
}
id[6] &= 0x0F // clear version
id[6] |= 0x40 // set version to 4 (random uuid)
id[8] &= 0x3F // clear variant
id[8] |= 0x80 // set to IETF variant
return hex.EncodeToString(id), nil
}

func (packet *Packet) JSON() ([]byte, error) {
packetJSON, err := json.Marshal(packet)
if err != nil {
return nil, err
}

interfaces := make(map[string]Interface, len(packet.Interfaces))
for _, inter := range packet.Interfaces {
if inter != nil {
interfaces[inter.Class()] = inter
}
}

if len(interfaces) > 0 {
interfaceJSON, err := json.Marshal(interfaces)
if err != nil {
return nil, err
}
packetJSON[len(packetJSON)-1] = ','
packetJSON = append(packetJSON, interfaceJSON[1:]...)
}

return packetJSON, nil
}

type context struct {
user *User
http *Http
tags map[string]string
}

func (c *context) setUser(u *User) { c.user = u }
func (c *context) setHttp(h *Http) { c.http = h }
func (c *context) setTags(t map[string]string) {
if c.tags == nil {
c.tags = make(map[string]string)
}
for k, v := range t {
c.tags[k] = v
}
}
func (c *context) clear() {
c.user = nil
c.http = nil
c.tags = nil
}

// Return a list of interfaces to be used in appending with the rest
func (c *context) interfaces() []Interface {
len, i := 0, 0
if c.user != nil {
len++
}
if c.http != nil {
len++
}
interfaces := make([]Interface, len)
if c.user != nil {
interfaces[i] = c.user
i++
}
if c.http != nil {
interfaces[i] = c.http
i++
}
return interfaces
}

// The maximum number of packets that will be buffered waiting to be delivered.
// Packets will be dropped if the buffer is full. Used by NewClient.
var MaxQueueBuffer = 100

func newTransport() Transport {
t := &HTTPTransport{}
rootCAs, err := gocertifi.CACerts()
if err != nil {
log.Println("raven: failed to load root TLS certificates:", err)
} else {
t.Client = &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{RootCAs: rootCAs},
},
}
}
return t
}

func newClient(tags map[string]string) *Client {
client := &Client{
Transport: newTransport(),
Tags: tags,
context: &context{},
sampleRate: 1.0,
queue: make(chan *outgoingPacket, MaxQueueBuffer),
}
client.SetDSN(os.Getenv("SENTRY_DSN"))
client.SetRelease(os.Getenv("SENTRY_RELEASE"))
client.SetEnvironment(os.Getenv("SENTRY_ENVIRONMENT"))
return client
}

// New constructs a new Sentry client instance
func New(dsn string) (*Client, error) {
client := newClient(nil)
return client, client.SetDSN(dsn)
}

// NewWithTags constructs a new Sentry client instance with default tags.
func NewWithTags(dsn string, tags map[string]string) (*Client, error) {
client := newClient(tags)
return client, client.SetDSN(dsn)
}

// NewClient constructs a Sentry client and spawns a background goroutine to
// handle packets sent by Client.Report.
//
// Deprecated: use New and NewWithTags instead
func NewClient(dsn string, tags map[string]string) (*Client, error) {
client := newClient(tags)
return client, client.SetDSN(dsn)
}

// Client encapsulates a connection to a Sentry server. It must be initialized
// by calling NewClient. Modification of fields concurrently with Send or after
// calling Report for the first time is not thread-safe.
type Client struct {
Tags map[string]string

Transport Transport

// DropHandler is called when a packet is dropped because the buffer is full.
DropHandler func(*Packet)

// Context that will get appending to all packets
context *context

mu sync.RWMutex
url string
projectID string
authHeader string
release string
environment string
sampleRate float32

// default logger name (leave empty for 'root')
defaultLoggerName string

includePaths []string
ignoreErrorsRegexp *regexp.Regexp
queue chan *outgoingPacket

// A WaitGroup to keep track of all currently in-progress captures
// This is intended to be used with Client.Wait() to assure that
// all messages have been transported before exiting the process.
wg sync.WaitGroup

// A Once to track only starting up the background worker once
start sync.Once
}

// Initialize a default *Client instance
var DefaultClient = newClient(nil)

func (c *Client) SetIgnoreErrors(errs []string) error {
joinedRegexp := strings.Join(errs, "|")
r, err := regexp.Compile(joinedRegexp)
if err != nil {
return fmt.Errorf("failed to compile regexp %q for %q: %v", joinedRegexp, errs, err)
}

c.mu.Lock()
c.ignoreErrorsRegexp = r
c.mu.Unlock()
return nil
}

func (c *Client) shouldExcludeErr(errStr string) bool {
c.mu.RLock()
defer c.mu.RUnlock()
return c.ignoreErrorsRegexp != nil && c.ignoreErrorsRegexp.MatchString(errStr)
}

func SetIgnoreErrors(errs ...string) error {
return DefaultClient.SetIgnoreErrors(errs)
}

// SetDSN updates a client with a new DSN. It safe to call after and
// concurrently with calls to Report and Send.
func (client *Client) SetDSN(dsn string) error {
if dsn == "" {
return nil
}

client.mu.Lock()
defer client.mu.Unlock()

uri, err := url.Parse(dsn)
if err != nil {
return err
}

if uri.User == nil {
return ErrMissingUser
}
publicKey := uri.User.Username()
secretKey, hasSecretKey := uri.User.Password()
uri.User = nil

if idx := strings.LastIndex(uri.Path, "/"); idx != -1 {
client.projectID = uri.Path[idx+1:]
uri.Path = uri.Path[:idx+1] + "api/" + client.projectID + "/store/"
}
if client.projectID == "" {
return ErrMissingProjectID
}

client.url = uri.String()

if hasSecretKey {
client.authHeader = fmt.Sprintf("Sentry sentry_version=4, sentry_key=%s, sentry_secret=%s", publicKey, secretKey)
} else {
client.authHeader = fmt.Sprintf("Sentry sentry_version=4, sentry_key=%s", publicKey)
}

return nil
}

// Sets the DSN for the default *Client instance
func SetDSN(dsn string) error { return DefaultClient.SetDSN(dsn) }

// SetRelease sets the "release" tag.
func (client *Client) SetRelease(release string) {
client.mu.Lock()
defer client.mu.Unlock()
client.release = release
}

// SetEnvironment sets the "environment" tag.
func (client *Client) SetEnvironment(environment string) {
client.mu.Lock()
defer client.mu.Unlock()
client.environment = environment
}

// SetDefaultLoggerName sets the default logger name.
func (client *Client) SetDefaultLoggerName(name string) {
client.mu.Lock()
defer client.mu.Unlock()
client.defaultLoggerName = name
}

// SetSampleRate sets how much sampling we want on client side
func (client *Client) SetSampleRate(rate float32) error {
client.mu.Lock()
defer client.mu.Unlock()

if rate < 0 || rate > 1 {
return ErrInvalidSampleRate
}
client.sampleRate = rate
return nil
}

// SetRelease sets the "release" tag on the default *Client
func SetRelease(release string) { DefaultClient.SetRelease(release) }

// SetEnvironment sets the "environment" tag on the default *Client
func SetEnvironment(environment string) { DefaultClient.SetEnvironment(environment) }

// SetDefaultLoggerName sets the "defaultLoggerName" on the default *Client
func SetDefaultLoggerName(name string) {
DefaultClient.SetDefaultLoggerName(name)
}

// SetSampleRate sets the "sample rate" on the degault *Client
func SetSampleRate(rate float32) error { return DefaultClient.SetSampleRate(rate) }

func (client *Client) worker() {
for outgoingPacket := range client.queue {

client.mu.RLock()
url, authHeader := client.url, client.authHeader
client.mu.RUnlock()

outgoingPacket.ch <- client.Transport.Send(url, authHeader, outgoingPacket.packet)
client.wg.Done()
}
}

// Capture asynchronously delivers a packet to the Sentry server. It is a no-op
// when client is nil. A channel is provided if it is important to check for a
// send's success.
func (client *Client) Capture(packet *Packet, captureTags map[string]string) (eventID string, ch chan error) {
ch = make(chan error, 1)

if client == nil {
// return a chan that always returns nil when the caller receives from it
close(ch)
return
}

if client.sampleRate < 1.0 && mrand.Float32() > client.sampleRate {
return
}

if packet == nil {
close(ch)
return
}

if client.shouldExcludeErr(packet.Message) {
return
}

// Keep track of all running Captures so that we can wait for them all to finish
// *Must* call client.wg.Done() on any path that indicates that an event was
// finished being acted upon, whether success or failure
client.wg.Add(1)

// Merge capture tags and client tags
packet.AddTags(captureTags)
packet.AddTags(client.Tags)

// Initialize any required packet fields
client.mu.RLock()
packet.AddTags(client.context.tags)
projectID := client.projectID
release := client.release
environment := client.environment
defaultLoggerName := client.defaultLoggerName
client.mu.RUnlock()

// set the global logger name on the packet if we must
if packet.Logger == "" && defaultLoggerName != "" {
packet.Logger = defaultLoggerName
}

err := packet.Init(projectID)
if err != nil {
ch <- err
client.wg.Done()
return
}

if packet.Release == "" {
packet.Release = release
}

if packet.Environment == "" {
packet.Environment = environment
}

outgoingPacket := &outgoingPacket{packet, ch}

// Lazily start background worker until we
// do our first write into the queue.
client.start.Do(func() {
go client.worker()
})

select {
case client.queue <- outgoingPacket:
default:
// Send would block, drop the packet
if client.DropHandler != nil {
client.DropHandler(packet)
}
ch <- ErrPacketDropped
client.wg.Done()
}

return packet.EventID, ch
}

// Capture asynchronously delivers a packet to the Sentry server with the default *Client.
// It is a no-op when client is nil. A channel is provided if it is important to check for a
// send's success.
func Capture(packet *Packet, captureTags map[string]string) (eventID string, ch chan error) {
return DefaultClient.Capture(packet, captureTags)
}

// CaptureMessage formats and delivers a string message to the Sentry server.
func (client *Client) CaptureMessage(message string, tags map[string]string, interfaces ...Interface) string {
if client == nil {
return ""
}

if client.shouldExcludeErr(message) {
return ""
}

packet := NewPacket(message, append(append(interfaces, client.context.interfaces()...), &Message{message, nil})...)
eventID, _ := client.Capture(packet, tags)

return eventID
}

// CaptureMessage formats and delivers a string message to the Sentry server with the default *Client
func CaptureMessage(message string, tags map[string]string, interfaces ...Interface) string {
return DefaultClient.CaptureMessage(message, tags, interfaces...)
}

// CaptureMessageAndWait is identical to CaptureMessage except it blocks and waits for the message to be sent.
func (client *Client) CaptureMessageAndWait(message string, tags map[string]string, interfaces ...Interface) string {
if client == nil {
return ""
}

if client.shouldExcludeErr(message) {
return ""
}

packet := NewPacket(message, append(append(interfaces, client.context.interfaces()...), &Message{message, nil})...)
eventID, ch := client.Capture(packet, tags)
if eventID != "" {
<-ch
}

return eventID
}

// CaptureMessageAndWait is identical to CaptureMessage except it blocks and waits for the message to be sent.
func CaptureMessageAndWait(message string, tags map[string]string, interfaces ...Interface) string {
return DefaultClient.CaptureMessageAndWait(message, tags, interfaces...)
}

// CaptureErrors formats and delivers an error to the Sentry server.
// Adds a stacktrace to the packet, excluding the call to this method.
func (client *Client) CaptureError(err error, tags map[string]string, interfaces ...Interface) string {
if client == nil {
return ""
}

if err == nil {
return ""
}

if client.shouldExcludeErr(err.Error()) {
return ""
}

extra := extractExtra(err)
cause := pkgErrors.Cause(err)

packet := NewPacketWithExtra(err.Error(), extra, append(append(interfaces, client.context.interfaces()...), NewException(cause, GetOrNewStacktrace(cause, 1, 3, client.includePaths)))...)
eventID, _ := client.Capture(packet, tags)

return eventID
}

// CaptureErrors formats and delivers an error to the Sentry server using the default *Client.
// Adds a stacktrace to the packet, excluding the call to this method.
func CaptureError(err error, tags map[string]string, interfaces ...Interface) string {
return DefaultClient.CaptureError(err, tags, interfaces...)
}

// CaptureErrorAndWait is identical to CaptureError, except it blocks and assures that the event was sent
func (client *Client) CaptureErrorAndWait(err error, tags map[string]string, interfaces ...Interface) string {
if client == nil {
return ""
}

if client.shouldExcludeErr(err.Error()) {
return ""
}

extra := extractExtra(err)
cause := pkgErrors.Cause(err)

packet := NewPacketWithExtra(err.Error(), extra, append(append(interfaces, client.context.interfaces()...), NewException(cause, GetOrNewStacktrace(cause, 1, 3, client.includePaths)))...)
eventID, ch := client.Capture(packet, tags)
if eventID != "" {
<-ch
}

return eventID
}

// CaptureErrorAndWait is identical to CaptureError, except it blocks and assures that the event was sent
func CaptureErrorAndWait(err error, tags map[string]string, interfaces ...Interface) string {
return DefaultClient.CaptureErrorAndWait(err, tags, interfaces...)
}

// CapturePanic calls f and then recovers and reports a panic to the Sentry server if it occurs.
// If an error is captured, both the error and the reported Sentry error ID are returned.
func (client *Client) CapturePanic(f func(), tags map[string]string, interfaces ...Interface) (err interface{}, errorID string) {
// Note: This doesn't need to check for client, because we still want to go through the defer/recover path
// Down the line, Capture will be noop'd, so while this does a _tiny_ bit of overhead constructing the
// *Packet just to be thrown away, this should not be the normal case. Could be refactored to
// be completely noop though if we cared.
defer func() {
var packet *Packet
err = recover()
switch rval := err.(type) {
case nil:
return
case error:
if client.shouldExcludeErr(rval.Error()) {
return
}
packet = NewPacket(rval.Error(), append(append(interfaces, client.context.interfaces()...), NewException(rval, NewStacktrace(2, 3, client.includePaths)))...)
default:
rvalStr := fmt.Sprint(rval)
if client.shouldExcludeErr(rvalStr) {
return
}
packet = NewPacket(rvalStr, append(append(interfaces, client.context.interfaces()...), NewException(errors.New(rvalStr), NewStacktrace(2, 3, client.includePaths)))...)
}

errorID, _ = client.Capture(packet, tags)
}()

f()
return
}

// CapturePanic calls f and then recovers and reports a panic to the Sentry server if it occurs.
// If an error is captured, both the error and the reported Sentry error ID are returned.
func CapturePanic(f func(), tags map[string]string, interfaces ...Interface) (interface{}, string) {
return DefaultClient.CapturePanic(f, tags, interfaces...)
}

// CapturePanicAndWait is identical to CaptureError, except it blocks and assures that the event was sent
func (client *Client) CapturePanicAndWait(f func(), tags map[string]string, interfaces ...Interface) (err interface{}, errorID string) {
// Note: This doesn't need to check for client, because we still want to go through the defer/recover path
// Down the line, Capture will be noop'd, so while this does a _tiny_ bit of overhead constructing the
// *Packet just to be thrown away, this should not be the normal case. Could be refactored to
// be completely noop though if we cared.
defer func() {
var packet *Packet
err = recover()
switch rval := err.(type) {
case nil:
return
case error:
if client.shouldExcludeErr(rval.Error()) {
return
}
packet = NewPacket(rval.Error(), append(append(interfaces, client.context.interfaces()...), NewException(rval, NewStacktrace(2, 3, client.includePaths)))...)
default:
rvalStr := fmt.Sprint(rval)
if client.shouldExcludeErr(rvalStr) {
return
}
packet = NewPacket(rvalStr, append(append(interfaces, client.context.interfaces()...), NewException(errors.New(rvalStr), NewStacktrace(2, 3, client.includePaths)))...)
}

var ch chan error
errorID, ch = client.Capture(packet, tags)
if errorID != "" {
<-ch
}
}()

f()
return
}

// CapturePanicAndWait is identical to CaptureError, except it blocks and assures that the event was sent
func CapturePanicAndWait(f func(), tags map[string]string, interfaces ...Interface) (interface{}, string) {
return DefaultClient.CapturePanicAndWait(f, tags, interfaces...)
}

func (client *Client) Close() {
close(client.queue)
}

func Close() { DefaultClient.Close() }

// Wait blocks and waits for all events to finish being sent to Sentry server
func (client *Client) Wait() {
client.wg.Wait()
}

// Wait blocks and waits for all events to finish being sent to Sentry server
func Wait() { DefaultClient.Wait() }

func (client *Client) URL() string {
client.mu.RLock()
defer client.mu.RUnlock()

return client.url
}

func URL() string { return DefaultClient.URL() }

func (client *Client) ProjectID() string {
client.mu.RLock()
defer client.mu.RUnlock()

return client.projectID
}

func ProjectID() string { return DefaultClient.ProjectID() }

func (client *Client) Release() string {
client.mu.RLock()
defer client.mu.RUnlock()

return client.release
}

func Release() string { return DefaultClient.Release() }

func IncludePaths() []string { return DefaultClient.IncludePaths() }

func (client *Client) IncludePaths() []string {
client.mu.RLock()
defer client.mu.RUnlock()

return client.includePaths
}

func SetIncludePaths(p []string) { DefaultClient.SetIncludePaths(p) }

func (client *Client) SetIncludePaths(p []string) {
client.mu.Lock()
defer client.mu.Unlock()

client.includePaths = p
}

func (c *Client) SetUserContext(u *User) {
c.mu.Lock()
defer c.mu.Unlock()
c.context.setUser(u)
}

func (c *Client) SetHttpContext(h *Http) {
c.mu.Lock()
defer c.mu.Unlock()
c.context.setHttp(h)
}

func (c *Client) SetTagsContext(t map[string]string) {
c.mu.Lock()
defer c.mu.Unlock()
c.context.setTags(t)
}

func (c *Client) ClearContext() {
c.mu.Lock()
defer c.mu.Unlock()
c.context.clear()
}

func SetUserContext(u *User) { DefaultClient.SetUserContext(u) }
func SetHttpContext(h *Http) { DefaultClient.SetHttpContext(h) }
func SetTagsContext(t map[string]string) { DefaultClient.SetTagsContext(t) }
func ClearContext() { DefaultClient.ClearContext() }

// HTTPTransport is the default transport, delivering packets to Sentry via the
// HTTP API.
type HTTPTransport struct {
*http.Client
}

func (t *HTTPTransport) Send(url, authHeader string, packet *Packet) error {
if url == "" {
return nil
}

body, contentType, err := serializedPacket(packet)
if err != nil {
return fmt.Errorf("error serializing packet: %v", err)
}
req, err := http.NewRequest("POST", url, body)
if err != nil {
return fmt.Errorf("can't create new request: %v", err)
}
req.Header.Set("X-Sentry-Auth", authHeader)
req.Header.Set("User-Agent", userAgent)
req.Header.Set("Content-Type", contentType)
res, err := t.Do(req)
if err != nil {
return err
}
io.Copy(ioutil.Discard, res.Body)
res.Body.Close()
if res.StatusCode != 200 {
return fmt.Errorf("raven: got http status %d - x-sentry-error: %s", res.StatusCode, res.Header.Get("X-Sentry-Error"))
}
return nil
}

func serializedPacket(packet *Packet) (io.Reader, string, error) {
packetJSON, err := packet.JSON()
if err != nil {
return nil, "", fmt.Errorf("error marshaling packet %+v to JSON: %v", packet, err)
}

// Only deflate/base64 the packet if it is bigger than 1KB, as there is
// overhead.
if len(packetJSON) > 1000 {
buf := &bytes.Buffer{}
b64 := base64.NewEncoder(base64.StdEncoding, buf)
deflate, _ := zlib.NewWriterLevel(b64, zlib.BestCompression)
deflate.Write(packetJSON)
deflate.Close()
b64.Close()
return buf, "application/octet-stream", nil
}
return bytes.NewReader(packetJSON), "application/json", nil
}

var hostname string

func init() {
hostname, _ = os.Hostname()
}

+ 60
- 0
vendor/github.com/getsentry/raven-go/errors.go View File

@@ -0,0 +1,60 @@
package raven

type causer interface {
Cause() error
}

type errWrappedWithExtra struct {
err error
extraInfo map[string]interface{}
}

func (ewx *errWrappedWithExtra) Error() string {
return ewx.err.Error()
}

func (ewx *errWrappedWithExtra) Cause() error {
return ewx.err
}

func (ewx *errWrappedWithExtra) ExtraInfo() Extra {
return ewx.extraInfo
}

// Adds extra data to an error before reporting to Sentry
func WrapWithExtra(err error, extraInfo map[string]interface{}) error {
return &errWrappedWithExtra{
err: err,
extraInfo: extraInfo,
}
}

type ErrWithExtra interface {
Error() string
Cause() error
ExtraInfo() Extra
}

// Iteratively fetches all the Extra data added to an error,
// and it's underlying errors. Extra data defined first is
// respected, and is not overridden when extracting.
func extractExtra(err error) Extra {
extra := Extra{}

currentErr := err
for currentErr != nil {
if errWithExtra, ok := currentErr.(ErrWithExtra); ok {
for k, v := range errWithExtra.ExtraInfo() {
extra[k] = v
}
}

if errWithCause, ok := currentErr.(causer); ok {
currentErr = errWithCause.Cause()
} else {
currentErr = nil
}
}

return extra
}

+ 42
- 0
vendor/github.com/getsentry/raven-go/example/example.go View File

@@ -0,0 +1,42 @@
package main

import (
"errors"
"fmt"
"github.com/getsentry/raven-go"
"log"
"net/http"
"os"
)

func trace() *raven.Stacktrace {
return raven.NewStacktrace(0, 2, nil)
}

func main() {
client, err := raven.NewWithTags(os.Args[1], map[string]string{"foo": "bar"})
if err != nil {
log.Fatal(err)
}
httpReq, _ := http.NewRequest("GET", "http://example.com/foo?bar=true", nil)
httpReq.RemoteAddr = "127.0.0.1:80"
httpReq.Header = http.Header{"Content-Type": {"text/html"}, "Content-Length": {"42"}}
packet := &raven.Packet{Message: "Test report", Interfaces: []raven.Interface{raven.NewException(errors.New("example"), trace()), raven.NewHttp(httpReq)}}
_, ch := client.Capture(packet, nil)
if err = <-ch; err != nil {
log.Fatal(err)
}
log.Print("sent packet successfully")
}

// CheckError sends error report to sentry and records event id and error name to the logs
func CheckError(err error, r *http.Request) {
client, err := raven.NewWithTags(os.Args[1], map[string]string{"foo": "bar"})
if err != nil {
log.Fatal(err)
}
packet := raven.NewPacket(err.Error(), raven.NewException(err, trace()), raven.NewHttp(r))
eventID, _ := client.Capture(packet, nil)
message := fmt.Sprintf("Error event with id \"%s\" - %s", eventID, err.Error())
log.Println(message)
}

+ 50
- 0
vendor/github.com/getsentry/raven-go/exception.go View File

@@ -0,0 +1,50 @@
package raven

import (
"reflect"
"regexp"
)

var errorMsgPattern = regexp.MustCompile(`\A(\w+): (.+)\z`)

func NewException(err error, stacktrace *Stacktrace) *Exception {
msg := err.Error()
ex := &Exception{
Stacktrace: stacktrace,
Value: msg,
Type: reflect.TypeOf(err).String(),
}
if m := errorMsgPattern.FindStringSubmatch(msg); m != nil {
ex.Module, ex.Value = m[1], m[2]
}
return ex
}

// https://docs.getsentry.com/hosted/clientdev/interfaces/#failure-interfaces
type Exception struct {
// Required
Value string `json:"value"`

// Optional
Type string `json:"type,omitempty"`
Module string `json:"module,omitempty"`
Stacktrace *Stacktrace `json:"stacktrace,omitempty"`
}

func (e *Exception) Class() string { return "exception" }

func (e *Exception) Culprit() string {
if e.Stacktrace == nil {
return ""
}
return e.Stacktrace.Culprit()
}

// Exceptions allows for chained errors
// https://docs.sentry.io/clientdev/interfaces/exception/
type Exceptions struct {
// Required
Values []*Exception `json:"values"`
}

func (es Exceptions) Class() string { return "exception" }

+ 99
- 0
vendor/github.com/getsentry/raven-go/http.go View File

@@ -0,0 +1,99 @@
package raven

import (
"errors"
"fmt"
"net"
"net/http"
"net/url"
"runtime/debug"
"strings"
)

func NewHttp(req *http.Request) *Http {
proto := "http"
if req.TLS != nil || req.Header.Get("X-Forwarded-Proto") == "https" {
proto = "https"
}
h := &Http{
Method: req.Method,
Cookies: req.Header.Get("Cookie"),
Query: sanitizeQuery(req.URL.Query()).Encode(),
URL: proto + "://" + req.Host + req.URL.Path,
Headers: make(map[string]string, len(req.Header)),
}
if addr, port, err := net.SplitHostPort(req.RemoteAddr); err == nil {
h.Env = map[string]string{"REMOTE_ADDR": addr, "REMOTE_PORT": port}
}
for k, v := range req.Header {
h.Headers[k] = strings.Join(v, ",")
}
h.Headers["Host"] = req.Host
return h
}

var querySecretFields = []string{"password", "passphrase", "passwd", "secret"}

func sanitizeQuery(query url.Values) url.Values {
for _, keyword := range querySecretFields {
for field := range query {
if strings.Contains(field, keyword) {
query[field] = []string{"********"}
}
}
}
return query
}

// https://docs.getsentry.com/hosted/clientdev/interfaces/#context-interfaces
type Http struct {
// Required
URL string `json:"url"`
Method string `json:"method"`
Query string `json:"query_string,omitempty"`

// Optional
Cookies string `json:"cookies,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
Env map[string]string `json:"env,omitempty"`

// Must be either a string or map[string]string
Data interface{} `json:"data,omitempty"`
}

func (h *Http) Class() string { return "request" }

// Recovery handler to wrap the stdlib net/http Mux.
// Example:
// http.HandleFunc("/", raven.RecoveryHandler(func(w http.ResponseWriter, r *http.Request) {
// ...
// }))
func RecoveryHandler(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
return Recoverer(http.HandlerFunc(handler)).ServeHTTP
}

// Recovery handler to wrap the stdlib net/http Mux.
// Example:
// mux := http.NewServeMux
// ...
// http.Handle("/", raven.Recoverer(mux))
func Recoverer(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if rval := recover(); rval != nil {
debug.PrintStack()
rvalStr := fmt.Sprint(rval)
var packet *Packet
if err, ok := rval.(error); ok {
packet = NewPacket(rvalStr, NewException(errors.New(rvalStr), GetOrNewStacktrace(err, 2, 3, nil)), NewHttp(r))
} else {
packet = NewPacket(rvalStr, NewException(errors.New(rvalStr), NewStacktrace(2, 3, nil)), NewHttp(r))
}
Capture(packet, nil)
w.WriteHeader(http.StatusInternalServerError)
}
}()

handler.ServeHTTP(w, r)
})
}

+ 49
- 0
vendor/github.com/getsentry/raven-go/interfaces.go View File

@@ -0,0 +1,49 @@
package raven

// https://docs.getsentry.com/hosted/clientdev/interfaces/#message-interface
type Message struct {
// Required
Message string `json:"message"`

// Optional
Params []interface{} `json:"params,omitempty"`
}

func (m *Message) Class() string { return "logentry" }

// https://docs.getsentry.com/hosted/clientdev/interfaces/#template-interface
type Template struct {
// Required
Filename string `json:"filename"`
Lineno int `json:"lineno"`
ContextLine string `json:"context_line"`

// Optional
PreContext []string `json:"pre_context,omitempty"`
PostContext []string `json:"post_context,omitempty"`
AbsolutePath string `json:"abs_path,omitempty"`
}

func (t *Template) Class() string { return "template" }

// https://docs.getsentry.com/hosted/clientdev/interfaces/#context-interfaces
type User struct {
// All fields are optional
ID string `json:"id,omitempty"`
Username string `json:"username,omitempty"`
Email string `json:"email,omitempty"`
IP string `json:"ip_address,omitempty"`
}

func (h *User) Class() string { return "user" }

// https://docs.getsentry.com/hosted/clientdev/interfaces/#context-interfaces
type Query struct {
// Required
Query string `json:"query"`

// Optional
Engine string `json:"engine,omitempty"`
}

func (q *Query) Class() string { return "query" }

+ 277
- 0
vendor/github.com/getsentry/raven-go/stacktrace.go View File

@@ -0,0 +1,277 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Some code from the runtime/debug package of the Go standard library.

package raven

import (
"bytes"
"go/build"
"io/ioutil"
"path/filepath"
"runtime"
"strings"
"sync"

"github.com/pkg/errors"
)

// https://docs.getsentry.com/hosted/clientdev/interfaces/#failure-interfaces
type Stacktrace struct {
// Required
Frames []*StacktraceFrame `json:"frames"`
}

func (s *Stacktrace) Class() string { return "stacktrace" }

func (s *Stacktrace) Culprit() string {
for i := len(s.Frames) - 1; i >= 0; i-- {
frame := s.Frames[i]
if frame.InApp == true && frame.Module != "" && frame.Function != "" {
return frame.Module + "." + frame.Function
}
}
return ""
}

type StacktraceFrame struct {
// At least one required
Filename string `json:"filename,omitempty"`
Function string `json:"function,omitempty"`
Module string `json:"module,omitempty"`

// Optional
Lineno int `json:"lineno,omitempty"`
Colno int `json:"colno,omitempty"`
AbsolutePath string `json:"abs_path,omitempty"`
ContextLine string `json:"context_line,omitempty"`
PreContext []string `json:"pre_context,omitempty"`
PostContext []string `json:"post_context,omitempty"`
InApp bool `json:"in_app"`
}

// Try to get stacktrace from err as an interface of github.com/pkg/errors, or else NewStacktrace()
func GetOrNewStacktrace(err error, skip int, context int, appPackagePrefixes []string) *Stacktrace {
stacktracer, errHasStacktrace := err.(interface {
StackTrace() errors.StackTrace
})
if errHasStacktrace {
var frames []*StacktraceFrame
for _, f := range stacktracer.StackTrace() {
pc := uintptr(f) - 1
fn := runtime.FuncForPC(pc)
var fName string
var file string
var line int
if fn != nil {
file, line = fn.FileLine(pc)
fName = fn.Name()
} else {
file = "unknown"
fName = "unknown"
}
frame := NewStacktraceFrame(pc, fName, file, line, context, appPackagePrefixes)
if frame != nil {
frames = append([]*StacktraceFrame{frame}, frames...)
}
}
return &Stacktrace{Frames: frames}
} else {
return NewStacktrace(skip+1, context, appPackagePrefixes)
}
}

// Intialize and populate a new stacktrace, skipping skip frames.
//
// context is the number of surrounding lines that should be included for context.
// Setting context to 3 would try to get seven lines. Setting context to -1 returns
// one line with no surrounding context, and 0 returns no context.
//
// appPackagePrefixes is a list of prefixes used to check whether a package should
// be considered "in app".
<