diff options
Diffstat (limited to 'vendor/cloud.google.com/go/errors/errors.go')
| -rw-r--r-- | vendor/cloud.google.com/go/errors/errors.go | 453 |
1 files changed, 0 insertions, 453 deletions
diff --git a/vendor/cloud.google.com/go/errors/errors.go b/vendor/cloud.google.com/go/errors/errors.go deleted file mode 100644 index d5e78b8f4..000000000 --- a/vendor/cloud.google.com/go/errors/errors.go +++ /dev/null @@ -1,453 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package errors is a Google Stackdriver Error Reporting library. -// -// This package is still experimental and subject to change. -// -// See https://cloud.google.com/error-reporting/ for more information. -// -// To initialize a client, use the NewClient function. Generally you will want -// to do this on program initialization. The NewClient function takes as -// arguments a context, the project name, a service name, and a version string. -// The service name and version string identify the running program, and are -// included in error reports. The version string can be left empty. NewClient -// also takes a bool that indicates whether to report errors using Stackdriver -// Logging, which will result in errors appearing in both the logs and the error -// dashboard. This is useful if you are already a user of Stackdriver Logging. -// -// import "cloud.google.com/go/errors" -// ... -// errorsClient, err = errors.NewClient(ctx, projectID, "myservice", "v1.0", true) -// -// The client can recover panics in your program and report them as errors. -// To use this functionality, defer its Catch method, as you would any other -// function for recovering panics. -// -// func foo(ctx context.Context, ...) { -// defer errorsClient.Catch(ctx) -// ... -// } -// -// Catch writes an error report containing the recovered value and a stack trace -// to Stackdriver Error Reporting. -// -// There are various options you can add to the call to Catch that modify how -// panics are handled. -// -// WithMessage and WithMessagef add a custom message after the recovered value, -// using fmt.Sprint and fmt.Sprintf respectively. -// -// defer errorsClient.Catch(ctx, errors.WithMessagef("x=%d", x)) -// -// WithRequest fills in various fields in the error report with information -// about an http.Request that's being handled. -// -// defer errorsClient.Catch(ctx, errors.WithRequest(httpReq)) -// -// By default, after recovering a panic, Catch will panic again with the -// recovered value. You can turn off this behavior with the Repanic option. -// -// defer errorsClient.Catch(ctx, errors.Repanic(false)) -// -// You can also change the default behavior for the client by changing the -// RepanicDefault field. -// -// errorsClient.RepanicDefault = false -// -// It is also possible to write an error report directly without recovering a -// panic, using Report or Reportf. -// -// if err != nil { -// errorsClient.Reportf(ctx, r, "unexpected error %v", err) -// } -// -// If you try to write an error report with a nil client, or if the client -// fails to write the report to the server, the error report is logged using -// log.Println. -package errors // import "cloud.google.com/go/errors" - -import ( - "bytes" - "fmt" - "log" - "net/http" - "runtime" - "strings" - "time" - - api "cloud.google.com/go/errorreporting/apiv1beta1" - "cloud.google.com/go/internal/version" - "cloud.google.com/go/logging" - "github.com/golang/protobuf/ptypes/timestamp" - gax "github.com/googleapis/gax-go" - "golang.org/x/net/context" - "google.golang.org/api/option" - erpb "google.golang.org/genproto/googleapis/devtools/clouderrorreporting/v1beta1" -) - -const ( - userAgent = `gcloud-golang-errorreporting/20160701` -) - -type apiInterface interface { - ReportErrorEvent(ctx context.Context, req *erpb.ReportErrorEventRequest, opts ...gax.CallOption) (*erpb.ReportErrorEventResponse, error) - Close() error -} - -var newApiInterface = func(ctx context.Context, opts ...option.ClientOption) (apiInterface, error) { - client, err := api.NewReportErrorsClient(ctx, opts...) - if err != nil { - return nil, err - } - client.SetGoogleClientInfo("gccl", version.Repo) - return client, nil -} - -type loggerInterface interface { - LogSync(ctx context.Context, e logging.Entry) error - Close() error -} - -type logger struct { - *logging.Logger - c *logging.Client -} - -func (l logger) Close() error { - return l.c.Close() -} - -var newLoggerInterface = func(ctx context.Context, projectID string, opts ...option.ClientOption) (loggerInterface, error) { - lc, err := logging.NewClient(ctx, projectID, opts...) - if err != nil { - return nil, fmt.Errorf("creating Logging client: %v", err) - } - l := lc.Logger("errorreports") - return logger{l, lc}, nil -} - -type sender interface { - send(ctx context.Context, r *http.Request, message string) - close() error -} - -// errorApiSender sends error reports using the Stackdriver Error Reporting API. -type errorApiSender struct { - apiClient apiInterface - projectID string - serviceContext erpb.ServiceContext -} - -// loggingSender sends error reports using the Stackdriver Logging API. -type loggingSender struct { - logger loggerInterface - projectID string - serviceContext map[string]string - client *logging.Client -} - -type Client struct { - sender - // RepanicDefault determines whether Catch will re-panic after recovering a - // panic. This behavior can be overridden for an individual call to Catch using - // the Repanic option. - RepanicDefault bool -} - -func NewClient(ctx context.Context, projectID, serviceName, serviceVersion string, useLogging bool, opts ...option.ClientOption) (*Client, error) { - if useLogging { - l, err := newLoggerInterface(ctx, projectID, opts...) - if err != nil { - return nil, fmt.Errorf("creating Logging client: %v", err) - } - sender := &loggingSender{ - logger: l, - projectID: projectID, - serviceContext: map[string]string{ - "service": serviceName, - }, - } - if serviceVersion != "" { - sender.serviceContext["version"] = serviceVersion - } - c := &Client{ - sender: sender, - RepanicDefault: true, - } - return c, nil - } else { - a, err := newApiInterface(ctx, opts...) - if err != nil { - return nil, fmt.Errorf("creating Error Reporting client: %v", err) - } - c := &Client{ - sender: &errorApiSender{ - apiClient: a, - projectID: "projects/" + projectID, - serviceContext: erpb.ServiceContext{ - Service: serviceName, - Version: serviceVersion, - }, - }, - RepanicDefault: true, - } - return c, nil - } -} - -// Close closes any resources held by the client. -// Close should be called when the client is no longer needed. -// It need not be called at program exit. -func (c *Client) Close() error { - err := c.sender.close() - c.sender = nil - return err -} - -// An Option is an optional argument to Catch. -type Option interface { - isOption() -} - -// PanicFlag returns an Option that can inform Catch that a panic has occurred. -// If *p is true when Catch is called, an error report is made even if recover -// returns nil. This allows Catch to report an error for panic(nil). -// If p is nil, the option is ignored. -// -// Here is an example of how to use PanicFlag: -// -// func foo(ctx context.Context, ...) { -// hasPanicked := true -// defer errorsClient.Catch(ctx, errors.PanicFlag(&hasPanicked)) -// ... -// ... -// // We have reached the end of the function, so we're not panicking. -// hasPanicked = false -// } -func PanicFlag(p *bool) Option { return panicFlag{p} } - -type panicFlag struct { - *bool -} - -func (h panicFlag) isOption() {} - -// Repanic returns an Option that determines whether Catch will re-panic after -// it reports an error. This overrides the default in the client. -func Repanic(r bool) Option { return repanic(r) } - -type repanic bool - -func (r repanic) isOption() {} - -// WithRequest returns an Option that informs Catch or Report of an http.Request -// that is being handled. Information from the Request is included in the error -// report, if one is made. -func WithRequest(r *http.Request) Option { return withRequest{r} } - -type withRequest struct { - *http.Request -} - -func (w withRequest) isOption() {} - -// WithMessage returns an Option that sets a message to be included in the error -// report, if one is made. v is converted to a string with fmt.Sprint. -func WithMessage(v ...interface{}) Option { return message(v) } - -type message []interface{} - -func (m message) isOption() {} - -// WithMessagef returns an Option that sets a message to be included in the error -// report, if one is made. format and v are converted to a string with fmt.Sprintf. -func WithMessagef(format string, v ...interface{}) Option { return messagef{format, v} } - -type messagef struct { - format string - v []interface{} -} - -func (m messagef) isOption() {} - -// Catch tries to recover a panic; if it succeeds, it writes an error report. -// It should be called by deferring it, like any other function for recovering -// panics. -// -// Catch can be called concurrently with other calls to Catch, Report or Reportf. -func (c *Client) Catch(ctx context.Context, opt ...Option) { - panicked := false - for _, o := range opt { - switch o := o.(type) { - case panicFlag: - panicked = panicked || o.bool != nil && *o.bool - } - } - x := recover() - if x == nil && !panicked { - return - } - var ( - r *http.Request - shouldRepanic = true - messages = []string{fmt.Sprint(x)} - ) - if c != nil { - shouldRepanic = c.RepanicDefault - } - for _, o := range opt { - switch o := o.(type) { - case repanic: - shouldRepanic = bool(o) - case withRequest: - r = o.Request - case message: - messages = append(messages, fmt.Sprint(o...)) - case messagef: - messages = append(messages, fmt.Sprintf(o.format, o.v...)) - } - } - c.logInternal(ctx, r, true, strings.Join(messages, " ")) - if shouldRepanic { - panic(x) - } -} - -// Report writes an error report unconditionally, instead of only when a panic -// occurs. -// If r is non-nil, information from the Request is included in the error report. -// -// Report can be called concurrently with other calls to Catch, Report or Reportf. -func (c *Client) Report(ctx context.Context, r *http.Request, v ...interface{}) { - c.logInternal(ctx, r, false, fmt.Sprint(v...)) -} - -// Reportf writes an error report unconditionally, instead of only when a panic -// occurs. -// If r is non-nil, information from the Request is included in the error report. -// -// Reportf can be called concurrently with other calls to Catch, Report or Reportf. -func (c *Client) Reportf(ctx context.Context, r *http.Request, format string, v ...interface{}) { - c.logInternal(ctx, r, false, fmt.Sprintf(format, v...)) -} - -func (c *Client) logInternal(ctx context.Context, r *http.Request, isPanic bool, msg string) { - // limit the stack trace to 16k. - var buf [16384]byte - stack := buf[0:runtime.Stack(buf[:], false)] - message := msg + "\n" + chopStack(stack, isPanic) - if c == nil { - log.Println("Error report used nil client:", message) - return - } - c.send(ctx, r, message) -} - -func (s *loggingSender) send(ctx context.Context, r *http.Request, message string) { - payload := map[string]interface{}{ - "eventTime": time.Now().In(time.UTC).Format(time.RFC3339Nano), - "message": message, - "serviceContext": s.serviceContext, - } - if r != nil { - payload["context"] = map[string]interface{}{ - "httpRequest": map[string]interface{}{ - "method": r.Method, - "url": r.Host + r.RequestURI, - "userAgent": r.UserAgent(), - "referrer": r.Referer(), - "remoteIp": r.RemoteAddr, - }, - } - } - e := logging.Entry{ - Severity: logging.Error, - Payload: payload, - } - err := s.logger.LogSync(ctx, e) - if err != nil { - log.Println("Error writing error report:", err, "report:", payload) - } -} - -func (s *loggingSender) close() error { - return s.client.Close() -} - -func (s *errorApiSender) send(ctx context.Context, r *http.Request, message string) { - time := time.Now() - var errorContext *erpb.ErrorContext - if r != nil { - errorContext = &erpb.ErrorContext{ - HttpRequest: &erpb.HttpRequestContext{ - Method: r.Method, - Url: r.Host + r.RequestURI, - UserAgent: r.UserAgent(), - Referrer: r.Referer(), - RemoteIp: r.RemoteAddr, - }, - } - } - req := erpb.ReportErrorEventRequest{ - ProjectName: s.projectID, - Event: &erpb.ReportedErrorEvent{ - EventTime: ×tamp.Timestamp{ - Seconds: time.Unix(), - Nanos: int32(time.Nanosecond()), - }, - ServiceContext: &s.serviceContext, - Message: message, - Context: errorContext, - }, - } - _, err := s.apiClient.ReportErrorEvent(ctx, &req) - if err != nil { - log.Println("Error writing error report:", err, "report:", message) - } -} - -func (s *errorApiSender) close() error { - return s.apiClient.Close() -} - -// chopStack trims a stack trace so that the function which panics or calls -// Report is first. -func chopStack(s []byte, isPanic bool) string { - var f []byte - if isPanic { - f = []byte("panic(") - } else { - f = []byte("cloud.google.com/go/errors.(*Client).Report") - } - - lfFirst := bytes.IndexByte(s, '\n') - if lfFirst == -1 { - return string(s) - } - stack := s[lfFirst:] - panicLine := bytes.Index(stack, f) - if panicLine == -1 { - return string(s) - } - stack = stack[panicLine+1:] - for i := 0; i < 2; i++ { - nextLine := bytes.IndexByte(stack, '\n') - if nextLine == -1 { - return string(s) - } - stack = stack[nextLine+1:] - } - return string(s[:lfFirst+1]) + string(stack) -} |
