Migrate Sirupsen to sirupsen.

This commit is contained in:
Ludovic Fernandez 2018-01-22 12:16:03 +01:00 committed by Traefiker
parent c134dcd6fe
commit fb4ba7af2b
684 changed files with 92394 additions and 33943 deletions

201
vendor/github.com/gravitational/trace/LICENSE generated vendored Normal file
View file

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2015 Gravitational, Inc.
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.

448
vendor/github.com/gravitational/trace/errors.go generated vendored Normal file
View file

@ -0,0 +1,448 @@
/*
Copyright 2015 Gravitational, Inc.
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 trace
import (
"crypto/x509"
"fmt"
"io"
"net"
"net/url"
"os"
)
// NotFound returns new instance of not found error
func NotFound(message string, args ...interface{}) error {
return WrapWithMessage(&NotFoundError{
Message: fmt.Sprintf(message, args...),
}, message, args...)
}
// NotFoundError indicates that object has not been found
type NotFoundError struct {
Message string `json:"message"`
}
// IsNotFoundError returns true to indicate that is NotFoundError
func (e *NotFoundError) IsNotFoundError() bool {
return true
}
// Error returns log friendly description of an error
func (e *NotFoundError) Error() string {
if e.Message != "" {
return e.Message
}
return "object not found"
}
// OrigError returns original error (in this case this is the error itself)
func (e *NotFoundError) OrigError() error {
return e
}
// IsNotFound returns whether this error is of NotFoundError type
func IsNotFound(e error) bool {
type nf interface {
IsNotFoundError() bool
}
err := Unwrap(e)
_, ok := err.(nf)
if !ok {
return os.IsNotExist(err)
}
return ok
}
// AlreadyExists returns a new instance of AlreadyExists error
func AlreadyExists(message string, args ...interface{}) error {
return WrapWithMessage(&AlreadyExistsError{
fmt.Sprintf(message, args...),
}, message, args...)
}
// AlreadyExistsError indicates that there's a duplicate object that already
// exists in the storage/system
type AlreadyExistsError struct {
Message string `json:"message"`
}
// Error returns log friendly description of an error
func (n *AlreadyExistsError) Error() string {
if n.Message != "" {
return n.Message
}
return "object already exists"
}
// IsAlreadyExistsError indicates that this error of the AlreadyExistsError type
func (AlreadyExistsError) IsAlreadyExistsError() bool {
return true
}
// OrigError returns original error (in this case this is the error itself)
func (e *AlreadyExistsError) OrigError() error {
return e
}
// IsAlreadyExists returns whether this is error indicating that object
// already exists
func IsAlreadyExists(e error) bool {
type ae interface {
IsAlreadyExistsError() bool
}
_, ok := Unwrap(e).(ae)
return ok
}
// BadParameter returns a new instance of BadParameterError
func BadParameter(message string, args ...interface{}) error {
return WrapWithMessage(&BadParameterError{
Message: fmt.Sprintf(message, args...),
}, message, args...)
}
// BadParameterError indicates that something is wrong with passed
// parameter to API method
type BadParameterError struct {
Message string `json:"message"`
}
// Error returns log friendly description of an error
func (b *BadParameterError) Error() string {
return b.Message
}
// OrigError returns original error (in this case this is the error itself)
func (b *BadParameterError) OrigError() error {
return b
}
// IsBadParameterError indicates that this error is of BadParameterError type
func (b *BadParameterError) IsBadParameterError() bool {
return true
}
// IsBadParameter returns whether this error is of BadParameterType
func IsBadParameter(e error) bool {
type bp interface {
IsBadParameterError() bool
}
_, ok := Unwrap(e).(bp)
return ok
}
// CompareFailed returns new instance of CompareFailedError
func CompareFailed(message string, args ...interface{}) error {
return WrapWithMessage(&CompareFailedError{Message: fmt.Sprintf(message, args...)}, message, args...)
}
// CompareFailedError indicates a failed comparison (e.g. bad password or hash)
type CompareFailedError struct {
// Message is user-friendly error message
Message string `json:"message"`
}
// Error is debug - friendly message
func (e *CompareFailedError) Error() string {
if e.Message != "" {
return e.Message
}
return "compare failed"
}
// OrigError returns original error (in this case this is the error itself)
func (e *CompareFailedError) OrigError() error {
return e
}
// IsCompareFailedError indicates that this is CompareFailedError
func (e *CompareFailedError) IsCompareFailedError() bool {
return true
}
// IsCompareFailed detects if this error is of CompareFailed type
func IsCompareFailed(e error) bool {
type cf interface {
IsCompareFailedError() bool
}
_, ok := Unwrap(e).(cf)
return ok
}
// AccessDenied returns new instance of AccessDeniedError
func AccessDenied(message string, args ...interface{}) error {
return WrapWithMessage(&AccessDeniedError{
Message: fmt.Sprintf(message, args...),
}, message, args...)
}
// AccessDeniedError indicates denied access
type AccessDeniedError struct {
Message string `json:"message"`
}
// Error is debug - friendly error message
func (e *AccessDeniedError) Error() string {
if e.Message != "" {
return e.Message
}
return "access denied"
}
// IsAccessDeniedError indicates that this error is of AccessDeniedError type
func (e *AccessDeniedError) IsAccessDeniedError() bool {
return true
}
// OrigError returns original error (in this case this is the error itself)
func (e *AccessDeniedError) OrigError() error {
return e
}
// IsAccessDenied detects if this error is of AccessDeniedError type
func IsAccessDenied(e error) bool {
type ad interface {
IsAccessDeniedError() bool
}
_, ok := Unwrap(e).(ad)
return ok
}
// ConvertSystemError converts system error to appropriate trace error
// if it is possible, otherwise, returns original error
func ConvertSystemError(err error) error {
innerError := Unwrap(err)
if os.IsExist(innerError) {
return WrapWithMessage(&AlreadyExistsError{Message: innerError.Error()}, innerError.Error())
}
if os.IsNotExist(innerError) {
return WrapWithMessage(&NotFoundError{Message: innerError.Error()}, innerError.Error())
}
if os.IsPermission(innerError) {
return WrapWithMessage(&AccessDeniedError{Message: innerError.Error()}, innerError.Error())
}
switch realErr := innerError.(type) {
case *net.OpError:
return WrapWithMessage(&ConnectionProblemError{
Message: realErr.Error(),
Err: realErr}, realErr.Error())
case *os.PathError:
message := fmt.Sprintf("failed to execute command %v error: %v", realErr.Path, realErr.Err)
return WrapWithMessage(&AccessDeniedError{
Message: message,
}, message)
case x509.SystemRootsError, x509.UnknownAuthorityError:
return wrapWithDepth(&TrustError{Err: innerError}, 2)
}
if _, ok := innerError.(net.Error); ok {
return WrapWithMessage(&ConnectionProblemError{
Message: innerError.Error(),
Err: innerError}, innerError.Error())
}
return err
}
// ConnectionProblem returns new instance of ConnectionProblemError
func ConnectionProblem(err error, message string, args ...interface{}) error {
return WrapWithMessage(&ConnectionProblemError{
Message: fmt.Sprintf(message, args...),
Err: err,
}, message, args...)
}
// ConnectionProblemError indicates a network related problem
type ConnectionProblemError struct {
Message string `json:"message"`
Err error `json:"-"`
}
// Error is debug - friendly error message
func (c *ConnectionProblemError) Error() string {
if c.Err == nil {
return c.Message
}
return c.Err.Error()
}
// IsConnectionProblemError indicates that this error is of ConnectionProblemError type
func (c *ConnectionProblemError) IsConnectionProblemError() bool {
return true
}
// OrigError returns original error (in this case this is the error itself)
func (c *ConnectionProblemError) OrigError() error {
return c
}
// IsConnectionProblem returns whether this error is of ConnectionProblemError
func IsConnectionProblem(e error) bool {
type ad interface {
IsConnectionProblemError() bool
}
_, ok := Unwrap(e).(ad)
return ok
}
// LimitExceeded returns whether new instance of LimitExceededError
func LimitExceeded(message string, args ...interface{}) error {
return WrapWithMessage(&LimitExceededError{
Message: fmt.Sprintf(message, args...),
}, message, args...)
}
// LimitExceededError indicates rate limit or connection limit problem
type LimitExceededError struct {
Message string `json:"message"`
}
// Error is debug - friendly error message
func (c *LimitExceededError) Error() string {
return c.Message
}
// IsLimitExceededError indicates that this error is of ConnectionProblem
func (c *LimitExceededError) IsLimitExceededError() bool {
return true
}
// OrigError returns original error (in this case this is the error itself)
func (c *LimitExceededError) OrigError() error {
return c
}
// IsLimitExceeded detects if this error is of LimitExceededError
func IsLimitExceeded(e error) bool {
type ad interface {
IsLimitExceededError() bool
}
_, ok := Unwrap(e).(ad)
return ok
}
// TrustError indicates trust-related validation error (e.g. untrusted cert)
type TrustError struct {
// Err is original error
Err error `json:"error"`
Message string
}
// Error returns log-friendly error description
func (t *TrustError) Error() string {
return t.Err.Error()
}
// IsTrustError indicates that this error is of TrustError type
func (*TrustError) IsTrustError() bool {
return true
}
// OrigError returns original error (in this case this is the error itself)
func (t *TrustError) OrigError() error {
return t
}
// IsTrustError returns if this is a trust error
func IsTrustError(e error) bool {
type te interface {
IsTrustError() bool
}
_, ok := Unwrap(e).(te)
return ok
}
// OAuth2 returns new instance of OAuth2Error
func OAuth2(code, message string, query url.Values) Error {
return WrapWithMessage(&OAuth2Error{
Code: code,
Message: message,
Query: query,
}, message)
}
// OAuth2Error defined an error used in OpenID Connect Flow (OIDC)
type OAuth2Error struct {
Code string `json:"code"`
Message string `json:"message"`
Query url.Values `json:"query"`
}
//Error returns log friendly description of an error
func (o *OAuth2Error) Error() string {
return fmt.Sprintf("OAuth2 error code=%v, message=%v", o.Code, o.Message)
}
// IsOAuth2Error returns whether this error of OAuth2Error type
func (o *OAuth2Error) IsOAuth2Error() bool {
return true
}
// IsOAuth2 returns if this is a OAuth2-related error
func IsOAuth2(e error) bool {
type oe interface {
IsOAuth2Error() bool
}
_, ok := Unwrap(e).(oe)
return ok
}
// IsEOF returns true if the passed error is io.EOF
func IsEOF(e error) bool {
return Unwrap(e) == io.EOF
}
// Retry return new instance of RetryError which indicates a transient error type
func Retry(err error, message string, args ...interface{}) error {
return WrapWithMessage(&RetryError{
Message: fmt.Sprintf(message, args...),
Err: err,
}, message, args...)
}
// RetryError indicates a transient error type
type RetryError struct {
Message string `json:"message"`
Err error `json:"-"`
}
// Error is debug-friendly error message
func (c *RetryError) Error() string {
if c.Err == nil {
return c.Message
}
return c.Err.Error()
}
// IsRetryError indicates that this error is of RetryError type
func (c *RetryError) IsRetryError() bool {
return true
}
// OrigError returns original error (in this case this is the error itself)
func (c *RetryError) OrigError() error {
return c
}
// IsRetryError returns whether this error is of ConnectionProblemError
func IsRetryError(e error) bool {
type ad interface {
IsRetryError() bool
}
_, ok := Unwrap(e).(ad)
return ok
}

129
vendor/github.com/gravitational/trace/httplib.go generated vendored Normal file
View file

@ -0,0 +1,129 @@
package trace
import (
"encoding/json"
"fmt"
"net/http"
)
// WriteError sets up HTTP error response and writes it to writer w
func WriteError(w http.ResponseWriter, err error) {
if IsAggregate(err) {
for i := 0; i < maxHops; i++ {
var aggErr Aggregate
var ok bool
if aggErr, ok = Unwrap(err).(Aggregate); !ok {
break
}
errors := aggErr.Errors()
if len(errors) == 0 {
break
}
err = errors[0]
}
}
writeError(w, err)
}
// ErrorToCode returns an appropriate HTTP status code based on the provided error type
func ErrorToCode(err error) int {
if IsNotFound(err) {
return http.StatusNotFound
} else if IsBadParameter(err) || IsOAuth2(err) {
return http.StatusBadRequest
} else if IsCompareFailed(err) {
return http.StatusPreconditionFailed
} else if IsAccessDenied(err) {
return http.StatusForbidden
} else if IsAlreadyExists(err) {
return http.StatusConflict
} else if IsLimitExceeded(err) {
return http.StatusTooManyRequests
} else if IsConnectionProblem(err) {
return http.StatusGatewayTimeout
}
return http.StatusInternalServerError
}
func writeError(w http.ResponseWriter, err error) {
replyJSON(w, ErrorToCode(err), err)
}
// ReadError converts http error to internal error type
// based on HTTP response code and HTTP body contents
// if status code does not indicate error, it will return nil
func ReadError(statusCode int, re []byte) error {
var e error
switch statusCode {
case http.StatusNotFound:
e = &NotFoundError{Message: string(re)}
case http.StatusBadRequest:
e = &BadParameterError{Message: string(re)}
case http.StatusPreconditionFailed:
e = &CompareFailedError{Message: string(re)}
case http.StatusForbidden:
e = &AccessDeniedError{Message: string(re)}
case http.StatusConflict:
e = &AlreadyExistsError{Message: string(re)}
case http.StatusTooManyRequests:
e = &LimitExceededError{Message: string(re)}
case http.StatusGatewayTimeout:
e = &ConnectionProblemError{Message: string(re)}
default:
if statusCode < 200 || statusCode > 299 {
return Errorf(string(re))
}
return nil
}
return unmarshalError(e, re)
}
func replyJSON(w http.ResponseWriter, code int, err error) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
var out []byte
if IsDebug() {
// trace error can marshal itself,
// otherwise capture error message and marshal it explicitly
var obj interface{} = err
if _, ok := err.(*TraceErr); !ok {
obj = message{Message: err.Error()}
}
out, err = json.MarshalIndent(obj, "", " ")
if err != nil {
out = []byte(fmt.Sprintf(`{"message": "internal marshal error: %v"}`, err))
}
} else {
innerError := err
if terr, ok := err.(Error); ok {
innerError = terr.OrigError()
}
out, err = json.Marshal(message{Message: innerError.Error()})
}
w.Write(out)
}
type message struct {
Message string `json:"message"`
}
func unmarshalError(err error, responseBody []byte) error {
if len(responseBody) == 0 {
return err
}
var raw RawTrace
if err2 := json.Unmarshal(responseBody, &raw); err2 != nil {
return err
}
if len(raw.Traces) != 0 && len(raw.Err) != 0 {
// try to capture traces, if there are any
err2 := json.Unmarshal(raw.Err, err)
if err2 != nil {
return err
}
return &TraceErr{Traces: raw.Traces, Err: err, Message: raw.Message}
}
json.Unmarshal(responseBody, err)
return err
}

240
vendor/github.com/gravitational/trace/log.go generated vendored Normal file
View file

@ -0,0 +1,240 @@
/*
Copyright 2015 Gravitational, Inc.
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 trace implements utility functions for capturing logs
package trace
import (
"bytes"
"fmt"
"regexp"
rundebug "runtime/debug"
"sort"
"strconv"
"strings"
"time"
log "github.com/sirupsen/logrus"
"runtime"
)
const (
// FileField is a field with code file added to structured traces
FileField = "file"
// FunctionField is a field with function name
FunctionField = "func"
// LevelField returns logging level as set by logrus
LevelField = "level"
// Component is a field that represents component - e.g. service or
// function
Component = "trace.component"
// ComponentFields is a fields component
ComponentFields = "trace.fields"
// DefaultComponentPadding is a default padding for component field
DefaultComponentPadding = 11
// DefaultLevelPadding is a default padding for level field
DefaultLevelPadding = 4
)
// TextFormatter is logrus-compatible formatter and adds
// file and line details to every logged entry.
type TextFormatter struct {
// DisableTimestamp disables timestamp output (useful when outputting to
// systemd logs)
DisableTimestamp bool
// ComponentPadding is a padding to pick when displaying
// and formatting component field, defaults to DefaultComponentPadding
ComponentPadding int
}
// Format implements logrus.Formatter interface and adds file and line
func (tf *TextFormatter) Format(e *log.Entry) (data []byte, err error) {
defer func() {
if r := recover(); r != nil {
data = append([]byte("panic in log formatter\n"), rundebug.Stack()...)
return
}
}()
var file string
if frameNo := findFrame(); frameNo != -1 {
t := newTrace(frameNo, nil)
file = t.Loc()
}
w := &writer{}
// time
if !tf.DisableTimestamp {
w.writeField(e.Time.Format(time.RFC3339))
}
// level
w.writeField(strings.ToUpper(padMax(e.Level.String(), DefaultLevelPadding)))
// component, always output
componentI, ok := e.Data[Component]
if !ok {
componentI = ""
}
component, ok := componentI.(string)
if !ok {
component = fmt.Sprintf("%v", componentI)
}
padding := DefaultComponentPadding
if tf.ComponentPadding != 0 {
padding = tf.ComponentPadding
}
if w.Len() > 0 {
w.WriteByte(' ')
}
if component != "" {
component = fmt.Sprintf("[%v]", component)
}
component = strings.ToUpper(padMax(component, padding))
if component[len(component)-1] != ' ' {
component = component[:len(component)-1] + "]"
}
w.WriteString(component)
// message
if e.Message != "" {
w.writeField(e.Message)
}
// rest of the fields
if len(e.Data) > 0 {
w.writeMap(e.Data)
}
// file, if present, always last
if file != "" {
w.writeField(file)
}
w.WriteByte('\n')
data = w.Bytes()
return
}
// JSONFormatter implements logrus.Formatter interface and adds file and line
// properties to JSON entries
type JSONFormatter struct {
log.JSONFormatter
}
// Format implements logrus.Formatter interface
func (j *JSONFormatter) Format(e *log.Entry) ([]byte, error) {
if frameNo := findFrame(); frameNo != -1 {
t := newTrace(frameNo, nil)
new := e.WithFields(log.Fields{
FileField: t.Loc(),
FunctionField: t.FuncName(),
})
new.Time = e.Time
new.Level = e.Level
new.Message = e.Message
e = new
}
return (&j.JSONFormatter).Format(e)
}
var r = regexp.MustCompile(`github\.com/(S|s)irupsen/logrus`)
func findFrame() int {
for i := 3; i < 10; i++ {
_, file, _, ok := runtime.Caller(i)
if !ok {
return -1
}
if !r.MatchString(file) {
return i
}
}
return -1
}
type writer struct {
bytes.Buffer
}
func (w *writer) writeField(value interface{}) {
if w.Len() > 0 {
w.WriteByte(' ')
}
w.writeValue(value)
}
func (w *writer) writeValue(value interface{}) {
stringVal, ok := value.(string)
if !ok {
stringVal = fmt.Sprint(value)
}
if !needsQuoting(stringVal) {
w.WriteString(stringVal)
} else {
w.WriteString(fmt.Sprintf("%q", stringVal))
}
}
func (w *writer) writeKeyValue(key string, value interface{}) {
if w.Len() > 0 {
w.WriteByte(' ')
}
w.WriteString(key)
w.WriteByte(':')
w.writeValue(value)
}
func (w *writer) writeMap(m map[string]interface{}) {
if len(m) == 0 {
return
}
keys := make([]string, 0, len(m))
for key := range m {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
if key == Component {
continue
}
switch val := m[key].(type) {
case log.Fields:
w.writeMap(val)
default:
w.writeKeyValue(key, val)
}
}
}
func needsQuoting(text string) bool {
for _, r := range text {
if !strconv.IsPrint(r) {
return true
}
}
return false
}
func padMax(in string, chars int) string {
switch {
case len(in) < chars:
return in + strings.Repeat(" ", chars-len(in))
default:
return in[:chars]
}
}

381
vendor/github.com/gravitational/trace/trace.go generated vendored Normal file
View file

@ -0,0 +1,381 @@
/*
Copyright 2015 Gravitational, Inc.
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 trace implements utility functions for capturing debugging
// information about file and line in error reports and logs.
package trace
import (
"encoding/json"
"fmt"
"path/filepath"
"runtime"
"strings"
"sync/atomic"
"golang.org/x/net/context"
)
var debug int32
// SetDebug turns on/off debugging mode, that causes Fatalf to panic
func SetDebug(enabled bool) {
if enabled {
atomic.StoreInt32(&debug, 1)
} else {
atomic.StoreInt32(&debug, 0)
}
}
// IsDebug returns true if debug mode is on, false otherwize
func IsDebug() bool {
return atomic.LoadInt32(&debug) == 1
}
// Wrap takes the original error and wraps it into the Trace struct
// memorizing the context of the error.
func Wrap(err error, args ...interface{}) Error {
if len(args) > 0 {
format := args[0]
args = args[1:]
return WrapWithMessage(err, format, args...)
}
return wrapWithDepth(err, 2)
}
// Unwrap unwraps error to it's original error
func Unwrap(err error) error {
if terr, ok := err.(Error); ok {
return terr.OrigError()
}
return err
}
// UserMessage returns user-friendly part of the error
func UserMessage(err error) string {
if err == nil {
return ""
}
if wrap, ok := err.(Error); ok {
return wrap.UserMessage()
}
return err.Error()
}
// DebugReport returns debug report with all known information
// about the error including stack trace if it was captured
func DebugReport(err error) string {
if err == nil {
return ""
}
if wrap, ok := err.(Error); ok {
return wrap.DebugReport()
}
return err.Error()
}
// WrapWithMessage wraps the original error into Error and adds user message if any
func WrapWithMessage(err error, message interface{}, args ...interface{}) Error {
trace := wrapWithDepth(err, 3)
if trace != nil {
trace.AddUserMessage(message, args...)
}
return trace
}
func wrapWithDepth(err error, depth int) Error {
if err == nil {
return nil
}
var trace Error
if wrapped, ok := err.(Error); ok {
trace = wrapped
} else {
trace = newTrace(depth+1, err)
}
return trace
}
// Errorf is similar to fmt.Errorf except that it captures
// more information about the origin of error, such as
// callee, line number and function that simplifies debugging
func Errorf(format string, args ...interface{}) (err error) {
err = fmt.Errorf(format, args...)
trace := wrapWithDepth(err, 2)
trace.AddUserMessage(format, args...)
return trace
}
// Fatalf - If debug is false Fatalf calls Errorf. If debug is
// true Fatalf calls panic
func Fatalf(format string, args ...interface{}) error {
if IsDebug() {
panic(fmt.Sprintf(format, args))
} else {
return Errorf(format, args)
}
}
func newTrace(depth int, err error) *TraceErr {
var pc [32]uintptr
count := runtime.Callers(depth+1, pc[:])
traces := make(Traces, count)
for i := 0; i < count; i++ {
fn := runtime.FuncForPC(pc[i])
filePath, line := fn.FileLine(pc[i])
traces[i] = Trace{
Func: fn.Name(),
Path: filePath,
Line: line,
}
}
return &TraceErr{
err,
traces,
"",
}
}
// Traces is a list of trace entries
type Traces []Trace
// SetTraces adds new traces to the list
func (s Traces) SetTraces(traces ...Trace) {
s = append(s, traces...)
}
// Func returns first function in trace list
func (s Traces) Func() string {
if len(s) == 0 {
return ""
}
return s[0].Func
}
// Func returns just function name
func (s Traces) FuncName() string {
if len(s) == 0 {
return ""
}
fn := filepath.ToSlash(s[0].Func)
idx := strings.LastIndex(fn, "/")
if idx == -1 || idx == len(fn)-1 {
return fn
}
return fn[idx+1:]
}
// Loc points to file/line location in the code
func (s Traces) Loc() string {
if len(s) == 0 {
return ""
}
return s[0].String()
}
// String returns debug-friendly representaton of trace stack
func (s Traces) String() string {
if len(s) == 0 {
return ""
}
out := make([]string, len(s))
for i, t := range s {
out[i] = fmt.Sprintf("\t%v:%v %v", t.Path, t.Line, t.Func)
}
return strings.Join(out, "\n")
}
// Trace stores structured trace entry, including file line and path
type Trace struct {
// Path is a full file path
Path string `json:"path"`
// Func is a function name
Func string `json:"func"`
// Line is a code line number
Line int `json:"line"`
}
// String returns debug-friendly representation of this trace
func (t *Trace) String() string {
dir, file := filepath.Split(t.Path)
dirs := strings.Split(filepath.ToSlash(filepath.Clean(dir)), "/")
if len(dirs) != 0 {
file = filepath.Join(dirs[len(dirs)-1], file)
}
return fmt.Sprintf("%v:%v", file, t.Line)
}
// TraceErr contains error message and some additional
// information about the error origin
type TraceErr struct {
Err error `json:"error"`
Traces `json:"traces"`
Message string `json:"message,omitemtpy"`
}
type RawTrace struct {
Err json.RawMessage `json:"error"`
Traces `json:"traces"`
Message string `json:"message"`
}
// AddUserMessage adds user-friendly message describing the error nature
func (e *TraceErr) AddUserMessage(formatArg interface{}, rest ...interface{}) {
newMessage := fmt.Sprintf(fmt.Sprintf("%v", formatArg), rest...)
if len(e.Message) == 0 {
e.Message = newMessage
} else {
e.Message = strings.Join([]string{e.Message, newMessage}, ", ")
}
}
// UserMessage returns user-friendly error message
func (e *TraceErr) UserMessage() string {
if e.Message != "" {
return e.Message
}
return e.Err.Error()
}
// DebugReport returns develeoper-friendly error report
func (e *TraceErr) DebugReport() string {
return fmt.Sprintf("\nERROR REPORT:\nOriginal Error: %T %v\nStack Trace:\n%v\nUser Message: %v\n", e.Err, e.Err.Error(), e.Traces.String(), e.Message)
}
// Error returns user-friendly error message when not in debug mode
func (e *TraceErr) Error() string {
if IsDebug() {
return e.DebugReport()
}
return e.UserMessage()
}
// OrigError returns original wrapped error
func (e *TraceErr) OrigError() error {
err := e.Err
// this is not an endless loop because I'm being
// paranoid, this is a safe protection against endless
// loops
for i := 0; i < maxHops; i++ {
newerr, ok := err.(Error)
if !ok {
break
}
if newerr.OrigError() != err {
err = newerr.OrigError()
}
}
return err
}
// maxHops is a max supported nested depth for errors
const maxHops = 50
// Error is an interface that helps to adapt usage of trace in the code
// When applications define new error types, they can implement the interface
// So error handlers can use OrigError() to retrieve error from the wrapper
type Error interface {
error
// OrigError returns original error wrapped in this error
OrigError() error
// AddMessage adds formatted user-facing message
// to the error, depends on the implementation,
// usually works as fmt.Sprintf(formatArg, rest...)
// but implementations can choose another way, e.g. treat
// arguments as structured args
AddUserMessage(formatArg interface{}, rest ...interface{})
// UserMessage returns user-friendly error message
UserMessage() string
// DebugReport returns develeoper-friendly error report
DebugReport() string
}
// NewAggregate creates a new aggregate instance from the specified
// list of errors
func NewAggregate(errs ...error) error {
// filter out possible nil values
var nonNils []error
for _, err := range errs {
if err != nil {
nonNils = append(nonNils, err)
}
}
if len(nonNils) == 0 {
return nil
}
return wrapWithDepth(aggregate(nonNils), 2)
}
// NewAggregateFromChannel creates a new aggregate instance from the provided
// errors channel.
//
// A context.Context can be passed in so the caller has the ability to cancel
// the operation. If this is not desired, simply pass context.Background().
func NewAggregateFromChannel(errCh chan error, ctx context.Context) error {
var errs []error
Loop:
for {
select {
case err, ok := <-errCh:
if !ok { // the channel is closed, time to exit
break Loop
}
errs = append(errs, err)
case <-ctx.Done():
break Loop
}
}
return NewAggregate(errs...)
}
// Aggregate interface combines several errors into one error
type Aggregate interface {
error
// Errors obtains the list of errors this aggregate combines
Errors() []error
}
// aggregate implements Aggregate
type aggregate []error
// Error implements the error interface
func (r aggregate) Error() string {
if len(r) == 0 {
return ""
}
output := r[0].Error()
for i := 1; i < len(r); i++ {
output = fmt.Sprintf("%v, %v", output, r[i])
}
return output
}
// Errors obtains the list of errors this aggregate combines
func (r aggregate) Errors() []error {
return []error(r)
}
// IsAggregate returns whether this error of Aggregate error type
func IsAggregate(err error) bool {
_, ok := Unwrap(err).(Aggregate)
return ok
}

112
vendor/github.com/gravitational/trace/udphook.go generated vendored Normal file
View file

@ -0,0 +1,112 @@
package trace
import (
"encoding/json"
"net"
"time"
"github.com/jonboulle/clockwork"
log "github.com/sirupsen/logrus"
)
const (
// UDPDefaultAddr is a default address to emit logs to
UDPDefaultAddr = "127.0.0.1:5000"
// UDPDefaultNet is a default network
UDPDefaultNet = "udp"
)
// UDPOptionSetter represents functional arguments passed to ELKHook
type UDPOptionSetter func(f *UDPHook)
// NewUDPHook returns logrus-compatible hook that sends data to UDP socket
func NewUDPHook(opts ...UDPOptionSetter) (*UDPHook, error) {
f := &UDPHook{}
for _, o := range opts {
o(f)
}
if f.Clock == nil {
f.Clock = clockwork.NewRealClock()
}
if f.clientNet == "" {
f.clientNet = UDPDefaultNet
}
if f.clientAddr == "" {
f.clientAddr = UDPDefaultAddr
}
addr, err := net.ResolveUDPAddr(f.clientNet, f.clientAddr)
if err != nil {
return nil, Wrap(err)
}
conn, err := net.ListenPacket("udp", ":0")
if err != nil {
return nil, Wrap(err)
}
f.addr = addr
f.conn = conn.(*net.UDPConn)
return f, nil
}
type UDPHook struct {
Clock clockwork.Clock
clientNet string
clientAddr string
addr *net.UDPAddr
conn *net.UDPConn
}
type Frame struct {
Time time.Time `json:"time"`
Type string `json:"type"`
Entry map[string]interface{} `json:"entry"`
Message string `json:"message"`
Level string `json:"level"`
}
// Fire fires the event to the ELK beat
func (elk *UDPHook) Fire(e *log.Entry) error {
// Make a copy to safely modify
entry := e.WithFields(nil)
if frameNo := findFrame(); frameNo != -1 {
t := newTrace(frameNo-1, nil)
entry.Data[FileField] = t.String()
entry.Data[FunctionField] = t.Func()
}
data, err := json.Marshal(Frame{
Time: elk.Clock.Now().UTC(),
Type: "trace",
Entry: entry.Data,
Message: entry.Message,
Level: entry.Level.String(),
})
if err != nil {
return Wrap(err)
}
conn, err := net.ListenPacket("udp", ":0")
if err != nil {
return Wrap(err)
}
defer conn.Close()
resolvedAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:5000")
if err != nil {
return Wrap(err)
}
_, err = (conn.(*net.UDPConn)).WriteToUDP(data, resolvedAddr)
return Wrap(err)
}
// Levels returns logging levels supported by logrus
func (elk *UDPHook) Levels() []log.Level {
return []log.Level{
log.PanicLevel,
log.FatalLevel,
log.ErrorLevel,
log.WarnLevel,
log.InfoLevel,
log.DebugLevel,
}
}