Initial commit
This commit is contained in:
12
vendor/github.com/cockroachdb/errors/.gitignore
generated
vendored
Normal file
12
vendor/github.com/cockroachdb/errors/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
201
vendor/github.com/cockroachdb/errors/LICENSE
generated
vendored
Normal file
201
vendor/github.com/cockroachdb/errors/LICENSE
generated
vendored
Normal 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 [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
62
vendor/github.com/cockroachdb/errors/Makefile.update-protos
generated
vendored
Normal file
62
vendor/github.com/cockroachdb/errors/Makefile.update-protos
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
# This makefile can be used to-regenerate the protobuf files.
|
||||
#
|
||||
# Prerequisites:
|
||||
# "protoc" from https://github.com/protocolbuffers/protobuf
|
||||
# go get github.com/cockroachdb/protoc-gen-gogoroach
|
||||
# go get github.com/gogo/protobuf/types
|
||||
# go get github.com/gogo/protobuf/protoc-gen-gogo
|
||||
#
|
||||
# Note: as of 2021-04-13, we like to use a custom protoc-gen-gogo
|
||||
# with additional options, to stabilize the marshalled
|
||||
# encoding of objects (so that they are deterministic
|
||||
# across marshal/unmarshal cycles) and reduce the memory footprint
|
||||
# of objects:
|
||||
#
|
||||
# vanity.TurnOnStable_MarshalerAll,
|
||||
# vanity.TurnOffGoUnrecognizedAll,
|
||||
# vanity.TurnOffGoUnkeyedAll,
|
||||
# vanity.TurnOffGoSizecacheAll,
|
||||
#
|
||||
# Until this is resolved, the "go get" commands above are not
|
||||
# adequate; instead:
|
||||
#
|
||||
# 1. set the PATH env var to point to CockroachDB's `bin`
|
||||
# sub-directory (after a successful CockroachDB build), where a
|
||||
# suitable version of protoc-gen-gogoroach is provided.
|
||||
#
|
||||
# 2. run `make -f Makefile.update-protos` with this PATH active.
|
||||
|
||||
export SHELL := env PWD=$(CURDIR) bash
|
||||
|
||||
PROTOS := $(wildcard \
|
||||
errbase/internal/*.proto \
|
||||
errorspb/*.proto \
|
||||
extgrpc/*.proto \
|
||||
exthttp/*.proto \
|
||||
grpc/*.proto \
|
||||
markers/internal/*.proto \
|
||||
)
|
||||
GO_SOURCES = $(PROTOS:.proto=.pb.go)
|
||||
|
||||
SED = sed
|
||||
SED_INPLACE := $(shell $(SED) --version 2>&1 | grep -q GNU && echo -i || echo "-i ''")
|
||||
|
||||
all: $(PROTOS)
|
||||
set -e; for dir in $(sort $(dir $(PROTOS))); do \
|
||||
protoc \
|
||||
-I. \
|
||||
-I$$GOPATH/src/ \
|
||||
-I$$GOPATH/src/github.com \
|
||||
-I$$GOPATH/src/github.com/cockroachdb/errors \
|
||||
-I$$GOPATH/src/github.com/gogo/protobuf \
|
||||
-I$$GOPATH/src/github.com/gogo/protobuf/protobuf \
|
||||
--gogoroach_out=Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types,plugins=grpc,import_prefix=:. \
|
||||
$$dir/*.proto; \
|
||||
done
|
||||
$(SED) $(SED_INPLACE) -E \
|
||||
-e '/import _ /d' \
|
||||
-e 's!import (fmt|math) "github.com/(fmt|math)"! !g' \
|
||||
-e 's!github.com/((bytes|encoding/binary|errors|fmt|io|math|github\.com|(google\.)?golang\.org)([^a-z]|$$))!\1!g' \
|
||||
-e 's!golang.org/x/net/context!context!g' \
|
||||
$(GO_SOURCES)
|
||||
gofmt -s -w $(GO_SOURCES)
|
||||
646
vendor/github.com/cockroachdb/errors/README.md
generated
vendored
Normal file
646
vendor/github.com/cockroachdb/errors/README.md
generated
vendored
Normal file
@@ -0,0 +1,646 @@
|
||||
# cockroachdb/errors: Go errors with network portability
|
||||
|
||||
This library aims to be used as a drop-in replacement to
|
||||
`github.com/pkg/errors` and Go's standard `errors` package. It also
|
||||
provides *network portability* of error objects, in ways suitable for
|
||||
distributed systems with mixed-version software compatibility.
|
||||
|
||||
It also provides native and comprehensive support for [PII](https://en.wikipedia.org/wiki/Personal_data)-free details
|
||||
and an opt-in [Sentry.io](https://sentry.io/) reporting mechanism that
|
||||
automatically formats error details and strips them of PII.
|
||||
|
||||
See also [the design RFC](https://github.com/cockroachdb/cockroach/blob/master/docs/RFCS/20190318_error_handling.md).
|
||||
|
||||

|
||||
[](https://pkg.go.dev/github.com/cockroachdb/errors)
|
||||
|
||||
Table of contents:
|
||||
|
||||
- [Features](#Features)
|
||||
- [How to use](#How-to-use)
|
||||
- [What comes out of an error?](#What-comes-out-of-an-error)
|
||||
- [Available error leaves](#Available-error-leaves)
|
||||
- [Available wrapper constructors](#Available-wrapper-constructors)
|
||||
- [Providing PII-free details](#Providing-PII-free-details)
|
||||
- [Building your own error types](#Building-your-own-error-types)
|
||||
- [Error composition (summary)](#Error-composition-summary)
|
||||
- [API (not constructing error objects)](#API-not-constructing-error-objects)
|
||||
|
||||
## Features
|
||||
|
||||
| Feature | Go's <1.13 `errors` | `github.com/pkg/errors` | Go 1.13 `errors`/`xerrors` | `cockroachdb/errors` |
|
||||
|-------------------------------------------------------------------------------------------------------|---------------------|-------------------------|----------------------------|----------------------|
|
||||
| error constructors (`New`, `Errorf` etc) | ✔ | ✔ | ✔ | ✔ |
|
||||
| error causes (`Cause` / `Unwrap`) | | ✔ | ✔ | ✔ |
|
||||
| cause barriers (`Opaque` / `Handled`) | | | ✔ | ✔ |
|
||||
| `errors.As()`, `errors.Is()` | | | ✔ | ✔ |
|
||||
| automatic error wrap when format ends with `: %w` | | | ✔ | ✔ |
|
||||
| standard wrappers with efficient stack trace capture | | ✔ | | ✔ |
|
||||
| **transparent protobuf encode/decode with forward compatibility** | | | | ✔ |
|
||||
| **`errors.Is()` recognizes errors across the network** | | | | ✔ |
|
||||
| **comprehensive support for PII-free reportable strings** | | | | ✔ |
|
||||
| support for both `Cause()` and `Unwrap()` [go#31778](https://github.com/golang/go/issues/31778) | | | | ✔ |
|
||||
| standard error reports to Sentry.io | | | | ✔ |
|
||||
| wrappers to denote assertion failures | | | | ✔ |
|
||||
| wrappers with issue tracker references | | | | ✔ |
|
||||
| wrappers for user-facing hints and details | | | | ✔ |
|
||||
| wrappers to attach secondary causes | | | | ✔ |
|
||||
| wrappers to attach [`logtags`](https://github.com/cockroachdb/logtags) details from `context.Context` | | | | ✔ |
|
||||
| `errors.FormatError()`, `Formatter`, `Printer` | | | (under construction) | ✔ |
|
||||
| `errors.SafeFormatError()`, `SafeFormatter` | | | | ✔ |
|
||||
| wrapper-aware `IsPermission()`, `IsTimeout()`, `IsExist()`, `IsNotExist()` | | | | ✔ |
|
||||
|
||||
"Forward compatibility" above refers to the ability of this library to
|
||||
recognize and properly handle network communication of error types it
|
||||
does not know about, for example when a more recent version of a
|
||||
software package sends a new error object to another system running an
|
||||
older version of the package.
|
||||
|
||||
## How to use
|
||||
|
||||
- construct errors with `errors.New()`, etc as usual, but also see the other [error leaf constructors](#Available-error-leaves) below.
|
||||
- wrap errors with `errors.Wrap()` as usual, but also see the [other wrappers](#Available-wrapper-constructors) below.
|
||||
- test error identity with `errors.Is()` as usual.
|
||||
**Unique in this library**: this works even if the error has traversed the network!
|
||||
Also, `errors.IsAny()` to recognize two or more reference errors.
|
||||
- replace uses of `os.IsPermission()`, `os.IsTimeout()`, `os.IsExist()` and `os.IsNotExist()` by their analog in sub-package `oserror` so
|
||||
that they can peek through layers of wrapping.
|
||||
- access error causes with `errors.UnwrapOnce()` / `errors.UnwrapAll()` (note: `errors.Cause()` and `errors.Unwrap()` also provided for compatibility with other error packages).
|
||||
- encode/decode errors to protobuf with `errors.EncodeError()` / `errors.DecodeError()`.
|
||||
- extract **PII-free safe details** with `errors.GetSafeDetails()`.
|
||||
- extract human-facing hints and details with `errors.GetAllHints()`/`errors.GetAllDetails()` or `errors.FlattenHints()`/`errors.FlattenDetails()`.
|
||||
- produce detailed Sentry.io reports with `errors.BuildSentryReport()` / `errors.ReportError()`.
|
||||
- implement your own error leaf types and wrapper types:
|
||||
- implement the `error` and `errors.Wrapper` interfaces as usual.
|
||||
- register encode/decode functions: call `errors.Register{Leaf,Wrapper}{Encoder,Decoder}()` in a `init()` function in your package.
|
||||
- implement `Format()` that redirects to `errors.FormatError()`.
|
||||
- see the section [Building your own error types](#Building-your-own-error-types) below.
|
||||
|
||||
## What comes out of an error?
|
||||
|
||||
| Error detail | `Error()` and format `%s`/`%q`/`%v` | format `%+v` | `GetSafeDetails()` | Sentry report via `ReportError()` |
|
||||
|-----------------------------------------------------------------|-------------------------------------|--------------|-------------------------------|-----------------------------------|
|
||||
| main message, eg `New()` | visible | visible | yes (CHANGED IN v1.6) | full (CHANGED IN v1.6) |
|
||||
| wrap prefix, eg `WithMessage()` | visible (as prefix) | visible | yes (CHANGED IN v1.6) | full (CHANGED IN v1.6) |
|
||||
| stack trace, eg `WithStack()` | not visible | simplified | yes | full |
|
||||
| hint , eg `WithHint()` | not visible | visible | no | type only |
|
||||
| detail, eg `WithDetail()` | not visible | visible | no | type only |
|
||||
| assertion failure annotation, eg `WithAssertionFailure()` | not visible | visible | no | type only |
|
||||
| issue links, eg `WithIssueLink()`, `UnimplementedError()` | not visible | visible | yes | full |
|
||||
| safe details, eg `WithSafeDetails()` | not visible | visible | yes | full |
|
||||
| telemetry keys, eg. `WithTelemetryKey()` | not visible | visible | yes | full |
|
||||
| secondary errors, eg. `WithSecondaryError()`, `CombineErrors()` | not visible | visible | redacted, recursively | redacted, recursively |
|
||||
| barrier origins, eg. `Handled()` | not visible | visible | redacted, recursively | redacted, recursively |
|
||||
| error domain, eg. `WithDomain()` | not visible | visible | yes | full |
|
||||
| context tags, eg. `WithContextTags()` | not visible | visible | keys visible, values redacted | keys visible, values redacted |
|
||||
|
||||
## Available error leaves
|
||||
|
||||
An error *leaf* is an object that implements the `error` interface,
|
||||
but does not refer to another error via a `Unwrap()` or `Cause()`
|
||||
method.
|
||||
|
||||
- `New(string) error`, `Newf(string, ...interface{}) error`, `Errorf(string, ...interface{}) error`: leaf errors with message
|
||||
- **when to use: common error cases.**
|
||||
- what it does: also captures the stack trace at point of call and redacts the provided message for safe reporting.
|
||||
- how to access the detail: `Error()`, regular Go formatting. **Details in Sentry report.**
|
||||
- see also: Section [Error composition](#Error-composition-summary) below. `errors.NewWithDepth()` variants to customize at which call depth the stack trace is captured.
|
||||
|
||||
- `AssertionFailedf(string, ...interface{}) error`, `NewAssertionFailureWithWrappedErrf(error, string, ...interface{}) error`: signals an assertion failure / programming error.
|
||||
- **when to use: when an invariant is violated; when an unreachable code path is reached.**
|
||||
- what it does: also captures the stack trace at point of call, redacts the provided strings for safe reporting, prepares a hint to inform a human user.
|
||||
- how to access the detail: `IsAssertionFailure()`/`HasAssertionFailure()`, format with `%+v`, Safe details included in Sentry reports.
|
||||
- see also: Section [Error composition](#Error-composition-summary) below. `errors.AssertionFailedWithDepthf()` variant to customize at which call depth the stack trace is captured.
|
||||
|
||||
- `Handled(error) error`, `Opaque(error) error`, `HandledWithMessage(error, string) error`: captures an error cause but make it invisible to `Unwrap()` / `Is()`.
|
||||
- **when to use: when a new error occurs while handling an error, and the original error must be "hidden".**
|
||||
- what it does: captures the cause in a hidden field. The error message is preserved unless the `...WithMessage()` variant is used.
|
||||
- how to access the detail: format with `%+v`, redacted details reported in Sentry reports.
|
||||
|
||||
- `UnimplementedError(IssueLink, string) error`: captures a message string and a URL reference to an external resource to denote a feature that was not yet implemented.
|
||||
- **when to use: to inform (human) users that some feature is not implemented yet and refer them to some external resource.**
|
||||
- what it does: captures the message, URL and detail in a wrapper. The URL and detail are considered safe for reporting.
|
||||
- how to access the detail: `errors.GetAllHints()`, `errors.FlattenHints()`, format with `%+v`, URL and detail included in Sentry report (not the message).
|
||||
- see also: `errors.WithIssueLink()` below for errors that are not specifically about unimplemented features.
|
||||
|
||||
## Available wrapper constructors
|
||||
|
||||
An error *wrapper* is an object that implements the `error` interface,
|
||||
and also refers to another error via an `Unwrap()` (preferred) and/or
|
||||
`Cause()` method.
|
||||
|
||||
All wrapper constructors can be applied safely to a `nil` `error`:
|
||||
they behave as no-ops in this case:
|
||||
|
||||
```go
|
||||
// The following:
|
||||
// if err := foo(); err != nil {
|
||||
// return errors.Wrap(err, "foo")
|
||||
// }
|
||||
// return nil
|
||||
//
|
||||
// is not needed. Instead, you can use this:
|
||||
return errors.Wrap(foo(), "foo")
|
||||
```
|
||||
|
||||
- `Wrap(error, string) error`, `Wrapf(error, string, ...interface{}) error`:
|
||||
- **when to use: on error return paths.**
|
||||
- what it does: combines `WithMessage()`, `WithStack()`, `WithSafeDetails()`.
|
||||
- how to access the details: `Error()`, regular Go formatting. **Details in Sentry report.**
|
||||
- see also: Section [Error composition](#Error-composition-summary) below. `WrapWithDepth()` variants to customize at which depth the stack trace is captured.
|
||||
|
||||
- `WithSecondaryError(error, error) error`: annotate an error with a secondary error.
|
||||
- **when to use: when an additional error occurs in the code that is handling a primary error.** Consider using `errors.CombineErrors()` instead (see below).
|
||||
- what it does: it captures the secondary error but hides it from `errors.Is()`.
|
||||
- how to access the detail: format with `%+v`, redacted recursively in Sentry reports.
|
||||
- see also: `errors.CombineErrors()`
|
||||
|
||||
- `CombineErrors(error, error) error`: combines two errors into one.
|
||||
- **when to use: when two operations occur concurrently and either can return an error, and only one final error must be returned.**
|
||||
- what it does: returns either of its arguments if the other is `nil`, otherwise calls `WithSecondaryError()`.
|
||||
- how to access the detail: see `WithSecondaryError()` above.
|
||||
|
||||
- `Mark(error, error) error`: gives the identity of one error to another error.
|
||||
- **when to use: when a caller expects to recognize a sentinel error with `errors.Is()` but the callee provides a diversity of error messages.**
|
||||
- what it does: it overrides the "error mark" used internally by `errors.Is()`.
|
||||
- how to access the detail: format with `%+v`, Sentry reports.
|
||||
|
||||
- `WithStack(error) error`: annotate with stack trace
|
||||
- **when to use:** usually not needed, use `errors.Wrap()`/`errors.Wrapf()` instead.
|
||||
|
||||
**Special cases:**
|
||||
|
||||
- when returning a sentinel, for example:
|
||||
|
||||
```go
|
||||
var myErr = errors.New("foo")
|
||||
|
||||
func myFunc() error {
|
||||
if ... {
|
||||
return errors.WithStack(myErr)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- on error return paths, when not trivial but also not warranting a wrap. For example:
|
||||
|
||||
```go
|
||||
err := foo()
|
||||
if err != nil {
|
||||
doSomething()
|
||||
if !somecond {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- what it does: captures (efficiently) a stack trace.
|
||||
- how to access the details: format with `%+v`, `errors.GetSafeDetails()`, Sentry reports. The stack trace is considered safe for reporting.
|
||||
- see also: `WithStackDepth()` to customize the call depth at which the stack trace is captured.
|
||||
|
||||
- `WithSafeDetails(error, string, ...interface{}) error`: safe details for reporting.
|
||||
- when to use: probably never. Use `errors.Wrap()`/`errors.Wrapf()` instead.
|
||||
- what it does: saves some strings for safe reporting.
|
||||
- how to access the detail: format with `%+v`, `errors.GetSafeDetails()`, Sentry report.
|
||||
|
||||
- `WithMessage(error, string) error`, `WithMessagef(error, string, ...interface{}) error`: message prefix.
|
||||
- when to use: probably never. Use `errors.Wrap()`/`errors.Wrapf()` instead.
|
||||
- what it does: adds a message prefix.
|
||||
- how to access the detail: `Error()`, regular Go formatting, Sentry Report.
|
||||
|
||||
- `WithDetail(error, string) error`, `WithDetailf(error, string, ...interface{}) error`, user-facing detail with contextual information.
|
||||
- **when to use: need to embark a message string to output when the error is presented to a developer.**
|
||||
- what it does: captures detail strings.
|
||||
- how to access the detail: `errors.GetAllDetails()`, `errors.FlattenDetails()` (all details are preserved), format with `%+v`. Not included in Sentry reports.
|
||||
|
||||
- `WithHint(error, string) error`, `WithHintf(error, string, ...interface{}) error`: user-facing detail with suggestion for action to take.
|
||||
- **when to use: need to embark a message string to output when the error is presented to an end user.**
|
||||
- what it does: captures hint strings.
|
||||
- how to access the detail: `errors.GetAllHints()`, `errors.FlattenHints()` (hints are de-duplicated), format with `%+v`. Not included in Sentry reports.
|
||||
|
||||
- `WithIssueLink(error, IssueLink) error`: annotate an error with an URL and arbitrary string.
|
||||
- **when to use: to refer (human) users to some external resources.**
|
||||
- what it does: captures the URL and detail in a wrapper. Both are considered safe for reporting.
|
||||
- how to access the detail: `errors.GetAllHints()`, `errors.FlattenHints()`, `errors.GetSafeDetails()`, format with `%+v`, Sentry report.
|
||||
- see also: `errors.UnimplementedError()` to construct leaves (see previous section).
|
||||
|
||||
- `WithTelemetry(error, string) error`: annotate an error with a key suitable for telemetry.
|
||||
- **when to use: to gather strings during error handling, for capture in the telemetry sub-system of a server package.**
|
||||
- what it does: captures the string. The telemetry key is considered safe for reporting.
|
||||
- how to access the detail: `errors.GetTelemetryKeys()`, `errors.GetSafeDetails()`, format with `%+v`, Sentry report.
|
||||
|
||||
- `WithDomain(error, Domain) error`, `HandledInDomain(error, Domain) error`, `HandledInDomainWithMessage(error, Domain, string) error` **(experimental)**: annotate an error with an origin package.
|
||||
- **when to use: at package boundaries.**
|
||||
- what it does: captures the identity of the error domain. Can be asserted with `errors.EnsureNotInDomain()`, `errors.NotInDomain()`.
|
||||
- how to access the detail: format with `%+v`, Sentry report.
|
||||
|
||||
- `WithAssertionFailure(error) error`: annotate an error as being an assertion failure.
|
||||
- when to use: probably never. Use `errors.AssertionFailedf()` and variants.
|
||||
- what it does: wraps the error with a special type. Triggers an auto-generated hint.
|
||||
- how to access the detail: `IsAssertionFailure()`/`HasAssertionFailure()`, `errors.GetAllHints()`, `errors.FlattenHints()`, format with `%+v`, Sentry report.
|
||||
|
||||
- `WithContextTags(error, context.Context) error`: annotate an error with the k/v pairs attached to a `context.Context` instance with the [`logtags`](https://github.com/cockroachdb/logtags) package.
|
||||
- **when to use: when capturing/producing an error and a `context.Context` is available.**
|
||||
- what it does: it captures the `logtags.Buffer` object in the wrapper.
|
||||
- how to access the detail: `errors.GetContextTags()`, format with `%+v`, Sentry reports.
|
||||
|
||||
## Providing PII-free details
|
||||
|
||||
The library support PII-free strings essentially as follows:
|
||||
|
||||
- by default, many strings included in an error object are considered
|
||||
to be PII-unsafe, and are stripped out when building a Sentry
|
||||
report.
|
||||
- some fields in the library are assumed to be PII-safe by default.
|
||||
- you can opt additional strings in to Sentry reports.
|
||||
|
||||
The following strings from this library are considered to be PII-free,
|
||||
and thus included in Sentry reports automatically:
|
||||
|
||||
- the *type* of error objects,
|
||||
- stack traces (containing only file paths, line numbers, function names - arguments are not included),
|
||||
- issue tracker links (including URL and detail field),
|
||||
- telemetry keys,
|
||||
- error domains,
|
||||
- context tag keys,
|
||||
- the `format string` argument of `Newf`, `AssertionFailedf`, etc (the constructors ending with `...f()`),
|
||||
- the *type* of the additional arguments passed to the `...f()` constructors,
|
||||
- the *value of specific argument types* passed to the `...f()` constructors, when known to be PII-safe.
|
||||
For details of which arguments are considered PII-free, see the [`redact` package](https://github.com/cockroachdb/redact).
|
||||
|
||||
It is possible to opt additional in to Sentry reporting, using either of the following methods:
|
||||
|
||||
- implement the `errors.SafeDetailer` interface, providing the
|
||||
`SafeDetails() []string` method on your error type.
|
||||
|
||||
- enclose additional arguments passed to the `...f()` constructors with `errors.Safe()`. For example:
|
||||
`err := errors.Newf("my code: %d", errors.Safe(123))`
|
||||
— in this example, the value 123 will be included when a Sentry report is constructed.
|
||||
- it also makes it available via `errors.GetSafeDetails()`/`GetAllSafeDetails()`.
|
||||
- the value 123 is also part of the main error message returned by `Error()`.
|
||||
|
||||
- attach additional arbitrary strings with `errors.WithSafeDetails(error, string, ...interface{}) error` and
|
||||
also use `errors.Safe()`.
|
||||
For example: `err = errors.WithSafeDetails(err, "additional data: %s", errors.Safe("hello"))`.
|
||||
- in this example, the string "hello" will be included in Sentry reports.
|
||||
- however, it is not part of the main error message returned by `Error()`.
|
||||
|
||||
For more details on how Sentry reports are built, see the [`report`](report) sub-package.
|
||||
|
||||
## Building your own error types
|
||||
|
||||
You can create an error type as usual in Go: implement the `error`
|
||||
interface, and, if your type is also a wrapper, the `errors.Wrapper`
|
||||
interface (an `Unwrap()` method). You may also want to implement the
|
||||
`Cause()` method for backward compatibility with
|
||||
`github.com/pkg/errors`, if your project also uses that.
|
||||
|
||||
If your error type is a wrapper, you should implement a `Format()`
|
||||
method that redirects to `errors.FormatError()`, otherwise `%+v` will
|
||||
not work. Additionally, if your type has a payload not otherwise
|
||||
visible via `Error()`, you may want to implement
|
||||
`errors.SafeFormatter`. See [making `%+v` work with your
|
||||
type](#Making-v-work-with-your-type) below for details.
|
||||
|
||||
Finally, you may want your new error type to be portable across
|
||||
the network.
|
||||
|
||||
If your error type is a leaf, and already implements `proto.Message`
|
||||
(from [gogoproto](https://github.com/gogo/protobuf)), you are all set
|
||||
and the errors library will use that automatically. If you do not or
|
||||
cannot implement `proto.Message`, or your error type is a wrapper,
|
||||
read on.
|
||||
|
||||
At a minimum, you will need a *decoder function*: while
|
||||
`cockroachdb/errors` already does a bunch of encoding/decoding work on
|
||||
new types automatically, the one thing it really cannot do on its own
|
||||
is instantiate a Go object using your new type.
|
||||
|
||||
Here is the simplest decode function for a new leaf error type and a
|
||||
new wrapper type:
|
||||
|
||||
```go
|
||||
// note: we use the gogoproto `proto` sub-package.
|
||||
func yourDecode(_ string, _ []string, _ proto.Message) error {
|
||||
return &yourType{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
errors.RegisterLeafEncoder((*yourType)(nil), yourDecodeFunc)
|
||||
}
|
||||
|
||||
func yourDecodeWrapper(cause error, _ string, _ []string, _ proto.Message) error {
|
||||
// Note: the library already takes care of encoding/decoding the cause.
|
||||
return &yourWrapperType{cause: cause}
|
||||
}
|
||||
|
||||
func init() {
|
||||
errors.RegisterWrapperDecoder((*yourWrapperType)(nil), yourDecodeWrapper)
|
||||
}
|
||||
```
|
||||
|
||||
In the case where your type does not have any other field (empty
|
||||
struct for leafs, just a cause for wrappers), this is all you have to
|
||||
do.
|
||||
|
||||
(See the type `withAssertionFailure` in
|
||||
[`assert/assert.go`](assert/assert.go) for an example of this simple
|
||||
case.)
|
||||
|
||||
If your type does have additional fields, you *may* still not need a
|
||||
custom encoder. This is because the library automatically
|
||||
encodes/decodes the main error message and any safe strings that your
|
||||
error types makes available via the `errors.SafeDetailer` interface
|
||||
(the `SafeDetails()` method).
|
||||
|
||||
Say, for example, you have the following leaf type:
|
||||
|
||||
```go
|
||||
type myLeaf struct {
|
||||
code int
|
||||
}
|
||||
|
||||
func (m *myLeaf) Error() string { return fmt.Sprintf("my error: %d" + m.code }
|
||||
```
|
||||
|
||||
In that case, the library will automatically encode the result of
|
||||
calling `Error()`. This string will then be passed back to your
|
||||
decoder function as the first argument. This makes it possible
|
||||
to decode the `code` field exactly:
|
||||
|
||||
```go
|
||||
func myLeafDecoder(msg string, _ []string, _ proto.Message) error {
|
||||
codeS := strings.TrimPrefix(msg, "my error: ")
|
||||
code, _ := strconv.Atoi(codeS)
|
||||
// Note: error handling for strconv is omitted here to simplify
|
||||
// the explanation. If your decoder function should fail, simply
|
||||
// return a `nil` error object (not another unrelated error!).
|
||||
return &myLeaf{code: code}
|
||||
}
|
||||
```
|
||||
|
||||
Likewise, if your fields are PII-free, they are safe to expose via the
|
||||
`errors.SafeDetailer` interface. Those strings also get encoded
|
||||
automatically, and get passed to the decoder function as the second
|
||||
argument.
|
||||
|
||||
For example, say you have the following leaf type:
|
||||
|
||||
```go
|
||||
type myLeaf struct {
|
||||
// both fields are PII-free.
|
||||
code int
|
||||
tag string
|
||||
}
|
||||
|
||||
func (m *myLeaf) Error() string { ... }
|
||||
```
|
||||
|
||||
Then you can expose the fields as safe details as follows:
|
||||
|
||||
```go
|
||||
func (m *myLeaf) SafeDetails() []string {
|
||||
return []string{fmt.Sprintf("%d", m.code), m.tag}
|
||||
}
|
||||
```
|
||||
|
||||
(If the data is PII-free, then it is good to do this in any case: it
|
||||
enables any network system that receives an error of your type, but
|
||||
does not know about it, to still produce useful Sentry reports.)
|
||||
|
||||
Once you have this, the decode function receives the strings and you
|
||||
can use them to re-construct the error:
|
||||
|
||||
```go
|
||||
func myLeafDecoder(_ string, details []string, _ proto.Message) error {
|
||||
// Note: you may want to test the length of the details slice
|
||||
// is correct.
|
||||
code, _ := strconv.Atoi(details[0])
|
||||
tag := details[1]
|
||||
return &myLeaf{code: code, tag: tag}
|
||||
}
|
||||
```
|
||||
|
||||
(For an example, see the `withTelemetry` type in [`telemetry/with_telemetry.go`](telemetry/with_telemetry.go).)
|
||||
|
||||
__The only case where you need a custom encoder is when your error
|
||||
type contains some fields that are not reflected in the error message
|
||||
(so you can't extract them back from there), and are not PII-free and
|
||||
thus cannot be reported as "safe details".__
|
||||
|
||||
To take inspiration from examples, see the following types in the
|
||||
library that need a custom encoder:
|
||||
|
||||
- Hints/details in [`hintdetail/with_hint.go`](hintdetail/with_hint.go) and [`hintdetail/with_detail.go`](hintdetail/with_detail.go).
|
||||
- Secondary error wrappers in [`secondary/with_secondary.go`](secondary/with_secondary.go).
|
||||
- Marker error wrappers at the end of [`markers/markers.go`](markers/markers.go).
|
||||
|
||||
### Making `%+v` work with your type
|
||||
|
||||
In short:
|
||||
|
||||
- When in doubt, you should always implement the `fmt.Formatter`
|
||||
interface (`Format(fmt.State, rune)`) on your custom error types,
|
||||
exactly as follows:
|
||||
|
||||
```go
|
||||
func (e *yourType) Format(s *fmt.State, verb rune) { errors.FormatError(e, s, verb) }
|
||||
```
|
||||
|
||||
(If you do not provide this redirection for your own custom wrapper
|
||||
type, this will disable the recursive application of the `%+v` flag
|
||||
to the causes chained from your wrapper.)
|
||||
|
||||
- You may optionally implement the `errors.SafeFormatter` interface:
|
||||
`SafeFormatError(p errors.Printer) (next error)`. This is optional, but
|
||||
should be done when some details are not included by `Error()` and
|
||||
should be emitted upon `%+v`.
|
||||
|
||||
The example `withHTTPCode` wrapper [included in the source tree](exthttp/ext_http.go)
|
||||
achieves this as follows:
|
||||
|
||||
```go
|
||||
// Format() implements fmt.Formatter, is required until Go knows about FormatError.
|
||||
func (w *withHTTPCode) Format(s fmt.State, verb rune) { errors.FormatError(w, s, verb) }
|
||||
|
||||
// FormatError() formats the error.
|
||||
func (w *withHTTPCode) SafeFormatError(p errors.Printer) (next error) {
|
||||
// Note: no need to print out the cause here!
|
||||
// FormatError() knows how to do this automatically.
|
||||
if p.Detail() {
|
||||
p.Printf("http code: %d", errors.Safe(w.code))
|
||||
}
|
||||
return w.cause
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Technical details follow:
|
||||
|
||||
- The errors library follows [the Go 2
|
||||
proposal](https://go.googlesource.com/proposal/+/master/design/29934-error-values.md).
|
||||
|
||||
- At some point in the future, Go's standard `fmt` library will learn
|
||||
[how to recognize error wrappers, and how to use the `errors.Formatter`
|
||||
interface automatically](https://github.com/golang/go/issues/29934). Until
|
||||
then, you must ensure that you also implement a `Format()` method
|
||||
(from `fmt.Formatter`) that redirects to `errors.FormatError`.
|
||||
|
||||
Note: you may implement `fmt.Formatter` (`Format()` method) in this
|
||||
way without implementing `errors.Formatter` (a `FormatError()`
|
||||
method). In that case, `errors.FormatError` will use a separate code
|
||||
path that does "the right thing", even for wrappers.
|
||||
|
||||
- The library provides an implementation of `errors.FormatError()`,
|
||||
modeled after the same function in Go 2. This is responsible for
|
||||
printing out error details, and knows how to present a chain of
|
||||
causes in a semi-structured format upon formatting with `%+v`.
|
||||
|
||||
### Ensuring `errors.Is` works when errors/packages are renamed
|
||||
|
||||
If a Go package containing a custom error type is renamed, or the
|
||||
error type itself is renamed, and errors of this type are transported
|
||||
over the network, then another system with a different code layout
|
||||
(e.g. running a different version of the software) may not be able to
|
||||
recognize the error any more via `errors.Is`.
|
||||
|
||||
To ensure that network portability continues to work across multiple
|
||||
software versions, in the case error types get renamed or Go packages
|
||||
get moved / renamed / etc, the server code must call
|
||||
`errors.RegisterTypeMigration()` from e.g. an `init()` function.
|
||||
|
||||
Example use:
|
||||
|
||||
```go
|
||||
previousPath := "github.com/old/path/to/error/package"
|
||||
previousTypeName := "oldpackage.oldErrorName"
|
||||
newErrorInstance := &newTypeName{...}
|
||||
errors.RegisterTypeMigration(previousPath, previousTypeName, newErrorInstance)
|
||||
```
|
||||
|
||||
## Error composition (summary)
|
||||
|
||||
| Constructor | Composes |
|
||||
|------------------------------------|-----------------------------------------------------------------------------------|
|
||||
| `New` | `NewWithDepth` (see below) |
|
||||
| `Errorf` | = `Newf` |
|
||||
| `Newf` | `NewWithDepthf` (see below) |
|
||||
| `WithMessage` | custom wrapper with message prefix and knowledge of safe strings |
|
||||
| `Wrap` | `WrapWithDepth` (see below) |
|
||||
| `Wrapf` | `WrapWithDepthf` (see below) |
|
||||
| `AssertionFailed` | `AssertionFailedWithDepthf` (see below) |
|
||||
| `NewWithDepth` | custom leaf with knowledge of safe strings + `WithStackDepth` (see below) |
|
||||
| `NewWithDepthf` | custom leaf with knowledge of safe strings + `WithSafeDetails` + `WithStackDepth` |
|
||||
| `WithMessagef` | custom wrapper with message prefix and knowledge of safe strings |
|
||||
| `WrapWithDepth` | `WithMessage` + `WithStackDepth` |
|
||||
| `WrapWithDepthf` | `WithMessagef` + `WithStackDepth` |
|
||||
| `AssertionFailedWithDepthf` | `NewWithDepthf` + `WithAssertionFailure` |
|
||||
| `NewAssertionErrorWithWrappedErrf` | `HandledWithMessagef` (barrier) + `WrapWithDepthf` + `WithAssertionFailure` |
|
||||
| `Join` | `JoinWithDepth` (see below) |
|
||||
| `JoinWithDepth` | multi-cause wrapper + `WithStackDepth` |
|
||||
## API (not constructing error objects)
|
||||
|
||||
The following is a summary of the non-constructor API functions, grouped by category.
|
||||
Detailed documentation can be found at: https://pkg.go.dev/github.com/cockroachdb/errors
|
||||
|
||||
```go
|
||||
// Access causes.
|
||||
func UnwrapAll(err error) error
|
||||
func UnwrapOnce(err error) error
|
||||
func Cause(err error) error // compatibility
|
||||
func Unwrap(err error) error // compatibility
|
||||
type Wrapper interface { ... } // compatibility
|
||||
|
||||
// Error formatting.
|
||||
type Formatter interface { ... } // compatibility, not recommended
|
||||
type SafeFormatter interface { ... }
|
||||
type Printer interface { ... }
|
||||
func FormatError(err error, s fmt.State, verb rune)
|
||||
func Formattable(err error) fmt.Formatter
|
||||
|
||||
// Identify errors.
|
||||
func Is(err, reference error) bool
|
||||
func IsAny(err error, references ...error) bool
|
||||
func If(err error, pred func(err error) (interface{}, bool)) (interface{}, bool)
|
||||
func As(err error, target interface{}) bool
|
||||
|
||||
// Encode/decode errors.
|
||||
type EncodedError // this is protobuf-encodable
|
||||
func EncodeError(ctx context.Context, err error) EncodedError
|
||||
func DecodeError(ctx context.Context, enc EncodedError) error
|
||||
|
||||
// Register encode/decode functions for custom/new error types.
|
||||
func RegisterLeafDecoder(typeName TypeKey, decoder LeafDecoder)
|
||||
func RegisterLeafEncoder(typeName TypeKey, encoder LeafEncoder)
|
||||
func RegisterWrapperDecoder(typeName TypeKey, decoder WrapperDecoder)
|
||||
func RegisterWrapperEncoder(typeName TypeKey, encoder WrapperEncoder)
|
||||
func RegisterWrapperEncoderWithMessageOverride (typeName TypeKey, encoder WrapperEncoderWithMessageOverride)
|
||||
func RegisterMultiCauseEncoder(theType TypeKey, encoder MultiCauseEncoder)
|
||||
func RegisterMultiCauseDecoder(theType TypeKey, decoder MultiCauseDecoder)
|
||||
type LeafEncoder = func(ctx context.Context, err error) (msg string, safeDetails []string, payload proto.Message)
|
||||
type LeafDecoder = func(ctx context.Context, msg string, safeDetails []string, payload proto.Message) error
|
||||
type WrapperEncoder = func(ctx context.Context, err error) (msgPrefix string, safeDetails []string, payload proto.Message)
|
||||
type WrapperEncoderWithMessageOverride = func(ctx context.Context, err error) (msgPrefix string, safeDetails []string, payload proto.Message, overrideError bool)
|
||||
type WrapperDecoder = func(ctx context.Context, cause error, msgPrefix string, safeDetails []string, payload proto.Message) error
|
||||
type MultiCauseEncoder = func(ctx context.Context, err error) (msg string, safeDetails []string, payload proto.Message)
|
||||
type MultiCauseDecoder = func(ctx context.Context, causes []error, msgPrefix string, safeDetails []string, payload proto.Message) error
|
||||
|
||||
// Registering package renames for custom error types.
|
||||
func RegisterTypeMigration(previousPkgPath, previousTypeName string, newType error)
|
||||
|
||||
// Sentry reports.
|
||||
func BuildSentryReport(err error) (*sentry.Event, map[string]interface{})
|
||||
func ReportError(err error) (string)
|
||||
|
||||
// Stack trace captures.
|
||||
func GetOneLineSource(err error) (file string, line int, fn string, ok bool)
|
||||
type ReportableStackTrace = sentry.StackTrace
|
||||
func GetReportableStackTrace(err error) *ReportableStackTrace
|
||||
|
||||
// Safe (PII-free) details.
|
||||
type SafeDetailPayload struct { ... }
|
||||
func GetAllSafeDetails(err error) []SafeDetailPayload
|
||||
func GetSafeDetails(err error) (payload SafeDetailPayload)
|
||||
|
||||
// Obsolete APIs.
|
||||
type SafeMessager interface { ... }
|
||||
func Redact(r interface{}) string
|
||||
|
||||
// Aliases redact.Safe.
|
||||
func Safe(v interface{}) SafeMessager
|
||||
|
||||
// Assertion failures.
|
||||
func HasAssertionFailure(err error) bool
|
||||
func IsAssertionFailure(err error) bool
|
||||
|
||||
// User-facing details and hints.
|
||||
func GetAllDetails(err error) []string
|
||||
func FlattenDetails(err error) string
|
||||
func GetAllHints(err error) []string
|
||||
func FlattenHints(err error) string
|
||||
|
||||
// Issue links / URL wrappers.
|
||||
func HasIssueLink(err error) bool
|
||||
func IsIssueLink(err error) bool
|
||||
func GetAllIssueLinks(err error) (issues []IssueLink)
|
||||
|
||||
// Unimplemented errors.
|
||||
func HasUnimplementedError(err error) bool
|
||||
func IsUnimplementedError(err error) bool
|
||||
|
||||
// Telemetry keys.
|
||||
func GetTelemetryKeys(err error) []string
|
||||
|
||||
// Domain errors.
|
||||
type Domain
|
||||
const NoDomain Domain
|
||||
func GetDomain(err error) Domain
|
||||
func NamedDomain(domainName string) Domain
|
||||
func PackageDomain() Domain
|
||||
func PackageDomainAtDepth(depth int) Domain
|
||||
func EnsureNotInDomain(err error, constructor DomainOverrideFn, forbiddenDomains ...Domain) error
|
||||
func NotInDomain(err error, doms ...Domain) bool
|
||||
|
||||
// Context tags.
|
||||
func GetContextTags(err error) []*logtags.Buffer
|
||||
```
|
||||
95
vendor/github.com/cockroachdb/errors/assert/assert.go
generated
vendored
Normal file
95
vendor/github.com/cockroachdb/errors/assert/assert.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 assert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/errors/markers"
|
||||
"github.com/cockroachdb/errors/stdstrings"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// WithAssertionFailure decorates the error with an assertion failure marker.
|
||||
// This is not intended to be used directly (see AssertionFailed() for
|
||||
// further decoration).
|
||||
//
|
||||
// Detail is shown:
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func WithAssertionFailure(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withAssertionFailure{cause: err}
|
||||
}
|
||||
|
||||
// HasAssertionFailure returns true if the error or any of its causes
|
||||
// is an assertion failure annotation.
|
||||
func HasAssertionFailure(err error) bool {
|
||||
_, ok := markers.If(err, func(err error) (v interface{}, ok bool) {
|
||||
v, ok = err.(*withAssertionFailure)
|
||||
return
|
||||
})
|
||||
return ok
|
||||
}
|
||||
|
||||
// IsAssertionFailure returns true if the error (not its causes) is an
|
||||
// assertion failure annotation. Consider using markers.If or
|
||||
// HasAssertionFailure to test both the error and its causes.
|
||||
func IsAssertionFailure(err error) bool {
|
||||
_, ok := err.(*withAssertionFailure)
|
||||
return ok
|
||||
}
|
||||
|
||||
type withAssertionFailure struct {
|
||||
cause error
|
||||
}
|
||||
|
||||
var _ error = (*withAssertionFailure)(nil)
|
||||
var _ fmt.Formatter = (*withAssertionFailure)(nil)
|
||||
var _ errbase.SafeFormatter = (*withAssertionFailure)(nil)
|
||||
|
||||
// ErrorHint implements the hintdetail.ErrorHinter interface.
|
||||
func (w *withAssertionFailure) ErrorHint() string {
|
||||
return AssertionErrorHint + stdstrings.IssueReferral
|
||||
}
|
||||
|
||||
// AssertionErrorHint is the hint emitted upon assertion failures.
|
||||
const AssertionErrorHint = `You have encountered an unexpected error.`
|
||||
|
||||
func (w *withAssertionFailure) Error() string { return w.cause.Error() }
|
||||
func (w *withAssertionFailure) Cause() error { return w.cause }
|
||||
func (w *withAssertionFailure) Unwrap() error { return w.cause }
|
||||
|
||||
func (w *withAssertionFailure) Format(s fmt.State, verb rune) { errbase.FormatError(w, s, verb) }
|
||||
func (w *withAssertionFailure) SafeFormatError(p errbase.Printer) error {
|
||||
if p.Detail() {
|
||||
p.Printf("assertion failure")
|
||||
}
|
||||
return w.cause
|
||||
}
|
||||
|
||||
func decodeAssertFailure(
|
||||
_ context.Context, cause error, _ string, _ []string, _ proto.Message,
|
||||
) error {
|
||||
return &withAssertionFailure{cause: cause}
|
||||
}
|
||||
|
||||
func init() {
|
||||
errbase.RegisterWrapperDecoder(errbase.GetTypeKey((*withAssertionFailure)(nil)), decodeAssertFailure)
|
||||
}
|
||||
35
vendor/github.com/cockroachdb/errors/assert_api.go
generated
vendored
Normal file
35
vendor/github.com/cockroachdb/errors/assert_api.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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
|
||||
|
||||
import "github.com/cockroachdb/errors/assert"
|
||||
|
||||
// WithAssertionFailure decorates the error with an assertion failure marker.
|
||||
// This is not intended to be used directly (see AssertionFailed() for
|
||||
// further decoration).
|
||||
//
|
||||
// Detail is shown:
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func WithAssertionFailure(err error) error { return assert.WithAssertionFailure(err) }
|
||||
|
||||
// HasAssertionFailure returns true if the error or any of its causes
|
||||
// is an assertion failure annotation.
|
||||
func HasAssertionFailure(err error) bool { return assert.HasAssertionFailure(err) }
|
||||
|
||||
// IsAssertionFailure returns true if the error (not its causes) is an
|
||||
// assertion failure annotation. Consider using markers.If or
|
||||
// HasAssertionFailure to test both the error and its causes.
|
||||
func IsAssertionFailure(err error) bool { return assert.IsAssertionFailure(err) }
|
||||
151
vendor/github.com/cockroachdb/errors/barriers/barriers.go
generated
vendored
Normal file
151
vendor/github.com/cockroachdb/errors/barriers/barriers.go
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 barriers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/redact"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// Handled swallows the provided error and hides it from the
|
||||
// Cause()/Unwrap() interface, and thus the Is() facility that
|
||||
// identifies causes. However, it retains it for the purpose of
|
||||
// printing the error out (e.g. for troubleshooting). The error
|
||||
// message is preserved in full.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`, shows details from hidden error.
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func Handled(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return HandledWithSafeMessage(err, redact.Sprint(err))
|
||||
}
|
||||
|
||||
// HandledWithMessage is like Handled except the message is overridden.
|
||||
// This can be used e.g. to hide message details or to prevent
|
||||
// downstream code to make assertions on the message's contents.
|
||||
func HandledWithMessage(err error, msg string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return HandledWithSafeMessage(err, redact.Sprint(msg))
|
||||
}
|
||||
|
||||
// HandledWithSafeMessage is like Handled except the message is overridden.
|
||||
// This can be used e.g. to hide message details or to prevent
|
||||
// downstream code to make assertions on the message's contents.
|
||||
func HandledWithSafeMessage(err error, msg redact.RedactableString) error {
|
||||
return &barrierErr{maskedErr: err, smsg: msg}
|
||||
}
|
||||
|
||||
// HandledWithMessagef is like HandledWithMessagef except the message
|
||||
// is formatted.
|
||||
func HandledWithMessagef(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &barrierErr{maskedErr: err, smsg: redact.Sprintf(format, args...)}
|
||||
}
|
||||
|
||||
// barrierErr is a leaf error type. It encapsulates a chain of
|
||||
// original causes, but these causes are hidden so that they inhibit
|
||||
// matching via Is() and the Cause()/Unwrap() recursions.
|
||||
type barrierErr struct {
|
||||
// Message for the barrier itself.
|
||||
// In the common case, the message from the masked error
|
||||
// is used as-is (see Handled() above) however it is
|
||||
// useful to cache it here since the masked error may
|
||||
// have a long chain of wrappers and its Error() call
|
||||
// may be expensive.
|
||||
smsg redact.RedactableString
|
||||
// Masked error chain.
|
||||
maskedErr error
|
||||
}
|
||||
|
||||
var _ error = (*barrierErr)(nil)
|
||||
var _ errbase.SafeDetailer = (*barrierErr)(nil)
|
||||
var _ errbase.SafeFormatter = (*barrierErr)(nil)
|
||||
var _ fmt.Formatter = (*barrierErr)(nil)
|
||||
|
||||
// barrierErr is an error.
|
||||
func (e *barrierErr) Error() string { return e.smsg.StripMarkers() }
|
||||
|
||||
// SafeDetails reports the PII-free details from the masked error.
|
||||
func (e *barrierErr) SafeDetails() []string {
|
||||
var details []string
|
||||
for err := e.maskedErr; err != nil; err = errbase.UnwrapOnce(err) {
|
||||
sd := errbase.GetSafeDetails(err)
|
||||
details = sd.Fill(details)
|
||||
}
|
||||
details = append(details, redact.Sprintf("masked error: %+v", e.maskedErr).Redact().StripMarkers())
|
||||
return details
|
||||
}
|
||||
|
||||
// Printing a barrier reveals the details.
|
||||
func (e *barrierErr) Format(s fmt.State, verb rune) { errbase.FormatError(e, s, verb) }
|
||||
|
||||
func (e *barrierErr) SafeFormatError(p errbase.Printer) (next error) {
|
||||
p.Print(e.smsg)
|
||||
if p.Detail() {
|
||||
p.Printf("-- cause hidden behind barrier\n%+v", e.maskedErr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A barrier error is encoded exactly.
|
||||
func encodeBarrier(
|
||||
ctx context.Context, err error,
|
||||
) (msg string, details []string, payload proto.Message) {
|
||||
e := err.(*barrierErr)
|
||||
enc := errbase.EncodeError(ctx, e.maskedErr)
|
||||
return string(e.smsg), e.SafeDetails(), &enc
|
||||
}
|
||||
|
||||
// A barrier error is decoded exactly.
|
||||
func decodeBarrier(ctx context.Context, msg string, _ []string, payload proto.Message) error {
|
||||
enc := payload.(*errbase.EncodedError)
|
||||
return &barrierErr{smsg: redact.RedactableString(msg), maskedErr: errbase.DecodeError(ctx, *enc)}
|
||||
}
|
||||
|
||||
// Previous versions of barrier errors.
|
||||
func decodeBarrierPrev(ctx context.Context, msg string, _ []string, payload proto.Message) error {
|
||||
enc := payload.(*errbase.EncodedError)
|
||||
return &barrierErr{smsg: redact.Sprint(msg), maskedErr: errbase.DecodeError(ctx, *enc)}
|
||||
}
|
||||
|
||||
// barrierError is the "old" type name of barrierErr. We use a new
|
||||
// name now to ensure a different decode function is used when
|
||||
// importing barriers from the previous structure, where the
|
||||
// message is not redactable.
|
||||
type barrierError struct {
|
||||
msg string
|
||||
maskedErr error
|
||||
}
|
||||
|
||||
func (b *barrierError) Error() string { return "" }
|
||||
|
||||
func init() {
|
||||
errbase.RegisterLeafDecoder(errbase.GetTypeKey((*barrierError)(nil)), decodeBarrierPrev)
|
||||
tn := errbase.GetTypeKey((*barrierErr)(nil))
|
||||
errbase.RegisterLeafDecoder(tn, decodeBarrier)
|
||||
errbase.RegisterLeafEncoder(tn, encodeBarrier)
|
||||
}
|
||||
34
vendor/github.com/cockroachdb/errors/barriers_api.go
generated
vendored
Normal file
34
vendor/github.com/cockroachdb/errors/barriers_api.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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
|
||||
|
||||
import "github.com/cockroachdb/errors/barriers"
|
||||
|
||||
// Handled swallows the provided error and hides it from the
|
||||
// Cause()/Unwrap() interface, and thus the Is() facility that
|
||||
// identifies causes. However, it retains it for the purpose of
|
||||
// printing the error out (e.g. for troubleshooting). The error
|
||||
// message is preserved in full.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`, shows details from hidden error.
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func Handled(err error) error { return barriers.Handled(err) }
|
||||
|
||||
// HandledWithMessage is like Handled except the message is overridden.
|
||||
// This can be used e.g. to hide message details or to prevent
|
||||
// downstream code to make assertions on the message's contents.
|
||||
func HandledWithMessage(err error, msg string) error { return barriers.HandledWithMessage(err, msg) }
|
||||
113
vendor/github.com/cockroachdb/errors/contexttags/contexttags.go
generated
vendored
Normal file
113
vendor/github.com/cockroachdb/errors/contexttags/contexttags.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 contexttags
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/logtags"
|
||||
"github.com/cockroachdb/redact"
|
||||
)
|
||||
|
||||
// WithContextTags captures the k/v pairs stored in the context via the
|
||||
// `logtags` package and annotates them on the error.
|
||||
//
|
||||
// Only the strong representation of values remains available. This is
|
||||
// because the library cannot guarantee that the underlying value is
|
||||
// preserved across the network. To avoid creating a stateful interface
|
||||
// (where the user code needs to know whether an error has traveled
|
||||
// through the network or not), the library restricts access to the
|
||||
// value part as strings. See GetContextTags() below.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`.
|
||||
// - via `GetContextTags()` below.
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func WithContextTags(err error, ctx context.Context) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
tags := logtags.FromContext(ctx)
|
||||
if tags == nil {
|
||||
return err
|
||||
}
|
||||
return &withContext{cause: err, tags: tags}
|
||||
}
|
||||
|
||||
// GetContextTags retrieves the k/v pairs stored in the error.
|
||||
// The sets are returned from outermost to innermost level of cause.
|
||||
// The returned logtags.Buffer only know about the string
|
||||
// representation of the values originally captured by the error.
|
||||
func GetContextTags(err error) (res []*logtags.Buffer) {
|
||||
for e := err; e != nil; e = errbase.UnwrapOnce(e) {
|
||||
if w, ok := e.(*withContext); ok {
|
||||
b := w.tags
|
||||
// Ensure that the buffer does not contain any non-string.
|
||||
if hasNonStringValue(b) {
|
||||
b = convertToStringsOnly(b)
|
||||
}
|
||||
res = append(res, b)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func hasNonStringValue(b *logtags.Buffer) bool {
|
||||
for _, t := range b.Get() {
|
||||
v := t.Value()
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
if _, ok := v.(string); !ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func convertToStringsOnly(b *logtags.Buffer) (res *logtags.Buffer) {
|
||||
for _, t := range b.Get() {
|
||||
res = res.Add(t.Key(), t.ValueStr())
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func redactTags(b *logtags.Buffer) []string {
|
||||
res := make([]string, len(b.Get()))
|
||||
redactableTagsIterate(b, func(i int, r redact.RedactableString) {
|
||||
res[i] = r.Redact().StripMarkers()
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
func redactableTagsIterate(b *logtags.Buffer, fn func(i int, s redact.RedactableString)) {
|
||||
var empty redact.SafeString
|
||||
for i, t := range b.Get() {
|
||||
k := t.Key()
|
||||
v := t.Value()
|
||||
eq := empty
|
||||
var val interface{} = empty
|
||||
if v != nil {
|
||||
if len(k) > 1 {
|
||||
eq = "="
|
||||
}
|
||||
val = v
|
||||
}
|
||||
res := redact.Sprintf("%s%s%v", redact.Safe(k), eq, val)
|
||||
fn(i, res)
|
||||
}
|
||||
}
|
||||
115
vendor/github.com/cockroachdb/errors/contexttags/with_context.go
generated
vendored
Normal file
115
vendor/github.com/cockroachdb/errors/contexttags/with_context.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 contexttags
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/errors/errorspb"
|
||||
"github.com/cockroachdb/logtags"
|
||||
"github.com/cockroachdb/redact"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type withContext struct {
|
||||
cause error
|
||||
// tags stores the context k/v pairs, non-redacted.
|
||||
// The errors library only gives access to the string representation
|
||||
// of the value part. This is because the network encoding of
|
||||
// a withContext instance only stores the string.
|
||||
tags *logtags.Buffer
|
||||
// redactedTags stores the context k/v pairs, redacted.
|
||||
// When this is defined, SafeDetails() uses it. Otherwise, it
|
||||
// re-redact tags above.
|
||||
redactedTags []string
|
||||
}
|
||||
|
||||
var _ error = (*withContext)(nil)
|
||||
var _ errbase.SafeDetailer = (*withContext)(nil)
|
||||
var _ errbase.SafeFormatter = (*withContext)(nil)
|
||||
var _ fmt.Formatter = (*withContext)(nil)
|
||||
|
||||
// withContext is an error. The original error message is preserved.
|
||||
func (w *withContext) Error() string { return w.cause.Error() }
|
||||
|
||||
// the cause is reachable.
|
||||
func (w *withContext) Cause() error { return w.cause }
|
||||
func (w *withContext) Unwrap() error { return w.cause }
|
||||
|
||||
// Printing a withContext reveals the tags.
|
||||
func (w *withContext) Format(s fmt.State, verb rune) { errbase.FormatError(w, s, verb) }
|
||||
|
||||
func (w *withContext) SafeFormatError(p errbase.Printer) error {
|
||||
if p.Detail() && w.tags != nil {
|
||||
p.Printf("tags: [")
|
||||
redactableTagsIterate(w.tags, func(i int, r redact.RedactableString) {
|
||||
if i > 0 {
|
||||
p.Printf(",")
|
||||
}
|
||||
p.Print(r)
|
||||
})
|
||||
p.Printf("]")
|
||||
}
|
||||
return w.cause
|
||||
}
|
||||
|
||||
// SafeDetails implements the errbase.SafeDetailer interface.
|
||||
func (w *withContext) SafeDetails() []string {
|
||||
if w.redactedTags != nil {
|
||||
return w.redactedTags
|
||||
}
|
||||
return redactTags(w.tags)
|
||||
}
|
||||
|
||||
func encodeWithContext(_ context.Context, err error) (string, []string, proto.Message) {
|
||||
w := err.(*withContext)
|
||||
p := &errorspb.TagsPayload{}
|
||||
for _, t := range w.tags.Get() {
|
||||
p.Tags = append(p.Tags, errorspb.TagPayload{Tag: t.Key(), Value: t.ValueStr()})
|
||||
}
|
||||
return "", w.SafeDetails(), p
|
||||
}
|
||||
|
||||
func decodeWithContext(
|
||||
_ context.Context, cause error, _ string, redactedTags []string, payload proto.Message,
|
||||
) error {
|
||||
m, ok := payload.(*errorspb.TagsPayload)
|
||||
if !ok {
|
||||
// If this ever happens, this means some version of the library
|
||||
// (presumably future) changed the payload type, and we're
|
||||
// receiving this here. In this case, give up and let
|
||||
// DecodeError use the opaque type.
|
||||
return nil
|
||||
}
|
||||
if len(m.Tags) == 0 && len(redactedTags) == 0 {
|
||||
// There are no tags stored. Either there are no tags stored, or
|
||||
// we received some new version of the protobuf message which does
|
||||
// things differently. Again, use the opaque type.
|
||||
return nil
|
||||
}
|
||||
// Convert the k/v pairs.
|
||||
var b *logtags.Buffer
|
||||
for _, t := range m.Tags {
|
||||
b = b.Add(t.Tag, t.Value)
|
||||
}
|
||||
return &withContext{cause: cause, tags: b, redactedTags: redactedTags}
|
||||
}
|
||||
|
||||
func init() {
|
||||
errbase.RegisterWrapperEncoder(errbase.GetTypeKey((*withContext)(nil)), encodeWithContext)
|
||||
errbase.RegisterWrapperDecoder(errbase.GetTypeKey((*withContext)(nil)), decodeWithContext)
|
||||
}
|
||||
47
vendor/github.com/cockroachdb/errors/contexttags_api.go
generated
vendored
Normal file
47
vendor/github.com/cockroachdb/errors/contexttags_api.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cockroachdb/errors/contexttags"
|
||||
"github.com/cockroachdb/logtags"
|
||||
)
|
||||
|
||||
// WithContextTags captures the k/v pairs stored in the context via the
|
||||
// `logtags` package and annotates them on the error.
|
||||
//
|
||||
// Only the strong representation of values remains available. This is
|
||||
// because the library cannot guarantee that the underlying value is
|
||||
// preserved across the network. To avoid creating a stateful interface
|
||||
// (where the user code needs to know whether an error has traveled
|
||||
// through the network or not), the library restricts access to the
|
||||
// value part as strings. See GetContextTags() below.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`.
|
||||
// - via `GetContextTags()` below.
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func WithContextTags(err error, ctx context.Context) error {
|
||||
return contexttags.WithContextTags(err, ctx)
|
||||
}
|
||||
|
||||
// GetContextTags retrieves the k/v pairs stored in the error.
|
||||
// The sets are returned from outermost to innermost level of cause.
|
||||
// The returned logtags.Buffer only know about the string
|
||||
// representation of the values originally captured by the error.
|
||||
func GetContextTags(err error) []*logtags.Buffer { return contexttags.GetContextTags(err) }
|
||||
156
vendor/github.com/cockroachdb/errors/domains/domains.go
generated
vendored
Normal file
156
vendor/github.com/cockroachdb/errors/domains/domains.go
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 domains
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/cockroachdb/errors/barriers"
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
)
|
||||
|
||||
// Domain is the type of a domain annotation.
|
||||
type Domain string
|
||||
|
||||
// NoDomain is the domain of errors that don't originate
|
||||
// from a barrier.
|
||||
const NoDomain Domain = "error domain: <none>"
|
||||
|
||||
// GetDomain extracts the domain of the given error, or NoDomain if
|
||||
// the error's cause does not have a domain annotation.
|
||||
func GetDomain(err error) Domain {
|
||||
for {
|
||||
if b, ok := err.(*withDomain); ok {
|
||||
return b.domain
|
||||
}
|
||||
// Recurse to the cause.
|
||||
if c := errbase.UnwrapOnce(err); c != nil {
|
||||
err = c
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
return NoDomain
|
||||
}
|
||||
|
||||
// WithDomain wraps an error so that it appears to come from the given domain.
|
||||
//
|
||||
// Domain is shown:
|
||||
// - via `errors.GetSafeDetails()`.
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func WithDomain(err error, domain Domain) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withDomain{cause: err, domain: domain}
|
||||
}
|
||||
|
||||
// New creates an error in the implicit domain (see PackageDomain() below)
|
||||
// of its caller.
|
||||
//
|
||||
// Domain is shown:
|
||||
// - via `errors.GetSafeDetails()`.
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func New(msg string) error {
|
||||
return WithDomain(errors.New(msg), PackageDomainAtDepth(1))
|
||||
}
|
||||
|
||||
// Newf/Errorf with format and args can be implemented similarly.
|
||||
|
||||
// HandledInDomain creates an error in the given domain and retains
|
||||
// the details of the given original error as context for
|
||||
// debugging. The original error is hidden and does not become a
|
||||
// "cause" for the new error. The original's error _message_
|
||||
// is preserved.
|
||||
//
|
||||
// See the documentation of `WithDomain()` and `errors.Handled()` for details.
|
||||
func HandledInDomain(err error, domain Domain) error {
|
||||
return WithDomain(barriers.Handled(err), domain)
|
||||
}
|
||||
|
||||
// HandledInDomainWithMessage is like HandledWithMessage but with a domain.
|
||||
func HandledInDomainWithMessage(err error, domain Domain, msg string) error {
|
||||
return WithDomain(barriers.HandledWithMessage(err, msg), domain)
|
||||
}
|
||||
|
||||
// Handled creates a handled error in the implicit domain (see
|
||||
// PackageDomain() below) of its caller.
|
||||
//
|
||||
// See the documentation of `barriers.Handled()` for details.
|
||||
func Handled(err error) error {
|
||||
return HandledInDomain(err, PackageDomainAtDepth(1))
|
||||
}
|
||||
|
||||
// Handledf with format and args can be implemented similarly.
|
||||
|
||||
// NotInDomain returns true if and only if the error's
|
||||
// domain is not one of the specified domains.
|
||||
func NotInDomain(err error, domains ...Domain) bool {
|
||||
return notInDomainInternal(GetDomain(err), domains...)
|
||||
}
|
||||
|
||||
func notInDomainInternal(d Domain, domains ...Domain) bool {
|
||||
for _, given := range domains {
|
||||
if d == given {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// EnsureNotInDomain checks whether the error is in the given domain(s).
|
||||
// If it is, the given constructor if provided is called to construct
|
||||
// an alternate error. If no error constructor is provided,
|
||||
// a new barrier is constructed automatically using the first
|
||||
// provided domain as new domain. The original error message
|
||||
// is preserved.
|
||||
func EnsureNotInDomain(
|
||||
err error, constructor func(originalDomain Domain, err error) error, forbiddenDomains ...Domain,
|
||||
) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Is the error already in the wanted domains?
|
||||
errDomain := GetDomain(err)
|
||||
if notInDomainInternal(errDomain, forbiddenDomains...) {
|
||||
// No: no-op.
|
||||
return err
|
||||
}
|
||||
return constructor(errDomain, err)
|
||||
}
|
||||
|
||||
// PackageDomain returns an error domain that represents the
|
||||
// package of its caller.
|
||||
func PackageDomain() Domain {
|
||||
return PackageDomainAtDepth(1)
|
||||
}
|
||||
|
||||
// PackageDomainAtDepth returns an error domain that describes the
|
||||
// package at the given call depth.
|
||||
func PackageDomainAtDepth(depth int) Domain {
|
||||
_, f, _, _ := runtime.Caller(1 + depth)
|
||||
return Domain("error domain: pkg " + filepath.Dir(f))
|
||||
}
|
||||
|
||||
// NamedDomain returns an error domain identified by the given string.
|
||||
func NamedDomain(domainName string) Domain {
|
||||
return Domain(fmt.Sprintf("error domain: %q", domainName))
|
||||
}
|
||||
84
vendor/github.com/cockroachdb/errors/domains/with_domain.go
generated
vendored
Normal file
84
vendor/github.com/cockroachdb/errors/domains/with_domain.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 domains
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/redact"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// withDomain is a wrapper type that adds a domain annotation to an
|
||||
// error.
|
||||
type withDomain struct {
|
||||
// Mandatory: error cause
|
||||
cause error
|
||||
// Mandatory: domain. This also must be free of PII
|
||||
// as it will be reported in "safe details".
|
||||
domain Domain
|
||||
}
|
||||
|
||||
var _ error = (*withDomain)(nil)
|
||||
var _ errbase.SafeDetailer = (*withDomain)(nil)
|
||||
var _ errbase.TypeKeyMarker = (*withDomain)(nil)
|
||||
var _ fmt.Formatter = (*withDomain)(nil)
|
||||
var _ errbase.SafeFormatter = (*withDomain)(nil)
|
||||
|
||||
// withDomain is an error. The original error message is preserved.
|
||||
func (e *withDomain) Error() string { return e.cause.Error() }
|
||||
|
||||
// the cause is reachable.
|
||||
func (e *withDomain) Cause() error { return e.cause }
|
||||
func (e *withDomain) Unwrap() error { return e.cause }
|
||||
|
||||
// ErrorKeyMarker implements the TypeNameMarker interface.
|
||||
// The full type name of barriers is extended with the domain as extra marker.
|
||||
// This ensures that domain-annotated errors appear to be of different types
|
||||
// for the purpose of Is().
|
||||
func (e *withDomain) ErrorKeyMarker() string { return string(e.domain) }
|
||||
|
||||
// SafeDetails reports the domain.
|
||||
func (e *withDomain) SafeDetails() []string {
|
||||
return []string{string(e.domain)}
|
||||
}
|
||||
|
||||
func (e *withDomain) Format(s fmt.State, verb rune) { errbase.FormatError(e, s, verb) }
|
||||
|
||||
func (e *withDomain) SafeFormatError(p errbase.Printer) error {
|
||||
if p.Detail() {
|
||||
p.Print(redact.Safe(e.domain))
|
||||
}
|
||||
return e.cause
|
||||
}
|
||||
|
||||
// A domain-annotated error is decoded exactly.
|
||||
func decodeWithDomain(
|
||||
_ context.Context, cause error, _ string, details []string, _ proto.Message,
|
||||
) error {
|
||||
if len(details) == 0 {
|
||||
// decoding failure: expecting at least one detail string
|
||||
// (the one that carries the domain string).
|
||||
return nil
|
||||
}
|
||||
return &withDomain{cause: cause, domain: Domain(details[0])}
|
||||
}
|
||||
|
||||
func init() {
|
||||
tn := errbase.GetTypeKey((*withDomain)(nil))
|
||||
errbase.RegisterWrapperDecoder(tn, decodeWithDomain)
|
||||
}
|
||||
78
vendor/github.com/cockroachdb/errors/domains_api.go
generated
vendored
Normal file
78
vendor/github.com/cockroachdb/errors/domains_api.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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
|
||||
|
||||
import "github.com/cockroachdb/errors/domains"
|
||||
|
||||
// Domain is the type of a domain annotation.
|
||||
type Domain = domains.Domain
|
||||
|
||||
// NoDomain is the domain of errors that don't originate
|
||||
// from a barrier.
|
||||
const NoDomain Domain = domains.NoDomain
|
||||
|
||||
// NamedDomain returns an error domain identified by the given string.
|
||||
func NamedDomain(domainName string) Domain { return domains.NamedDomain(domainName) }
|
||||
|
||||
// PackageDomain returns an error domain that represents the
|
||||
// package of its caller.
|
||||
func PackageDomain() Domain { return domains.PackageDomainAtDepth(1) }
|
||||
|
||||
// PackageDomainAtDepth returns an error domain that describes the
|
||||
// package at the given call depth.
|
||||
func PackageDomainAtDepth(depth int) Domain { return domains.PackageDomainAtDepth(depth) }
|
||||
|
||||
// WithDomain wraps an error so that it appears to come from the given domain.
|
||||
//
|
||||
// Domain is shown:
|
||||
// - via `errors.GetSafeDetails()`.
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func WithDomain(err error, domain Domain) error { return domains.WithDomain(err, domain) }
|
||||
|
||||
// NotInDomain returns true if and only if the error's
|
||||
// domain is not one of the specified domains.
|
||||
func NotInDomain(err error, doms ...Domain) bool { return domains.NotInDomain(err, doms...) }
|
||||
|
||||
// EnsureNotInDomain checks whether the error is in the given domain(s).
|
||||
// If it is, the given constructor if provided is called to construct
|
||||
// an alternate error. If no error constructor is provided,
|
||||
// a new barrier is constructed automatically using the first
|
||||
// provided domain as new domain. The original error message
|
||||
// is preserved.
|
||||
func EnsureNotInDomain(err error, constructor DomainOverrideFn, forbiddenDomains ...Domain) error {
|
||||
return domains.EnsureNotInDomain(err, constructor, forbiddenDomains...)
|
||||
}
|
||||
|
||||
// DomainOverrideFn is the type of the callback function passed to EnsureNotInDomain().
|
||||
type DomainOverrideFn = func(originalDomain Domain, err error) error
|
||||
|
||||
// HandledInDomain creates an error in the given domain and retains
|
||||
// the details of the given original error as context for
|
||||
// debugging. The original error is hidden and does not become a
|
||||
// "cause" for the new error. The original's error _message_
|
||||
// is preserved.
|
||||
//
|
||||
// See the documentation of `WithDomain()` and `errors.Handled()` for details.
|
||||
func HandledInDomain(err error, domain Domain) error { return domains.HandledInDomain(err, domain) }
|
||||
|
||||
// HandledInDomainWithMessage is like HandledWithMessage but with a domain.
|
||||
func HandledInDomainWithMessage(err error, domain Domain, msg string) error {
|
||||
return domains.HandledInDomainWithMessage(err, domain, msg)
|
||||
}
|
||||
|
||||
// GetDomain extracts the domain of the given error, or NoDomain if
|
||||
// the error's cause does not have a domain annotation.
|
||||
func GetDomain(err error) Domain { return domains.GetDomain(err) }
|
||||
214
vendor/github.com/cockroachdb/errors/errbase/adapters.go
generated
vendored
Normal file
214
vendor/github.com/cockroachdb/errors/errbase/adapters.go
generated
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 errbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
goErr "errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/cockroachdb/errors/errorspb"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
pkgErr "github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// This file provides the library the ability to encode/decode
|
||||
// standard error types.
|
||||
|
||||
// errors.errorString from base Go does not need an encoding
|
||||
// function, because the base encoding logic in EncodeLeaf() is
|
||||
// able to extract everything about it.
|
||||
|
||||
// we can then decode it exactly.
|
||||
func decodeErrorString(_ context.Context, msg string, _ []string, _ proto.Message) error {
|
||||
return goErr.New(msg)
|
||||
}
|
||||
|
||||
// context.DeadlineExceeded uses a custom type.
|
||||
func decodeDeadlineExceeded(_ context.Context, _ string, _ []string, _ proto.Message) error {
|
||||
return context.DeadlineExceeded
|
||||
}
|
||||
|
||||
// errors.fundamental from github.com/pkg/errors cannot be encoded
|
||||
// exactly because it includes a non-serializable stack trace
|
||||
// object. In order to work with it, we encode it by dumping
|
||||
// the stack trace in a safe reporting detail field, and decode
|
||||
// it as an opaqueLeaf instance in this package.
|
||||
|
||||
func encodePkgFundamental(
|
||||
_ context.Context, err error,
|
||||
) (msg string, safe []string, _ proto.Message) {
|
||||
msg = err.Error()
|
||||
iErr := err.(interface{ StackTrace() pkgErr.StackTrace })
|
||||
safeDetails := []string{fmt.Sprintf("%+v", iErr.StackTrace())}
|
||||
return msg, safeDetails, nil
|
||||
}
|
||||
|
||||
// errors.withMessage from github.com/pkg/errors can be encoded
|
||||
// exactly because it just has a message prefix. The base encoding
|
||||
// logic in EncodeWrapper() is able to extract everything from it.
|
||||
|
||||
// we can then decode it exactly.
|
||||
func decodeWithMessage(
|
||||
_ context.Context, cause error, msgPrefix string, _ []string, _ proto.Message,
|
||||
) error {
|
||||
return pkgErr.WithMessage(cause, msgPrefix)
|
||||
}
|
||||
|
||||
// errors.withStack from github.com/pkg/errors cannot be encoded
|
||||
// exactly because it includes a non-serializable stack trace
|
||||
// object. In order to work with it, we encode it by dumping
|
||||
// the stack trace in a safe reporting detail field, and decode
|
||||
// it as an opaqueWrapper instance in this package.
|
||||
|
||||
func encodePkgWithStack(
|
||||
_ context.Context, err error,
|
||||
) (msgPrefix string, safe []string, _ proto.Message) {
|
||||
iErr := err.(interface{ StackTrace() pkgErr.StackTrace })
|
||||
safeDetails := []string{fmt.Sprintf("%+v", iErr.StackTrace())}
|
||||
return "" /* withStack does not have a message prefix */, safeDetails, nil
|
||||
}
|
||||
|
||||
func encodePathError(
|
||||
_ context.Context, err error,
|
||||
) (msgPrefix string, safe []string, details proto.Message) {
|
||||
p := err.(*os.PathError)
|
||||
msg := p.Op + " " + p.Path
|
||||
details = &errorspb.StringsPayload{
|
||||
Details: []string{p.Op, p.Path},
|
||||
}
|
||||
return msg, []string{p.Op}, details
|
||||
}
|
||||
|
||||
func decodePathError(
|
||||
_ context.Context, cause error, _ string, _ []string, payload proto.Message,
|
||||
) (result error) {
|
||||
m, ok := payload.(*errorspb.StringsPayload)
|
||||
if !ok || len(m.Details) < 2 {
|
||||
// If this ever happens, this means some version of the library
|
||||
// (presumably future) changed the payload type, and we're
|
||||
// receiving this here. In this case, give up and let
|
||||
// DecodeError use the opaque type.
|
||||
return nil
|
||||
}
|
||||
return &os.PathError{
|
||||
Op: m.Details[0],
|
||||
Path: m.Details[1],
|
||||
Err: cause,
|
||||
}
|
||||
}
|
||||
|
||||
func encodeLinkError(
|
||||
_ context.Context, err error,
|
||||
) (msgPrefix string, safe []string, details proto.Message) {
|
||||
p := err.(*os.LinkError)
|
||||
msg := p.Op + " " + p.Old + " " + p.New
|
||||
details = &errorspb.StringsPayload{
|
||||
Details: []string{p.Op, p.Old, p.New},
|
||||
}
|
||||
return msg, []string{p.Op}, details
|
||||
}
|
||||
|
||||
func decodeLinkError(
|
||||
_ context.Context, cause error, _ string, _ []string, payload proto.Message,
|
||||
) (result error) {
|
||||
m, ok := payload.(*errorspb.StringsPayload)
|
||||
if !ok || len(m.Details) < 3 {
|
||||
// If this ever happens, this means some version of the library
|
||||
// (presumably future) changed the payload type, and we're
|
||||
// receiving this here. In this case, give up and let
|
||||
// DecodeError use the opaque type.
|
||||
return nil
|
||||
}
|
||||
return &os.LinkError{
|
||||
Op: m.Details[0],
|
||||
Old: m.Details[1],
|
||||
New: m.Details[2],
|
||||
Err: cause,
|
||||
}
|
||||
}
|
||||
|
||||
func encodeSyscallError(
|
||||
_ context.Context, err error,
|
||||
) (msgPrefix string, safe []string, details proto.Message) {
|
||||
p := err.(*os.SyscallError)
|
||||
return p.Syscall, nil, nil
|
||||
}
|
||||
|
||||
func decodeSyscallError(
|
||||
_ context.Context, cause error, msg string, _ []string, _ proto.Message,
|
||||
) (result error) {
|
||||
return os.NewSyscallError(msg, cause)
|
||||
}
|
||||
|
||||
// OpaqueErrno represents a syscall.Errno error object that
|
||||
// was constructed on a different OS/platform combination.
|
||||
type OpaqueErrno struct {
|
||||
msg string
|
||||
details *errorspb.ErrnoPayload
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (o *OpaqueErrno) Error() string { return o.msg }
|
||||
|
||||
// Is tests whether this opaque errno object represents a special os error type.
|
||||
func (o *OpaqueErrno) Is(target error) bool {
|
||||
return (target == os.ErrPermission && o.details.IsPermission) ||
|
||||
(target == os.ErrExist && o.details.IsExist) ||
|
||||
(target == os.ErrNotExist && o.details.IsNotExist)
|
||||
}
|
||||
|
||||
// Temporary tests whether this opaque errno object encodes a temporary error.
|
||||
func (o *OpaqueErrno) Temporary() bool { return o.details.IsTemporary }
|
||||
|
||||
// Timeout tests whether this opaque errno object encodes a timeout error.
|
||||
func (o *OpaqueErrno) Timeout() bool { return o.details.IsTimeout }
|
||||
|
||||
func encodeOpaqueErrno(
|
||||
_ context.Context, err error,
|
||||
) (msg string, safe []string, payload proto.Message) {
|
||||
e := err.(*OpaqueErrno)
|
||||
return e.Error(), []string{e.Error()}, e.details
|
||||
}
|
||||
|
||||
func init() {
|
||||
baseErr := goErr.New("")
|
||||
RegisterLeafDecoder(GetTypeKey(baseErr), decodeErrorString)
|
||||
|
||||
RegisterLeafDecoder(GetTypeKey(context.DeadlineExceeded), decodeDeadlineExceeded)
|
||||
|
||||
pkgE := pkgErr.New("")
|
||||
RegisterLeafEncoder(GetTypeKey(pkgE), encodePkgFundamental)
|
||||
|
||||
RegisterWrapperDecoder(GetTypeKey(pkgErr.WithMessage(baseErr, "")), decodeWithMessage)
|
||||
|
||||
ws := pkgErr.WithStack(baseErr)
|
||||
RegisterWrapperEncoder(GetTypeKey(ws), encodePkgWithStack)
|
||||
|
||||
registerOsPathErrorMigration() // Needed for Go 1.16.
|
||||
pKey := GetTypeKey(&os.PathError{})
|
||||
RegisterWrapperEncoder(pKey, encodePathError)
|
||||
RegisterWrapperDecoder(pKey, decodePathError)
|
||||
|
||||
pKey = GetTypeKey(&os.LinkError{})
|
||||
RegisterWrapperEncoder(pKey, encodeLinkError)
|
||||
RegisterWrapperDecoder(pKey, decodeLinkError)
|
||||
pKey = GetTypeKey(&os.SyscallError{})
|
||||
RegisterWrapperEncoder(pKey, encodeSyscallError)
|
||||
RegisterWrapperDecoder(pKey, decodeSyscallError)
|
||||
|
||||
RegisterLeafEncoder(GetTypeKey(&OpaqueErrno{}), encodeOpaqueErrno)
|
||||
}
|
||||
66
vendor/github.com/cockroachdb/errors/errbase/adapters_errno.go
generated
vendored
Normal file
66
vendor/github.com/cockroachdb/errors/errbase/adapters_errno.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// +build !plan9
|
||||
|
||||
package errbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
|
||||
"github.com/cockroachdb/errors/errorspb"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
const thisArch = runtime.GOOS + ":" + runtime.GOARCH
|
||||
|
||||
func encodeErrno(_ context.Context, err error) (msg string, safe []string, payload proto.Message) {
|
||||
e := err.(syscall.Errno)
|
||||
payload = &errorspb.ErrnoPayload{
|
||||
OrigErrno: int64(e),
|
||||
Arch: thisArch,
|
||||
IsPermission: e.Is(os.ErrPermission),
|
||||
IsExist: e.Is(os.ErrExist),
|
||||
IsNotExist: e.Is(os.ErrNotExist),
|
||||
IsTimeout: e.Timeout(),
|
||||
IsTemporary: e.Temporary(),
|
||||
}
|
||||
return e.Error(), []string{e.Error()}, payload
|
||||
}
|
||||
|
||||
func decodeErrno(_ context.Context, msg string, _ []string, payload proto.Message) error {
|
||||
m, ok := payload.(*errorspb.ErrnoPayload)
|
||||
if !ok {
|
||||
// If this ever happens, this means some version of the library
|
||||
// (presumably future) changed the payload type, and we're
|
||||
// receiving this here. In this case, give up and let
|
||||
// DecodeError use the opaque type.
|
||||
return nil
|
||||
}
|
||||
if m.Arch != thisArch {
|
||||
// The errno object is coming from a different platform. We'll
|
||||
// keep it opaque here.
|
||||
return &OpaqueErrno{msg: msg, details: m}
|
||||
}
|
||||
return syscall.Errno(m.OrigErrno)
|
||||
}
|
||||
|
||||
func init() {
|
||||
pKey := GetTypeKey(syscall.Errno(0))
|
||||
RegisterLeafEncoder(pKey, encodeErrno)
|
||||
RegisterLeafDecoder(pKey, decodeErrno)
|
||||
}
|
||||
206
vendor/github.com/cockroachdb/errors/errbase/decode.go
generated
vendored
Normal file
206
vendor/github.com/cockroachdb/errors/errbase/decode.go
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 errbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cockroachdb/errors/errorspb"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/gogo/protobuf/types"
|
||||
)
|
||||
|
||||
// DecodeError decodes an error.
|
||||
//
|
||||
// Can only be called if the EncodedError is set (see IsSet()).
|
||||
func DecodeError(ctx context.Context, enc EncodedError) error {
|
||||
if w := enc.GetWrapper(); w != nil {
|
||||
return decodeWrapper(ctx, w)
|
||||
}
|
||||
return decodeLeaf(ctx, enc.GetLeaf())
|
||||
}
|
||||
|
||||
func decodeLeaf(ctx context.Context, enc *errorspb.EncodedErrorLeaf) error {
|
||||
// In case there is a detailed payload, decode it.
|
||||
var payload proto.Message
|
||||
if enc.Details.FullDetails != nil {
|
||||
var d types.DynamicAny
|
||||
err := types.UnmarshalAny(enc.Details.FullDetails, &d)
|
||||
if err != nil {
|
||||
// It's OK if we can't decode. We'll use
|
||||
// the opaque type below.
|
||||
warningFn(ctx, "error while unmarshalling error: %+v", err)
|
||||
} else {
|
||||
payload = d.Message
|
||||
}
|
||||
}
|
||||
|
||||
// Do we have a leaf decoder for this type?
|
||||
typeKey := TypeKey(enc.Details.ErrorTypeMark.FamilyName)
|
||||
if decoder, ok := leafDecoders[typeKey]; ok {
|
||||
// Yes, use it.
|
||||
genErr := decoder(ctx, enc.Message, enc.Details.ReportablePayload, payload)
|
||||
if genErr != nil {
|
||||
// Decoding succeeded. Use this.
|
||||
return genErr
|
||||
}
|
||||
// Decoding failed, we'll drop through to opaqueLeaf{} below.
|
||||
} else if decoder, ok := multiCauseDecoders[typeKey]; ok {
|
||||
causes := make([]error, len(enc.MultierrorCauses))
|
||||
for i, e := range enc.MultierrorCauses {
|
||||
causes[i] = DecodeError(ctx, *e)
|
||||
}
|
||||
genErr := decoder(ctx, causes, enc.Message, enc.Details.ReportablePayload, payload)
|
||||
if genErr != nil {
|
||||
return genErr
|
||||
}
|
||||
} else {
|
||||
// Shortcut for non-registered proto-encodable error types:
|
||||
// if it already implements `error`, it's good to go.
|
||||
if e, ok := payload.(error); ok {
|
||||
// yes: we're done!
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
if len(enc.MultierrorCauses) > 0 {
|
||||
causes := make([]error, len(enc.MultierrorCauses))
|
||||
for i, e := range enc.MultierrorCauses {
|
||||
causes[i] = DecodeError(ctx, *e)
|
||||
}
|
||||
leaf := &opaqueLeafCauses{
|
||||
causes: causes,
|
||||
}
|
||||
leaf.msg = enc.Message
|
||||
leaf.details = enc.Details
|
||||
return leaf
|
||||
}
|
||||
|
||||
// No decoder and no error type: we'll keep what we received and
|
||||
// make it ready to re-encode exactly (if the error leaves over the
|
||||
// network again).
|
||||
return &opaqueLeaf{
|
||||
msg: enc.Message,
|
||||
details: enc.Details,
|
||||
}
|
||||
}
|
||||
|
||||
func decodeWrapper(ctx context.Context, enc *errorspb.EncodedWrapper) error {
|
||||
// First decode the cause.
|
||||
cause := DecodeError(ctx, enc.Cause)
|
||||
|
||||
// In case there is a detailed payload, decode it.
|
||||
var payload proto.Message
|
||||
if enc.Details.FullDetails != nil {
|
||||
var d types.DynamicAny
|
||||
err := types.UnmarshalAny(enc.Details.FullDetails, &d)
|
||||
if err != nil {
|
||||
// It's OK if we can't decode. We'll use
|
||||
// the opaque type below.
|
||||
warningFn(ctx, "error while unmarshalling wrapper error: %+v", err)
|
||||
} else {
|
||||
payload = d.Message
|
||||
}
|
||||
}
|
||||
|
||||
// Do we have a wrapper decoder for this?
|
||||
typeKey := TypeKey(enc.Details.ErrorTypeMark.FamilyName)
|
||||
if decoder, ok := decoders[typeKey]; ok {
|
||||
// Yes, use it.
|
||||
genErr := decoder(ctx, cause, enc.Message, enc.Details.ReportablePayload, payload)
|
||||
if genErr != nil {
|
||||
// Decoding succeeded. Use this.
|
||||
return genErr
|
||||
}
|
||||
// Decoding failed, we'll drop through to opaqueWrapper{} below.
|
||||
}
|
||||
|
||||
// Otherwise, preserve all details about the original object.
|
||||
return &opaqueWrapper{
|
||||
cause: cause,
|
||||
prefix: enc.Message,
|
||||
details: enc.Details,
|
||||
messageType: MessageType(enc.MessageType),
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterLeafDecoder can be used to register new leaf error types to
|
||||
// the library. Registered types will be decoded using their own
|
||||
// Go type when an error is decoded. Wrappers that have not been
|
||||
// registered will be decoded using the opaqueLeaf type.
|
||||
//
|
||||
// Note: if the error type has been migrated from a previous location
|
||||
// or a different type, ensure that RegisterTypeMigration() was called
|
||||
// prior to RegisterLeafDecoder().
|
||||
func RegisterLeafDecoder(theType TypeKey, decoder LeafDecoder) {
|
||||
if decoder == nil {
|
||||
delete(leafDecoders, theType)
|
||||
} else {
|
||||
leafDecoders[theType] = decoder
|
||||
}
|
||||
}
|
||||
|
||||
// LeafDecoder is to be provided (via RegisterLeafDecoder above)
|
||||
// by additional wrapper types not yet known to this library.
|
||||
// A nil return indicates that decoding was not successful.
|
||||
type LeafDecoder = func(ctx context.Context, msg string, safeDetails []string, payload proto.Message) error
|
||||
|
||||
// registry for RegisterLeafDecoder.
|
||||
var leafDecoders = map[TypeKey]LeafDecoder{}
|
||||
|
||||
// RegisterWrapperDecoder can be used to register new wrapper types to
|
||||
// the library. Registered wrappers will be decoded using their own
|
||||
// Go type when an error is decoded. Wrappers that have not been
|
||||
// registered will be decoded using the opaqueWrapper type.
|
||||
//
|
||||
// Note: if the error type has been migrated from a previous location
|
||||
// or a different type, ensure that RegisterTypeMigration() was called
|
||||
// prior to RegisterWrapperDecoder().
|
||||
func RegisterWrapperDecoder(theType TypeKey, decoder WrapperDecoder) {
|
||||
if decoder == nil {
|
||||
delete(decoders, theType)
|
||||
} else {
|
||||
decoders[theType] = decoder
|
||||
}
|
||||
}
|
||||
|
||||
// WrapperDecoder is to be provided (via RegisterWrapperDecoder above)
|
||||
// by additional wrapper types not yet known to this library.
|
||||
// A nil return indicates that decoding was not successful.
|
||||
type WrapperDecoder = func(ctx context.Context, cause error, msgPrefix string, safeDetails []string, payload proto.Message) error
|
||||
|
||||
// registry for RegisterWrapperType.
|
||||
var decoders = map[TypeKey]WrapperDecoder{}
|
||||
|
||||
// MultiCauseDecoder is to be provided (via RegisterMultiCauseDecoder
|
||||
// above) by additional multi-cause wrapper types not yet known by the
|
||||
// library. A nil return indicates that decoding was not successful.
|
||||
type MultiCauseDecoder = func(ctx context.Context, causes []error, msgPrefix string, safeDetails []string, payload proto.Message) error
|
||||
|
||||
// registry for RegisterMultiCauseDecoder.
|
||||
var multiCauseDecoders = map[TypeKey]MultiCauseDecoder{}
|
||||
|
||||
// RegisterMultiCauseDecoder can be used to register new multi-cause
|
||||
// wrapper types to the library. Registered wrappers will be decoded
|
||||
// using their own Go type when an error is decoded. Multi-cause
|
||||
// wrappers that have not been registered will be decoded using the
|
||||
// opaqueWrapper type.
|
||||
func RegisterMultiCauseDecoder(theType TypeKey, decoder MultiCauseDecoder) {
|
||||
if decoder == nil {
|
||||
delete(multiCauseDecoders, theType)
|
||||
} else {
|
||||
multiCauseDecoders[theType] = decoder
|
||||
}
|
||||
}
|
||||
438
vendor/github.com/cockroachdb/errors/errbase/encode.go
generated
vendored
Normal file
438
vendor/github.com/cockroachdb/errors/errbase/encode.go
generated
vendored
Normal file
@@ -0,0 +1,438 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 errbase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/cockroachdb/errors/errorspb"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/gogo/protobuf/types"
|
||||
)
|
||||
|
||||
// EncodedError is the type of an encoded (and protobuf-encodable) error.
|
||||
type EncodedError = errorspb.EncodedError
|
||||
|
||||
// EncodeError encodes an error.
|
||||
func EncodeError(ctx context.Context, err error) EncodedError {
|
||||
if cause := UnwrapOnce(err); cause != nil {
|
||||
return encodeWrapper(ctx, err, cause)
|
||||
}
|
||||
return encodeLeaf(ctx, err, UnwrapMulti(err))
|
||||
}
|
||||
|
||||
// encodeLeaf encodes a leaf error. This function accepts a `causes`
|
||||
// argument because we encode multi-cause errors using the Leaf
|
||||
// protobuf. This was done to enable backwards compatibility when
|
||||
// introducing this functionality since the Wrapper type already has a
|
||||
// required single `cause` field.
|
||||
func encodeLeaf(ctx context.Context, err error, causes []error) EncodedError {
|
||||
var msg string
|
||||
var details errorspb.EncodedErrorDetails
|
||||
|
||||
if e, ok := err.(*opaqueLeaf); ok {
|
||||
msg = e.msg
|
||||
details = e.details
|
||||
} else if e, ok := err.(*opaqueLeafCauses); ok {
|
||||
msg = e.msg
|
||||
details = e.details
|
||||
} else {
|
||||
details.OriginalTypeName, details.ErrorTypeMark.FamilyName, details.ErrorTypeMark.Extension = getTypeDetails(err, false /*onlyFamily*/)
|
||||
|
||||
var payload proto.Message
|
||||
|
||||
// If we have a manually registered encoder, use that.
|
||||
typeKey := TypeKey(details.ErrorTypeMark.FamilyName)
|
||||
if enc, ok := leafEncoders[typeKey]; ok {
|
||||
msg, details.ReportablePayload, payload = enc(ctx, err)
|
||||
} else {
|
||||
// No encoder. Let's try to manually extract fields.
|
||||
|
||||
// The message comes from Error(). Simple.
|
||||
msg = err.Error()
|
||||
|
||||
// If there are known safe details, use them.
|
||||
if s, ok := err.(SafeDetailer); ok {
|
||||
details.ReportablePayload = s.SafeDetails()
|
||||
}
|
||||
|
||||
// If it's also a protobuf message, we'll use that as
|
||||
// payload. DecodeLeaf() will know how to turn that back into a
|
||||
// full error if there is no decoder.
|
||||
payload, _ = err.(proto.Message)
|
||||
}
|
||||
// If there is a detail payload, encode it.
|
||||
details.FullDetails = encodeAsAny(ctx, err, payload)
|
||||
}
|
||||
|
||||
var cs []*EncodedError
|
||||
if len(causes) > 0 {
|
||||
cs = make([]*EncodedError, len(causes))
|
||||
for i, ee := range causes {
|
||||
ee := EncodeError(ctx, ee)
|
||||
cs[i] = &ee
|
||||
}
|
||||
}
|
||||
|
||||
return EncodedError{
|
||||
Error: &errorspb.EncodedError_Leaf{
|
||||
Leaf: &errorspb.EncodedErrorLeaf{
|
||||
Message: msg,
|
||||
Details: details,
|
||||
MultierrorCauses: cs,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// warningFn can be overridden with a suitable logging function using
|
||||
// SetWarningFn() below.
|
||||
var warningFn = func(_ context.Context, format string, args ...interface{}) {
|
||||
log.Printf(format, args...)
|
||||
}
|
||||
|
||||
// SetWarningFn enables configuration of the warning function.
|
||||
func SetWarningFn(fn func(context.Context, string, ...interface{})) {
|
||||
warningFn = fn
|
||||
}
|
||||
|
||||
func encodeAsAny(ctx context.Context, err error, payload proto.Message) *types.Any {
|
||||
if payload == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
any, marshalErr := types.MarshalAny(payload)
|
||||
if marshalErr != nil {
|
||||
warningFn(ctx,
|
||||
"error %+v (%T) announces proto message, but marshaling fails: %+v",
|
||||
err, err, marshalErr)
|
||||
return nil
|
||||
}
|
||||
|
||||
return any
|
||||
}
|
||||
|
||||
// encodeWrapper encodes an error wrapper.
|
||||
func encodeWrapper(ctx context.Context, err, cause error) EncodedError {
|
||||
var msg string
|
||||
var details errorspb.EncodedErrorDetails
|
||||
messageType := Prefix
|
||||
|
||||
if e, ok := err.(*opaqueWrapper); ok {
|
||||
// We delegate all knowledge of the error string
|
||||
// to the original encoder and do not try to re-engineer
|
||||
// the prefix out of the error. This helps maintain
|
||||
// backward compatibility with earlier versions of the
|
||||
// encoder which don't have any understanding of
|
||||
// error string ownership by the wrapper.
|
||||
msg = e.prefix
|
||||
details = e.details
|
||||
messageType = e.messageType
|
||||
} else {
|
||||
details.OriginalTypeName, details.ErrorTypeMark.FamilyName, details.ErrorTypeMark.Extension = getTypeDetails(err, false /*onlyFamily*/)
|
||||
|
||||
var payload proto.Message
|
||||
|
||||
// If we have a manually registered encoder, use that.
|
||||
typeKey := TypeKey(details.ErrorTypeMark.FamilyName)
|
||||
if enc, ok := encoders[typeKey]; ok {
|
||||
msg, details.ReportablePayload, payload, messageType = enc(ctx, err)
|
||||
} else {
|
||||
// No encoder.
|
||||
// In that case, we'll try to compute a message prefix
|
||||
// manually.
|
||||
msg, messageType = extractPrefix(err, cause)
|
||||
|
||||
// If there are known safe details, use them.
|
||||
if s, ok := err.(SafeDetailer); ok {
|
||||
details.ReportablePayload = s.SafeDetails()
|
||||
}
|
||||
|
||||
// That's all we can get.
|
||||
}
|
||||
// If there is a detail payload, encode it.
|
||||
details.FullDetails = encodeAsAny(ctx, err, payload)
|
||||
}
|
||||
|
||||
return EncodedError{
|
||||
Error: &errorspb.EncodedError_Wrapper{
|
||||
Wrapper: &errorspb.EncodedWrapper{
|
||||
Cause: EncodeError(ctx, cause),
|
||||
Message: msg,
|
||||
Details: details,
|
||||
MessageType: errorspb.MessageType(messageType),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// extractPrefix extracts the prefix from a wrapper's error message.
|
||||
// For example,
|
||||
//
|
||||
// err := errors.New("bar")
|
||||
// err = errors.Wrap(err, "foo")
|
||||
// extractPrefix(err)
|
||||
//
|
||||
// returns "foo".
|
||||
//
|
||||
// If a presumed wrapper does not have a message prefix, it is assumed
|
||||
// to override the entire error message and `extractPrefix` returns
|
||||
// the entire message and the boolean `true` to signify that the causes
|
||||
// should not be appended to it.
|
||||
func extractPrefix(err, cause error) (string, MessageType) {
|
||||
causeSuffix := cause.Error()
|
||||
errMsg := err.Error()
|
||||
|
||||
if strings.HasSuffix(errMsg, causeSuffix) {
|
||||
prefix := errMsg[:len(errMsg)-len(causeSuffix)]
|
||||
// If error msg matches exactly then this is a wrapper
|
||||
// with no message of its own.
|
||||
if len(prefix) == 0 {
|
||||
return "", Prefix
|
||||
}
|
||||
if strings.HasSuffix(prefix, ": ") {
|
||||
return prefix[:len(prefix)-2], Prefix
|
||||
}
|
||||
}
|
||||
// If we don't have the cause as a suffix, then we have
|
||||
// some other string as our error msg, preserve that and
|
||||
// mark as override
|
||||
return errMsg, FullMessage
|
||||
}
|
||||
|
||||
func getTypeDetails(
|
||||
err error, onlyFamily bool,
|
||||
) (origTypeName string, typeKeyFamily string, typeKeyExtension string) {
|
||||
// If we have received an error of type not known locally,
|
||||
// we still know its type name. Return that.
|
||||
switch t := err.(type) {
|
||||
case *opaqueLeaf:
|
||||
return t.details.OriginalTypeName, t.details.ErrorTypeMark.FamilyName, t.details.ErrorTypeMark.Extension
|
||||
case *opaqueLeafCauses:
|
||||
return t.details.OriginalTypeName, t.details.ErrorTypeMark.FamilyName, t.details.ErrorTypeMark.Extension
|
||||
case *opaqueWrapper:
|
||||
return t.details.OriginalTypeName, t.details.ErrorTypeMark.FamilyName, t.details.ErrorTypeMark.Extension
|
||||
}
|
||||
|
||||
// Compute the full error name, for reporting and printing details.
|
||||
tn := getFullTypeName(err)
|
||||
// Compute a family name, used to find decoders and to compare error identities.
|
||||
fm := tn
|
||||
if prevKey, ok := backwardRegistry[TypeKey(tn)]; ok {
|
||||
fm = string(prevKey)
|
||||
}
|
||||
|
||||
if onlyFamily {
|
||||
return tn, fm, ""
|
||||
}
|
||||
|
||||
// If the error has an extra type marker, add it.
|
||||
// This is not used by the base functionality but
|
||||
// is hooked into by the barrier subsystem.
|
||||
var em string
|
||||
if tm, ok := err.(TypeKeyMarker); ok {
|
||||
em = tm.ErrorKeyMarker()
|
||||
}
|
||||
return tn, fm, em
|
||||
}
|
||||
|
||||
// TypeKeyMarker can be implemented by errors that wish to extend
|
||||
// their type name as seen by GetTypeKey().
|
||||
//
|
||||
// Note: the key marker is considered safe for reporting and
|
||||
// is included in sentry reports.
|
||||
type TypeKeyMarker interface {
|
||||
ErrorKeyMarker() string
|
||||
}
|
||||
|
||||
func getFullTypeName(err error) string {
|
||||
t := reflect.TypeOf(err)
|
||||
pkgPath := getPkgPath(t)
|
||||
return makeTypeKey(pkgPath, t.String())
|
||||
}
|
||||
|
||||
func makeTypeKey(pkgPath, typeNameString string) string {
|
||||
return pkgPath + "/" + typeNameString
|
||||
}
|
||||
|
||||
// getPkgPath extract the package path for a Go type. We'll do some
|
||||
// extra work for typical types that did not get a name, for example
|
||||
// *E has the package path of E.
|
||||
func getPkgPath(t reflect.Type) string {
|
||||
pkgPath := t.PkgPath()
|
||||
if pkgPath != "" {
|
||||
return pkgPath
|
||||
}
|
||||
// Try harder.
|
||||
switch t.Kind() {
|
||||
case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
return getPkgPath(t.Elem())
|
||||
}
|
||||
// Nothing to report.
|
||||
return ""
|
||||
}
|
||||
|
||||
// TypeKey identifies an error for the purpose of looking up decoders.
|
||||
// It is equivalent to the "family name" in ErrorTypeMarker.
|
||||
type TypeKey string
|
||||
|
||||
// GetTypeKey retrieve the type key for a given error object. This
|
||||
// is meant for use in combination with the Register functions.
|
||||
func GetTypeKey(err error) TypeKey {
|
||||
_, familyName, _ := getTypeDetails(err, true /*onlyFamily*/)
|
||||
return TypeKey(familyName)
|
||||
}
|
||||
|
||||
// GetTypeMark retrieves the ErrorTypeMark for a given error object.
|
||||
// This is meant for use in the markers sub-package.
|
||||
func GetTypeMark(err error) errorspb.ErrorTypeMark {
|
||||
_, familyName, extension := getTypeDetails(err, false /*onlyFamily*/)
|
||||
return errorspb.ErrorTypeMark{FamilyName: familyName, Extension: extension}
|
||||
}
|
||||
|
||||
// RegisterLeafEncoder can be used to register new leaf error types to
|
||||
// the library. Registered types will be encoded using their own
|
||||
// Go type when an error is encoded. Wrappers that have not been
|
||||
// registered will be encoded using the opaqueLeaf type.
|
||||
//
|
||||
// Note: if the error type has been migrated from a previous location
|
||||
// or a different type, ensure that RegisterTypeMigration() was called
|
||||
// prior to RegisterLeafEncoder().
|
||||
func RegisterLeafEncoder(theType TypeKey, encoder LeafEncoder) {
|
||||
if encoder == nil {
|
||||
delete(leafEncoders, theType)
|
||||
} else {
|
||||
leafEncoders[theType] = encoder
|
||||
}
|
||||
}
|
||||
|
||||
// LeafEncoder is to be provided (via RegisterLeafEncoder above)
|
||||
// by additional wrapper types not yet known to this library.
|
||||
type LeafEncoder = func(ctx context.Context, err error) (msg string, safeDetails []string, payload proto.Message)
|
||||
|
||||
// registry for RegisterLeafEncoder.
|
||||
var leafEncoders = map[TypeKey]LeafEncoder{}
|
||||
|
||||
// RegisterMultiCauseEncoder can be used to register new multi-cause
|
||||
// error types to the library. Registered types will be encoded using
|
||||
// their own Go type when an error is encoded. Multi-cause wrappers
|
||||
// that have not been registered will be encoded using the
|
||||
// opaqueWrapper type.
|
||||
func RegisterMultiCauseEncoder(theType TypeKey, encoder MultiCauseEncoder) {
|
||||
// This implementation is a simple wrapper around `LeafEncoder`
|
||||
// because we implemented multi-cause error wrapper encoding into a
|
||||
// `Leaf` instead of a `Wrapper` for smoother backwards
|
||||
// compatibility support. Exposing this detail to consumers of the
|
||||
// API is confusing and hence avoided. The causes of the error are
|
||||
// encoded separately regardless of this encoder's implementation.
|
||||
RegisterLeafEncoder(theType, encoder)
|
||||
}
|
||||
|
||||
// MultiCauseEncoder is to be provided (via RegisterMultiCauseEncoder
|
||||
// above) by additional multi-cause wrapper types not yet known to this
|
||||
// library. The encoder will automatically extract and encode the
|
||||
// causes of this error by calling `Unwrap()` and expecting a slice of
|
||||
// errors.
|
||||
type MultiCauseEncoder = func(ctx context.Context, err error) (msg string, safeDetails []string, payload proto.Message)
|
||||
|
||||
// RegisterWrapperEncoder can be used to register new wrapper types to
|
||||
// the library. Registered wrappers will be encoded using their own
|
||||
// Go type when an error is encoded. Wrappers that have not been
|
||||
// registered will be encoded using the opaqueWrapper type.
|
||||
//
|
||||
// Note: if the error type has been migrated from a previous location
|
||||
// or a different type, ensure that RegisterTypeMigration() was called
|
||||
// prior to RegisterWrapperEncoder().
|
||||
func RegisterWrapperEncoder(theType TypeKey, encoder WrapperEncoder) {
|
||||
RegisterWrapperEncoderWithMessageType(
|
||||
theType,
|
||||
func(ctx context.Context, err error) (
|
||||
msgPrefix string,
|
||||
safeDetails []string,
|
||||
payload proto.Message,
|
||||
messageType MessageType,
|
||||
) {
|
||||
prefix, details, payload := encoder(ctx, err)
|
||||
return prefix, details, payload, messageType
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterWrapperEncoderWithMessageType can be used to register
|
||||
// new wrapper types to the library. Registered wrappers will be
|
||||
// encoded using their own Go type when an error is encoded. Wrappers
|
||||
// that have not been registered will be encoded using the
|
||||
// opaqueWrapper type.
|
||||
//
|
||||
// This function differs from RegisterWrapperEncoder by allowing the
|
||||
// caller to explicitly decide whether the wrapper owns the entire
|
||||
// error message or not. Otherwise, the relationship is inferred.
|
||||
//
|
||||
// Note: if the error type has been migrated from a previous location
|
||||
// or a different type, ensure that RegisterTypeMigration() was called
|
||||
// prior to RegisterWrapperEncoder().
|
||||
func RegisterWrapperEncoderWithMessageType(
|
||||
theType TypeKey, encoder WrapperEncoderWithMessageType,
|
||||
) {
|
||||
if encoder == nil {
|
||||
delete(encoders, theType)
|
||||
} else {
|
||||
encoders[theType] = encoder
|
||||
}
|
||||
}
|
||||
|
||||
// WrapperEncoder is to be provided (via RegisterWrapperEncoder above)
|
||||
// by additional wrapper types not yet known to this library.
|
||||
type WrapperEncoder func(ctx context.Context, err error) (
|
||||
msgPrefix string,
|
||||
safeDetails []string,
|
||||
payload proto.Message,
|
||||
)
|
||||
|
||||
// MessageType is used to encode information about an error message
|
||||
// within a wrapper error type. This information is used to affect
|
||||
// display logic.
|
||||
type MessageType errorspb.MessageType
|
||||
|
||||
// Values below should match the ones in errorspb.MessageType for
|
||||
// direct conversion.
|
||||
const (
|
||||
// Prefix denotes an error message that should be prepended to the
|
||||
// message of its cause.
|
||||
Prefix MessageType = MessageType(errorspb.MessageType_PREFIX)
|
||||
// FullMessage denotes an error message that contains the text of its
|
||||
// causes and can be displayed standalone.
|
||||
FullMessage = MessageType(errorspb.MessageType_FULL_MESSAGE)
|
||||
)
|
||||
|
||||
// WrapperEncoderWithMessageType is to be provided (via
|
||||
// RegisterWrapperEncoderWithMessageType above) by additional wrapper
|
||||
// types not yet known to this library. This encoder returns an
|
||||
// additional enum which indicates whether the wrapper owns the error
|
||||
// message completely instead of simply being a prefix with the error
|
||||
// message of its causes appended to it. This information is encoded
|
||||
// along with the prefix in order to provide context during error
|
||||
// display.
|
||||
type WrapperEncoderWithMessageType func(ctx context.Context, err error) (
|
||||
msgPrefix string,
|
||||
safeDetails []string,
|
||||
payload proto.Message,
|
||||
messageType MessageType,
|
||||
)
|
||||
|
||||
// registry for RegisterWrapperType.
|
||||
var encoders = map[TypeKey]WrapperEncoderWithMessageType{}
|
||||
990
vendor/github.com/cockroachdb/errors/errbase/format_error.go
generated
vendored
Normal file
990
vendor/github.com/cockroachdb/errors/errbase/format_error.go
generated
vendored
Normal file
@@ -0,0 +1,990 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// This file is forked and modified from golang.org/x/xerrors,
|
||||
// at commit 3ee3066db522c6628d440a3a91c4abdd7f5ef22f (2019-05-10).
|
||||
// From the original code:
|
||||
// Copyright 2018 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.
|
||||
//
|
||||
// Changes specific to this fork marked as inline comments.
|
||||
|
||||
package errbase
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/cockroachdb/redact"
|
||||
"github.com/kr/pretty"
|
||||
pkgErr "github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// FormatError formats an error according to s and verb.
|
||||
// This is a helper meant for use when implementing the fmt.Formatter
|
||||
// interface on custom error objects.
|
||||
//
|
||||
// If the error implements errors.Formatter, FormatError calls its
|
||||
// FormatError method of f with an errors.Printer configured according
|
||||
// to s and verb, and writes the result to s.
|
||||
//
|
||||
// Otherwise, if it is a wrapper, FormatError prints out its error prefix,
|
||||
// then recurses on its cause.
|
||||
//
|
||||
// Otherwise, its Error() text is printed.
|
||||
func FormatError(err error, s fmt.State, verb rune) {
|
||||
formatErrorInternal(err, s, verb, false /* redactableOutput */)
|
||||
}
|
||||
|
||||
// FormatRedactableError formats an error as a safe object.
|
||||
//
|
||||
// Note that certain verb/flags combinations are currently not
|
||||
// supported, and result in a rendering that considers the entire
|
||||
// object as unsafe. For example, %q, %#v are not yet supported.
|
||||
func FormatRedactableError(err error, s redact.SafePrinter, verb rune) {
|
||||
formatErrorInternal(err, s, verb, true /* redactable */)
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Also inform the redact package of how to print an error
|
||||
// safely. This is used when an error is passed as argument
|
||||
// to one of the redact print functions.
|
||||
redact.RegisterRedactErrorFn(FormatRedactableError)
|
||||
}
|
||||
|
||||
// Formattable wraps an error into a fmt.Formatter which
|
||||
// will provide "smart" formatting even if the outer layer
|
||||
// of the error does not implement the Formatter interface.
|
||||
func Formattable(err error) fmt.Formatter {
|
||||
return &errorFormatter{err}
|
||||
}
|
||||
|
||||
// formatErrorInternal is the shared logic between FormatError
|
||||
// and FormatErrorRedactable.
|
||||
//
|
||||
// When the redactableOutput argument is true, the fmt.State argument
|
||||
// is really a redact.SafePrinter and casted down as necessary.
|
||||
//
|
||||
// If verb and flags are not one of the supported error formatting
|
||||
// combinations (in particular, %q, %#v etc), then the redactableOutput
|
||||
// argument is ignored. This limitation may be lifted in a later
|
||||
// version.
|
||||
func formatErrorInternal(err error, s fmt.State, verb rune, redactableOutput bool) {
|
||||
// Assuming this function is only called from the Format method, and given
|
||||
// that FormatError takes precedence over Format, it cannot be called from
|
||||
// any package that supports errors.Formatter. It is therefore safe to
|
||||
// disregard that State may be a specific printer implementation and use one
|
||||
// of our choice instead.
|
||||
|
||||
p := state{State: s, redactableOutput: redactableOutput}
|
||||
|
||||
switch {
|
||||
case verb == 'v' && s.Flag('+') && !s.Flag('#'):
|
||||
// Here we are going to format as per %+v, into p.buf.
|
||||
//
|
||||
// We need to start with the innermost (root cause) error first,
|
||||
// then the layers of wrapping from innermost to outermost, so as
|
||||
// to enable stack trace de-duplication. This requires a
|
||||
// post-order traversal. Since we have a linked list, the best we
|
||||
// can do is a recursion.
|
||||
p.formatRecursive(
|
||||
err,
|
||||
true, /* isOutermost */
|
||||
true, /* withDetail */
|
||||
false, /* withDepth */
|
||||
0, /* depth */
|
||||
)
|
||||
|
||||
// We now have all the data, we can render the result.
|
||||
p.formatEntries(err)
|
||||
|
||||
// We're done formatting. Apply width/precision parameters.
|
||||
p.finishDisplay(verb)
|
||||
|
||||
case !redactableOutput && verb == 'v' && s.Flag('#'):
|
||||
// We only know how to process %#v if redactable output is not
|
||||
// requested. This is because the structured output may emit
|
||||
// arbitrary unsafe strings without redaction markers,
|
||||
// or improperly balanced/escaped redaction markers.
|
||||
if stringer, ok := err.(fmt.GoStringer); ok {
|
||||
io.WriteString(&p.finalBuf, stringer.GoString())
|
||||
} else {
|
||||
// Not a GoStringer: delegate to the pretty library.
|
||||
fmt.Fprintf(&p.finalBuf, "%# v", pretty.Formatter(err))
|
||||
}
|
||||
p.finishDisplay(verb)
|
||||
|
||||
case verb == 's' ||
|
||||
// We only handle %v/%+v or other combinations here; %#v is unsupported.
|
||||
(verb == 'v' && !s.Flag('#')) ||
|
||||
// If redactable output is not requested, then we also
|
||||
// know how to format %x/%X (print bytes of error message in hex)
|
||||
// and %q (quote the result).
|
||||
// If redactable output is requested, then we don't know
|
||||
// how to perform these exotic verbs, because they
|
||||
// may muck with the redaction markers. In this case,
|
||||
// we simply refuse the format as per the default clause below.
|
||||
(!redactableOutput && (verb == 'x' || verb == 'X' || verb == 'q')):
|
||||
// Only the error message.
|
||||
//
|
||||
// Use an intermediate buffer because there may be alignment
|
||||
// instructions to obey in the final rendering or
|
||||
// quotes to add (for %q).
|
||||
//
|
||||
// Conceptually, we could just do
|
||||
// p.buf.WriteString(err.Error())
|
||||
// However we also advertise that Error() can be implemented
|
||||
// by calling FormatError(), in which case we'd get an infinite
|
||||
// recursion. So we have no choice but to peel the data
|
||||
// and then assemble the pieces ourselves.
|
||||
p.formatRecursive(
|
||||
err,
|
||||
true, /* isOutermost */
|
||||
false, /* withDetail */
|
||||
false, /* withDepth */
|
||||
0, /* depth */
|
||||
)
|
||||
p.formatSingleLineOutput()
|
||||
p.finishDisplay(verb)
|
||||
|
||||
default:
|
||||
// Unknown verb. Do like fmt.Printf and tell the user we're
|
||||
// confused.
|
||||
//
|
||||
// Note that the following logic is correct regardless of the
|
||||
// value of 'redactableOutput', because the display of the verb and type
|
||||
// are always safe for redaction. If/when this code is changed to
|
||||
// print more details, care is to be taken to add redaction
|
||||
// markers if s.redactableOutput is set.
|
||||
p.finalBuf.WriteString("%!")
|
||||
p.finalBuf.WriteRune(verb)
|
||||
p.finalBuf.WriteByte('(')
|
||||
switch {
|
||||
case err != nil:
|
||||
p.finalBuf.WriteString(reflect.TypeOf(err).String())
|
||||
default:
|
||||
p.finalBuf.WriteString("<nil>")
|
||||
}
|
||||
p.finalBuf.WriteByte(')')
|
||||
io.Copy(s, &p.finalBuf)
|
||||
}
|
||||
}
|
||||
|
||||
// formatEntries reads the entries from s.entries and produces a
|
||||
// detailed rendering in s.finalBuf.
|
||||
//
|
||||
// Note that if s.redactableOutput is true, s.finalBuf is to contain a
|
||||
// RedactableBytes. However, we are not using the helper facilities
|
||||
// from redact.SafePrinter to do this, so care should be taken below
|
||||
// to properly escape markers, etc.
|
||||
func (s *state) formatEntries(err error) {
|
||||
// The first entry at the top is special. We format it as follows:
|
||||
//
|
||||
// <complete error message>
|
||||
// (1) <details>
|
||||
s.formatSingleLineOutput()
|
||||
s.finalBuf.WriteString("\n(1)")
|
||||
|
||||
s.printEntry(s.entries[len(s.entries)-1])
|
||||
|
||||
// All the entries that follow are printed as follows:
|
||||
//
|
||||
// Wraps: (N) <details>
|
||||
//
|
||||
for i, j := len(s.entries)-2, 2; i >= 0; i, j = i-1, j+1 {
|
||||
s.finalBuf.WriteByte('\n')
|
||||
// Extra indentation starts at depth==2 because the direct
|
||||
// children of the root error area already printed on separate
|
||||
// newlines.
|
||||
for m := 0; m < s.entries[i].depth-1; m += 1 {
|
||||
if m == s.entries[i].depth-2 {
|
||||
s.finalBuf.WriteString("└─ ")
|
||||
} else {
|
||||
s.finalBuf.WriteByte(' ')
|
||||
s.finalBuf.WriteByte(' ')
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(&s.finalBuf, "Wraps: (%d)", j)
|
||||
entry := s.entries[i]
|
||||
s.printEntry(entry)
|
||||
}
|
||||
|
||||
// At the end, we link all the (N) references to the Go type of the
|
||||
// error.
|
||||
s.finalBuf.WriteString("\nError types:")
|
||||
for i, j := len(s.entries)-1, 1; i >= 0; i, j = i-1, j+1 {
|
||||
fmt.Fprintf(&s.finalBuf, " (%d) %T", j, s.entries[i].err)
|
||||
}
|
||||
}
|
||||
|
||||
// printEntry renders the entry given as argument
|
||||
// into s.finalBuf.
|
||||
//
|
||||
// If s.redactableOutput is set, then s.finalBuf is to contain
|
||||
// a RedactableBytes, with redaction markers. In that
|
||||
// case, we must be careful to escape (or not) the entry
|
||||
// depending on entry.redactable.
|
||||
//
|
||||
// If s.redactableOutput is unset, then we are not caring about
|
||||
// redactability. In that case entry.redactable is not set
|
||||
// anyway and we can pass contents through.
|
||||
func (s *state) printEntry(entry formatEntry) {
|
||||
if len(entry.head) > 0 {
|
||||
if entry.head[0] != '\n' {
|
||||
s.finalBuf.WriteByte(' ')
|
||||
}
|
||||
if len(entry.head) > 0 {
|
||||
if !s.redactableOutput || entry.redactable {
|
||||
// If we don't care about redaction, then we can pass the string
|
||||
// through.
|
||||
//
|
||||
// If we do care about redaction, and entry.redactable is true,
|
||||
// then entry.head is already a RedactableBytes. Then we can
|
||||
// also pass it through.
|
||||
s.finalBuf.Write(entry.head)
|
||||
} else {
|
||||
// We care about redaction, and the head is unsafe. Escape it
|
||||
// and enclose the result within redaction markers.
|
||||
s.finalBuf.Write([]byte(redact.EscapeBytes(entry.head)))
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(entry.details) > 0 {
|
||||
if len(entry.head) == 0 {
|
||||
if entry.details[0] != '\n' {
|
||||
s.finalBuf.WriteByte(' ')
|
||||
}
|
||||
}
|
||||
if !s.redactableOutput || entry.redactable {
|
||||
// If we don't care about redaction, then we can pass the string
|
||||
// through.
|
||||
//
|
||||
// If we do care about redaction, and entry.redactable is true,
|
||||
// then entry.details is already a RedactableBytes. Then we can
|
||||
// also pass it through.
|
||||
s.finalBuf.Write(entry.details)
|
||||
} else {
|
||||
// We care about redaction, and the details are unsafe. Escape
|
||||
// them and enclose the result within redaction markers.
|
||||
s.finalBuf.Write([]byte(redact.EscapeBytes(entry.details)))
|
||||
}
|
||||
}
|
||||
if entry.stackTrace != nil {
|
||||
s.finalBuf.WriteString("\n -- stack trace:")
|
||||
s.finalBuf.WriteString(strings.ReplaceAll(
|
||||
fmt.Sprintf("%+v", entry.stackTrace),
|
||||
"\n", string(detailSep)))
|
||||
if entry.elidedStackTrace {
|
||||
fmt.Fprintf(&s.finalBuf, "%s[...repeated from below...]", detailSep)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// formatSingleLineOutput prints the details extracted via
|
||||
// formatRecursive() through the chain of errors as if .Error() has
|
||||
// been called: it only prints the non-detail parts and prints them on
|
||||
// one line with ": " separators.
|
||||
//
|
||||
// This function is used both when FormatError() is called indirectly
|
||||
// from .Error(), e.g. in:
|
||||
//
|
||||
// (e *myType) Error() { return fmt.Sprintf("%v", e) }
|
||||
// (e *myType) Format(s fmt.State, verb rune) { errors.FormatError(s, verb, e) }
|
||||
//
|
||||
// and also to print the first line in the output of a %+v format.
|
||||
//
|
||||
// It reads from s.entries and writes to s.finalBuf.
|
||||
// s.buf is left untouched.
|
||||
//
|
||||
// Note that if s.redactableOutput is true, s.finalBuf is to contain a
|
||||
// RedactableBytes. However, we are not using the helper facilities
|
||||
// from redact.SafePrinter to do this, so care should be taken below
|
||||
// to properly escape markers, etc.
|
||||
func (s *state) formatSingleLineOutput() {
|
||||
for i := len(s.entries) - 1; i >= 0; i-- {
|
||||
entry := &s.entries[i]
|
||||
if entry.elideShort {
|
||||
continue
|
||||
}
|
||||
if s.finalBuf.Len() > 0 && len(entry.head) > 0 {
|
||||
s.finalBuf.WriteString(": ")
|
||||
}
|
||||
if len(entry.head) == 0 {
|
||||
// shortcut, to avoid the copy below.
|
||||
continue
|
||||
}
|
||||
if !s.redactableOutput || entry.redactable {
|
||||
// If we don't care about redaction, then we can pass the string
|
||||
// through.
|
||||
//
|
||||
// If we do care about redaction, and entry.redactable is true,
|
||||
// then entry.head is already a RedactableBytes. Then we can
|
||||
// also pass it through.
|
||||
s.finalBuf.Write(entry.head)
|
||||
} else {
|
||||
// We do care about redaction, but entry.redactable is unset.
|
||||
// This means entry.head is unsafe. We need to escape it.
|
||||
s.finalBuf.Write([]byte(redact.EscapeBytes(entry.head)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// formatRecursive performs a post-order traversal on the chain of
|
||||
// errors to collect error details from innermost to outermost.
|
||||
//
|
||||
// It uses s.buf as an intermediate buffer to collect strings.
|
||||
// It populates s.entries as a result.
|
||||
// Between each layer of error, s.buf is reset.
|
||||
//
|
||||
// s.finalBuf is untouched. The conversion of s.entries
|
||||
// to s.finalBuf is done by formatSingleLineOutput() and/or
|
||||
// formatEntries().
|
||||
//
|
||||
// `withDepth` and `depth` are used to tag subtrees of multi-cause
|
||||
// errors for added indentation during printing. Once a multi-cause
|
||||
// error is encountered, all subsequent calls with set `withDepth` to
|
||||
// true, and increment `depth` during recursion. This information is
|
||||
// persisted into the generated entries and used later to display the
|
||||
// error with increased indentation based in the depth.
|
||||
func (s *state) formatRecursive(err error, isOutermost, withDetail, withDepth bool, depth int) int {
|
||||
cause := UnwrapOnce(err)
|
||||
numChildren := 0
|
||||
if cause != nil {
|
||||
// Recurse first, which populates entries list starting from innermost
|
||||
// entry. If we've previously seen a multi-cause wrapper, `withDepth`
|
||||
// will be true, and we'll record the depth below ensuring that extra
|
||||
// indentation is applied to this inner cause during printing.
|
||||
// Otherwise, we maintain "straight" vertical formatting by keeping the
|
||||
// parent callers `withDepth` value of `false` by default.
|
||||
numChildren += s.formatRecursive(cause, false, withDetail, withDepth, depth+1)
|
||||
}
|
||||
|
||||
causes := UnwrapMulti(err)
|
||||
for _, c := range causes {
|
||||
// Override `withDepth` to true for all child entries ensuring they have
|
||||
// indentation applied during formatting to distinguish them from
|
||||
// parents.
|
||||
numChildren += s.formatRecursive(c, false, withDetail, true, depth+1)
|
||||
}
|
||||
// inserted := len(s.entries) - 1 - startChildren
|
||||
|
||||
// Reinitialize the state for this stage of wrapping.
|
||||
s.wantDetail = withDetail
|
||||
s.needSpace = false
|
||||
s.needNewline = 0
|
||||
s.multiLine = false
|
||||
s.notEmpty = false
|
||||
s.hasDetail = false
|
||||
s.headBuf = nil
|
||||
|
||||
seenTrace := false
|
||||
|
||||
bufIsRedactable := false
|
||||
|
||||
switch v := err.(type) {
|
||||
case SafeFormatter:
|
||||
bufIsRedactable = true
|
||||
desiredShortening := v.SafeFormatError((*safePrinter)(s))
|
||||
if desiredShortening == nil {
|
||||
// The error wants to elide the short messages from inner causes.
|
||||
// Read backwards through list of entries up to the number of new
|
||||
// entries created "under" this one amount and mark `elideShort`
|
||||
// true.
|
||||
s.elideShortChildren(numChildren)
|
||||
}
|
||||
|
||||
case Formatter:
|
||||
desiredShortening := v.FormatError((*printer)(s))
|
||||
if desiredShortening == nil {
|
||||
// The error wants to elide the short messages from inner
|
||||
// causes. Do it.
|
||||
s.elideShortChildren(numChildren)
|
||||
}
|
||||
|
||||
case fmt.Formatter:
|
||||
// We can only use a fmt.Formatter when both the following
|
||||
// conditions are true:
|
||||
// - when it is the leaf error, because a fmt.Formatter
|
||||
// on a wrapper also recurses.
|
||||
// - when it is not the outermost wrapper, because
|
||||
// the Format() method is likely to be calling FormatError()
|
||||
// to do its job and we want to avoid an infinite recursion.
|
||||
if !isOutermost && cause == nil {
|
||||
v.Format(s, 'v')
|
||||
if st, ok := err.(StackTraceProvider); ok {
|
||||
// This is likely a leaf error from github/pkg/errors.
|
||||
// The thing probably printed its stack trace on its own.
|
||||
seenTrace = true
|
||||
// We'll subsequently simplify stack traces in wrappers.
|
||||
s.lastStack = st.StackTrace()
|
||||
}
|
||||
} else {
|
||||
if elideCauseMsg := s.formatSimple(err, cause); elideCauseMsg {
|
||||
// The error wants to elide the short messages from inner
|
||||
// causes. Do it.
|
||||
s.elideShortChildren(numChildren)
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
// Handle the special case overrides for context.Canceled,
|
||||
// os.PathError, etc for which we know how to extract some safe
|
||||
// strings.
|
||||
//
|
||||
// We need to do this in the `default` branch, instead of doing
|
||||
// this above the switch, because the special handler could call a
|
||||
// .Error() that delegates its implementation to fmt.Formatter,
|
||||
// errors.Safeformatter or errors.Formattable, which brings us
|
||||
// back to this method in a call cycle. So we need to handle the
|
||||
// various interfaces first.
|
||||
printDone := false
|
||||
for _, fn := range specialCases {
|
||||
if handled, desiredShortening := fn(err, (*safePrinter)(s), cause == nil /* leaf */); handled {
|
||||
printDone = true
|
||||
bufIsRedactable = true
|
||||
if desiredShortening == nil {
|
||||
// The error wants to elide the short messages from inner
|
||||
// causes. Do it.
|
||||
s.elideShortChildren(numChildren)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if !printDone {
|
||||
// If the error did not implement errors.Formatter nor
|
||||
// fmt.Formatter, but it is a wrapper, still attempt best effort:
|
||||
// print what we can at this level.
|
||||
elideChildren := s.formatSimple(err, cause)
|
||||
// always elideChildren when dealing with multi-cause errors.
|
||||
if len(causes) > 0 {
|
||||
elideChildren = true
|
||||
}
|
||||
if elideChildren {
|
||||
// The error wants to elide the short messages from inner
|
||||
// causes. Do it.
|
||||
s.elideShortChildren(numChildren)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect the result.
|
||||
entry := s.collectEntry(err, bufIsRedactable, withDepth, depth)
|
||||
|
||||
// If there's an embedded stack trace, also collect it.
|
||||
// This will get either a stack from pkg/errors, or ours.
|
||||
if !seenTrace {
|
||||
if st, ok := err.(StackTraceProvider); ok {
|
||||
entry.stackTrace, entry.elidedStackTrace = ElideSharedStackTraceSuffix(s.lastStack, st.StackTrace())
|
||||
s.lastStack = entry.stackTrace
|
||||
}
|
||||
}
|
||||
|
||||
// Remember the entry for later rendering.
|
||||
s.entries = append(s.entries, entry)
|
||||
s.buf = bytes.Buffer{}
|
||||
|
||||
return numChildren + 1
|
||||
}
|
||||
|
||||
// elideShortChildren takes a number of entries to set `elideShort` to
|
||||
// false. The reason a number of entries is needed is that we may be
|
||||
// eliding a subtree of causes in the case of a multi-cause error. In
|
||||
// the multi-cause case, we need to know how many of the prior errors
|
||||
// in the list of entries is a child of this subtree.
|
||||
func (s *state) elideShortChildren(newEntries int) {
|
||||
for i := 0; i < newEntries; i++ {
|
||||
s.entries[len(s.entries)-1-i].elideShort = true
|
||||
}
|
||||
}
|
||||
|
||||
func (s *state) collectEntry(err error, bufIsRedactable bool, withDepth bool, depth int) formatEntry {
|
||||
entry := formatEntry{err: err}
|
||||
if s.wantDetail {
|
||||
// The buffer has been populated as a result of formatting with
|
||||
// %+v. In that case, if the printer has separated detail
|
||||
// from non-detail, we can use the split.
|
||||
if s.hasDetail {
|
||||
entry.head = s.headBuf
|
||||
entry.details = s.buf.Bytes()
|
||||
} else {
|
||||
entry.head = s.buf.Bytes()
|
||||
}
|
||||
} else {
|
||||
entry.head = s.headBuf
|
||||
if len(entry.head) > 0 && entry.head[len(entry.head)-1] != '\n' &&
|
||||
s.buf.Len() > 0 && s.buf.Bytes()[0] != '\n' {
|
||||
entry.head = append(entry.head, '\n')
|
||||
}
|
||||
entry.head = append(entry.head, s.buf.Bytes()...)
|
||||
}
|
||||
|
||||
if bufIsRedactable {
|
||||
// In this case, we've produced entry.head/entry.details using a
|
||||
// SafeFormatError() invocation. The strings in
|
||||
// entry.head/entry.detail contain redaction markers at this
|
||||
// point.
|
||||
if s.redactableOutput {
|
||||
// Redaction markers desired in the final output. Keep the
|
||||
// redaction markers.
|
||||
entry.redactable = true
|
||||
} else {
|
||||
// Markers not desired in the final output: strip the markers.
|
||||
entry.head = redact.RedactableBytes(entry.head).StripMarkers()
|
||||
entry.details = redact.RedactableBytes(entry.details).StripMarkers()
|
||||
}
|
||||
}
|
||||
|
||||
if withDepth {
|
||||
entry.depth = depth
|
||||
}
|
||||
|
||||
return entry
|
||||
}
|
||||
|
||||
// safeErrorPrinterFn is the type of a function that can take
|
||||
// over the safe printing of an error. This is used to inject special
|
||||
// cases into the formatting in errutil. We need this machinery to
|
||||
// prevent import cycles.
|
||||
type safeErrorPrinterFn = func(err error, p Printer, isLeaf bool) (handled bool, next error)
|
||||
|
||||
// specialCases is a list of functions to apply for special cases.
|
||||
var specialCases []safeErrorPrinterFn
|
||||
|
||||
// RegisterSpecialCasePrinter registers a handler.
|
||||
func RegisterSpecialCasePrinter(fn safeErrorPrinterFn) {
|
||||
specialCases = append(specialCases, fn)
|
||||
}
|
||||
|
||||
// formatSimple performs a best effort at extracting the details at a
|
||||
// given level of wrapping when the error object does not implement
|
||||
// the Formatter interface.
|
||||
// Returns true if we want to elide errors from causal chain.
|
||||
func (s *state) formatSimple(err, cause error) bool {
|
||||
var pref string
|
||||
elideCauses := false
|
||||
if cause != nil {
|
||||
var messageType MessageType
|
||||
pref, messageType = extractPrefix(err, cause)
|
||||
if messageType == FullMessage {
|
||||
elideCauses = true
|
||||
}
|
||||
} else {
|
||||
pref = err.Error()
|
||||
}
|
||||
if len(pref) > 0 {
|
||||
s.Write([]byte(pref))
|
||||
}
|
||||
return elideCauses
|
||||
}
|
||||
|
||||
// finishDisplay renders s.finalBuf into s.State.
|
||||
func (p *state) finishDisplay(verb rune) {
|
||||
if p.redactableOutput {
|
||||
// If we're rendering in redactable form, then s.finalBuf contains
|
||||
// a RedactableBytes. We can emit that directly.
|
||||
sp := p.State.(redact.SafePrinter)
|
||||
sp.Print(redact.RedactableBytes(p.finalBuf.Bytes()))
|
||||
return
|
||||
}
|
||||
// Not redactable: render depending on flags and verb.
|
||||
|
||||
width, okW := p.Width()
|
||||
_, okP := p.Precision()
|
||||
|
||||
// If `direct` is set to false, then the buffer is always
|
||||
// passed through fmt.Printf regardless of the width and alignment
|
||||
// settings. This is important for e.g. %q where quotes must be added
|
||||
// in any case.
|
||||
// If `direct` is set to true, then the detour via
|
||||
// fmt.Printf only occurs if there is a width or alignment
|
||||
// specifier.
|
||||
direct := verb == 'v' || verb == 's'
|
||||
|
||||
if !direct || (okW && width > 0) || okP {
|
||||
_, format := redact.MakeFormat(p, verb)
|
||||
fmt.Fprintf(p.State, format, p.finalBuf.String())
|
||||
} else {
|
||||
io.Copy(p.State, &p.finalBuf)
|
||||
}
|
||||
}
|
||||
|
||||
var detailSep = []byte("\n | ")
|
||||
|
||||
// state tracks error printing state. It implements fmt.State.
|
||||
type state struct {
|
||||
// state inherits fmt.State.
|
||||
//
|
||||
// If we are rendering with redactableOutput=true, then fmt.State
|
||||
// can be downcasted to redact.SafePrinter.
|
||||
fmt.State
|
||||
|
||||
// redactableOutput indicates whether we want the output
|
||||
// to use redaction markers. When set to true,
|
||||
// the fmt.State above is actually a redact.SafePrinter.
|
||||
redactableOutput bool
|
||||
|
||||
// finalBuf contains the final rendered string, prior to being
|
||||
// copied to the fmt.State above.
|
||||
//
|
||||
// If redactableOutput is true, then finalBuf contains a RedactableBytes
|
||||
// and safe redaction markers. Otherwise, it can be considered
|
||||
// an unsafe string.
|
||||
finalBuf bytes.Buffer
|
||||
|
||||
// entries collect the result of formatRecursive(). They are
|
||||
// consumed by formatSingleLineOutput() and formatEntries() to
|
||||
// produce the contents of finalBuf.
|
||||
entries []formatEntry
|
||||
|
||||
// buf collects the details of the current error object at a given
|
||||
// stage of recursion in formatRecursive().
|
||||
//
|
||||
// At each stage of recursion (level of wrapping), buf contains
|
||||
// successively:
|
||||
//
|
||||
// - at the beginning, the "simple" part of the error message --
|
||||
// either the pre-Detail() string if the error implements Formatter,
|
||||
// or the result of Error().
|
||||
//
|
||||
// - after the first call to Detail(), buf is copied to headBuf,
|
||||
// then reset, then starts collecting the "advanced" part of the
|
||||
// error message.
|
||||
//
|
||||
// At the end of an error layer, the contents of buf and headBuf
|
||||
// are collected into a formatEntry by collectEntry().
|
||||
// This collection does not touch finalBuf above.
|
||||
//
|
||||
// The entries are later consumed by formatSingleLineOutput() or
|
||||
// formatEntries() to produce the contents of finalBuf.
|
||||
//
|
||||
//
|
||||
// Notes regarding redaction markers and string safety. Throughout a
|
||||
// single "level" of error, there are three cases to consider:
|
||||
//
|
||||
// - the error level implements SafeErrorFormatter and
|
||||
// s.redactableOutput is set. In that case, the error's
|
||||
// SafeErrorFormat() is used to produce a RedactableBytes in
|
||||
// buf/headBuf via safePrinter{}, and an entry is collected at the
|
||||
// end of that with the redactable bit set on the entry.
|
||||
//
|
||||
// - the error level implements SafeErrorFormatter
|
||||
// and s.redactableOutput is *not* set. In this case,
|
||||
// for convenience we implement non-redactable output by using
|
||||
// SafeErrorFormat() to generate a RedactableBytes into
|
||||
// buf/headBuf via safePrinter{}, and then stripping the redaction
|
||||
// markers to produce the entry. The entry is not marked as
|
||||
// redactable.
|
||||
//
|
||||
// - in the remaining case (s.redactableOutput is not set or the
|
||||
// error only implements Formatter), then we use FormatError()
|
||||
// to produce a non-redactable string into buf/headBuf,
|
||||
// and mark the resulting entry as non-redactable.
|
||||
buf bytes.Buffer
|
||||
// When an error's FormatError() calls Detail(), the current
|
||||
// value of buf above is copied to headBuf, and a new
|
||||
// buf is initialized.
|
||||
headBuf []byte
|
||||
|
||||
// lastStack tracks the last stack trace observed when looking at
|
||||
// the errors from innermost to outermost. This is used to elide
|
||||
// redundant stack trace entries.
|
||||
lastStack StackTrace
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// The following attributes organize the synchronization of writes
|
||||
// to buf and headBuf, during the rendering of a single error
|
||||
// layer. They get reset between layers.
|
||||
|
||||
// hasDetail becomes true at each level of the formatRecursive()
|
||||
// recursion after the first call to .Detail(). It is used to
|
||||
// determine how to translate buf/headBuf into a formatEntry.
|
||||
hasDetail bool
|
||||
|
||||
// wantDetail is set to true when the error is formatted via %+v.
|
||||
// When false, printer.Detail() will always return false and the
|
||||
// error's .FormatError() method can perform less work. (This is an
|
||||
// optimization for the common case when an error's .Error() method
|
||||
// delegates its work to its .FormatError() via fmt.Format and
|
||||
// errors.FormatError().)
|
||||
wantDetail bool
|
||||
|
||||
// collectingRedactableString is true iff the data being accumulated
|
||||
// into buf comes from a redact string. It ensures that newline
|
||||
// characters are not included inside redaction markers.
|
||||
collectingRedactableString bool
|
||||
|
||||
// notEmpty tracks, at each level of recursion of formatRecursive(),
|
||||
// whether there were any details printed by an error's
|
||||
// .FormatError() method. It is used to properly determine whether
|
||||
// the printout should start with a newline and padding.
|
||||
notEmpty bool
|
||||
// needSpace tracks whether the next character displayed should pad
|
||||
// using a space character.
|
||||
needSpace bool
|
||||
// needNewline tracks whether the next character displayed should
|
||||
// pad using a newline and indentation.
|
||||
needNewline int
|
||||
// multiLine tracks whether the details so far contain multiple
|
||||
// lines. It is used to determine whether an enclosed stack trace,
|
||||
// if any, should be introduced with a separator.
|
||||
multiLine bool
|
||||
}
|
||||
|
||||
// formatEntry collects the textual details about one level of
|
||||
// wrapping or the leaf error in an error chain.
|
||||
type formatEntry struct {
|
||||
err error
|
||||
// redactable is true iff the data in head and details
|
||||
// are RedactableBytes. See the explanatory comments
|
||||
// on (state).buf for when this is set.
|
||||
redactable bool
|
||||
// head is the part of the text that is suitable for printing in the
|
||||
// one-liner summary, or when producing the output of .Error().
|
||||
head []byte
|
||||
// details is the part of the text produced in the advanced output
|
||||
// included for `%+v` formats.
|
||||
details []byte
|
||||
// elideShort, if true, elides the value of 'head' from concatenated
|
||||
// "short" messages produced by formatSingleLineOutput().
|
||||
elideShort bool
|
||||
|
||||
// stackTrace, if non-nil, reports the stack trace embedded at this
|
||||
// level of error.
|
||||
stackTrace StackTrace
|
||||
// elidedStackTrace, if true, indicates that the stack trace was
|
||||
// truncated to avoid duplication of entries. This is used to
|
||||
// display a truncation indicator during verbose rendering.
|
||||
elidedStackTrace bool
|
||||
|
||||
// depth, if positive, represents a nesting depth of this error as
|
||||
// a causer of others. This is used with verbose printing to
|
||||
// illustrate the nesting depth for multi-cause error wrappers.
|
||||
depth int
|
||||
}
|
||||
|
||||
// String is used for debugging only.
|
||||
func (e formatEntry) String() string {
|
||||
return fmt.Sprintf("formatEntry{%T, %q, %q}", e.err, e.head, e.details)
|
||||
}
|
||||
|
||||
// Write implements io.Writer.
|
||||
func (s *state) Write(b []byte) (n int, err error) {
|
||||
if len(b) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
k := 0
|
||||
|
||||
sep := detailSep
|
||||
if !s.wantDetail {
|
||||
sep = []byte("\n")
|
||||
}
|
||||
|
||||
for i, c := range b {
|
||||
if c == '\n' {
|
||||
//if s.needNewline > 0 {
|
||||
// for i := 0; i < s.needNewline-1; i++ {
|
||||
// s.buf.Write(detailSep[:len(sep)-1])
|
||||
// }
|
||||
// s.needNewline = 0
|
||||
//}
|
||||
// Flush all the bytes seen so far.
|
||||
s.buf.Write(b[k:i])
|
||||
// Don't print the newline itself; instead, prepare the state so
|
||||
// that the _next_ character encountered will pad with a newline.
|
||||
// This algorithm avoids terminating error details with excess
|
||||
// newline characters.
|
||||
k = i + 1
|
||||
s.needNewline++
|
||||
s.needSpace = false
|
||||
s.multiLine = true
|
||||
if s.wantDetail {
|
||||
s.switchOver()
|
||||
}
|
||||
} else {
|
||||
if s.needNewline > 0 && s.notEmpty {
|
||||
// If newline chars were pending, display them now.
|
||||
for i := 0; i < s.needNewline-1; i++ {
|
||||
s.buf.Write(detailSep[:len(sep)-1])
|
||||
}
|
||||
s.buf.Write(sep)
|
||||
s.needNewline = 0
|
||||
s.needSpace = false
|
||||
} else if s.needSpace {
|
||||
s.buf.WriteByte(' ')
|
||||
s.needSpace = false
|
||||
}
|
||||
s.notEmpty = true
|
||||
}
|
||||
}
|
||||
//if s.needNewline > 0 {
|
||||
// for i := 0; i < s.needNewline-1; i++ {
|
||||
// s.buf.Write(detailSep[:len(sep)-1])
|
||||
// }
|
||||
//}
|
||||
s.buf.Write(b[k:])
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
// printer wraps a state to implement an xerrors.Printer.
|
||||
type printer state
|
||||
|
||||
func (p *state) detail() bool {
|
||||
if !p.wantDetail {
|
||||
return false
|
||||
}
|
||||
if p.notEmpty {
|
||||
p.needNewline = 1
|
||||
}
|
||||
p.switchOver()
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *state) switchOver() {
|
||||
if p.hasDetail {
|
||||
return
|
||||
}
|
||||
p.headBuf = p.buf.Bytes()
|
||||
p.buf = bytes.Buffer{}
|
||||
p.notEmpty = false
|
||||
p.hasDetail = true
|
||||
|
||||
// One of the newlines is accounted for in the switch over.
|
||||
// p.needNewline -= 1
|
||||
}
|
||||
|
||||
func (s *printer) Detail() bool {
|
||||
return ((*state)(s)).detail()
|
||||
}
|
||||
|
||||
func (s *printer) Print(args ...interface{}) {
|
||||
s.enhanceArgs(args)
|
||||
fmt.Fprint((*state)(s), args...)
|
||||
}
|
||||
|
||||
func (s *printer) Printf(format string, args ...interface{}) {
|
||||
s.enhanceArgs(args)
|
||||
fmt.Fprintf((*state)(s), format, args...)
|
||||
}
|
||||
|
||||
func (s *printer) enhanceArgs(args []interface{}) {
|
||||
prevStack := s.lastStack
|
||||
lastSeen := prevStack
|
||||
for i := range args {
|
||||
if st, ok := args[i].(pkgErr.StackTrace); ok {
|
||||
args[i], _ = ElideSharedStackTraceSuffix(prevStack, st)
|
||||
lastSeen = st
|
||||
}
|
||||
if err, ok := args[i].(error); ok {
|
||||
args[i] = &errorFormatter{err}
|
||||
}
|
||||
}
|
||||
s.lastStack = lastSeen
|
||||
}
|
||||
|
||||
// safePrinter is a variant to printer used when the current error
|
||||
// level implements SafeFormatter.
|
||||
//
|
||||
// In any case, it uses the error's SafeFormatError() method to
|
||||
// prepare a RedactableBytes into s.buf / s.headBuf.
|
||||
// The the explanation for `buf` in the state struct.
|
||||
type safePrinter state
|
||||
|
||||
func (s *safePrinter) Detail() bool {
|
||||
return ((*state)(s)).detail()
|
||||
}
|
||||
|
||||
func (s *safePrinter) Print(args ...interface{}) {
|
||||
s.enhanceArgs(args)
|
||||
redact.Fprint((*state)(s), args...)
|
||||
}
|
||||
|
||||
func (s *safePrinter) Printf(format string, args ...interface{}) {
|
||||
s.enhanceArgs(args)
|
||||
redact.Fprintf((*state)(s), format, args...)
|
||||
}
|
||||
|
||||
func (s *safePrinter) enhanceArgs(args []interface{}) {
|
||||
prevStack := s.lastStack
|
||||
lastSeen := prevStack
|
||||
for i := range args {
|
||||
if st, ok := args[i].(pkgErr.StackTrace); ok {
|
||||
thisStack, _ := ElideSharedStackTraceSuffix(prevStack, st)
|
||||
// Stack traces are safe strings.
|
||||
args[i] = redact.Safe(thisStack)
|
||||
lastSeen = st
|
||||
}
|
||||
// In contrast with (*printer).enhanceArgs(), we don't use a
|
||||
// special case for `error` here, because the redact package
|
||||
// already helps us recursing into a safe print for
|
||||
// error objects.
|
||||
}
|
||||
s.lastStack = lastSeen
|
||||
}
|
||||
|
||||
type errorFormatter struct{ err error }
|
||||
|
||||
// Format implements the fmt.Formatter interface.
|
||||
func (ef *errorFormatter) Format(s fmt.State, verb rune) { FormatError(ef.err, s, verb) }
|
||||
|
||||
// Error implements error, so that `redact` knows what to do with it.
|
||||
func (ef *errorFormatter) Error() string { return ef.err.Error() }
|
||||
|
||||
// Unwrap makes it a wrapper.
|
||||
func (ef *errorFormatter) Unwrap() error { return ef.err }
|
||||
|
||||
// Cause makes it a wrapper.
|
||||
func (ef *errorFormatter) Cause() error { return ef.err }
|
||||
|
||||
// ElideSharedStackTraceSuffix removes the suffix of newStack that's already
|
||||
// present in prevStack. The function returns true if some entries
|
||||
// were elided.
|
||||
func ElideSharedStackTraceSuffix(prevStack, newStack StackTrace) (StackTrace, bool) {
|
||||
if len(prevStack) == 0 {
|
||||
return newStack, false
|
||||
}
|
||||
if len(newStack) == 0 {
|
||||
return newStack, false
|
||||
}
|
||||
|
||||
// Skip over the common suffix.
|
||||
var i, j int
|
||||
for i, j = len(newStack)-1, len(prevStack)-1; i > 0 && j > 0; i, j = i-1, j-1 {
|
||||
if newStack[i] != prevStack[j] {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == 0 {
|
||||
// Keep at least one entry.
|
||||
i = 1
|
||||
}
|
||||
return newStack[:i], i < len(newStack)-1
|
||||
}
|
||||
|
||||
// StackTrace is the type of the data for a call stack.
|
||||
// This mirrors the type of the same name in github.com/pkg/errors.
|
||||
type StackTrace = pkgErr.StackTrace
|
||||
|
||||
// StackFrame is the type of a single call frame entry.
|
||||
// This mirrors the type of the same name in github.com/pkg/errors.
|
||||
type StackFrame = pkgErr.Frame
|
||||
|
||||
// StackTraceProvider is a provider of StackTraces.
|
||||
// This is, intendedly, defined to be implemented by pkg/errors.stack.
|
||||
type StackTraceProvider interface {
|
||||
StackTrace() StackTrace
|
||||
}
|
||||
99
vendor/github.com/cockroachdb/errors/errbase/formatter.go
generated
vendored
Normal file
99
vendor/github.com/cockroachdb/errors/errbase/formatter.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// This file is taken from golang.org/x/xerrors,
|
||||
// at commit 3ee3066db522c6628d440a3a91c4abdd7f5ef22f (2019-05-10).
|
||||
// From the original code:
|
||||
// Copyright 2018 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.
|
||||
|
||||
package errbase
|
||||
|
||||
// A Formatter formats error messages.
|
||||
//
|
||||
// NB: Consider implementing SafeFormatter instead. This will ensure
|
||||
// that error displays can distinguish bits that are PII-safe.
|
||||
type Formatter interface {
|
||||
error
|
||||
|
||||
// FormatError prints the receiver's first error.
|
||||
// The return value decides what happens in the case
|
||||
// FormatError() is used to produce a "short" message,
|
||||
// eg. when it is used to implement Error():
|
||||
//
|
||||
// - if it returns nil, then the short message
|
||||
// contains no more than that produced for this error,
|
||||
// even if the error has a further causal chain.
|
||||
//
|
||||
// - if it returns non-nil, then the short message
|
||||
// contains the value printed by this error,
|
||||
// followed by that of its causal chain.
|
||||
// (e.g. thiserror: itscause: furthercause)
|
||||
//
|
||||
// Note that all the causal chain is reported in verbose reports in
|
||||
// any case.
|
||||
FormatError(p Printer) (next error)
|
||||
}
|
||||
|
||||
// SafeFormatter is implemented by error leaf or wrapper types that want
|
||||
// to separate safe and non-safe information when printed out.
|
||||
//
|
||||
// When multiple errors are chained (e.g. via errors.Wrap), intermediate
|
||||
// layers in the error that do not implement SafeError are considered
|
||||
// “unsafe”
|
||||
type SafeFormatter interface {
|
||||
// SafeFormatError prints the receiver's first error.
|
||||
//
|
||||
// The provided Printer behaves like a redact.SafePrinter its
|
||||
// Print() and Printf() methods conditionally add redaction markers
|
||||
// around unsafe bits.
|
||||
//
|
||||
// The return value of SafeFormatError() decides what happens in the
|
||||
// case the method is used to produce a "short" message, eg. when it
|
||||
// is used to implement Error():
|
||||
//
|
||||
// - if it returns nil, then the short message
|
||||
// contains no more than that produced for this error,
|
||||
// even if the error has a further causal chain.
|
||||
//
|
||||
// - if it returns non-nil, then the short message
|
||||
// contains the value printed by this error,
|
||||
// followed by that of its causal chain.
|
||||
// (e.g. thiserror: itscause: furthercause)
|
||||
//
|
||||
// Note that all the causal chain is reported in verbose reports in
|
||||
// any case.
|
||||
SafeFormatError(p Printer) (next error)
|
||||
}
|
||||
|
||||
// A Printer formats error messages.
|
||||
//
|
||||
// The most common implementation of Printer is the one provided by package fmt
|
||||
// during Printf (as of Go 1.13). Localization packages such as golang.org/x/text/message
|
||||
// typically provide their own implementations.
|
||||
type Printer interface {
|
||||
// Print appends args to the message output.
|
||||
Print(args ...interface{})
|
||||
|
||||
// Printf writes a formatted string.
|
||||
Printf(format string, args ...interface{})
|
||||
|
||||
// Detail reports whether error detail is requested.
|
||||
// After the first call to Detail, all text written to the Printer
|
||||
// is formatted as additional detail, or ignored when
|
||||
// detail has not been requested.
|
||||
// If Detail returns false, the caller can avoid printing the detail at all.
|
||||
Detail() bool
|
||||
}
|
||||
123
vendor/github.com/cockroachdb/errors/errbase/migrations.go
generated
vendored
Normal file
123
vendor/github.com/cockroachdb/errors/errbase/migrations.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 errbase
|
||||
|
||||
import "fmt"
|
||||
|
||||
// This file provides the library with the ability to handle cases
|
||||
// where an error type migrates, i.e. its package changes path or the
|
||||
// type name is changed.
|
||||
//
|
||||
// There are several scenarios to contend with. Assuming the error
|
||||
// type is initially called "foo", in version v1 of the code.
|
||||
//
|
||||
// Scenario 1: simple migration
|
||||
// - v2 renames foo -> bar
|
||||
// v2 calls: RegisterTypeMigration("foo", &bar{})
|
||||
// - v2 and v1 are connected
|
||||
// - v1 sends an error to v2:
|
||||
// - v2 has the migration registered, recognizes that "foo"
|
||||
// refers to bar
|
||||
// - v2 sends an error to v1
|
||||
// - v2 rewrites the error key upon send to the name known to v1
|
||||
//
|
||||
// Scenario 2: simultaneous migration
|
||||
// - vA renames foo -> bar
|
||||
// vA calls RegisterTypeMigration("foo", &bar{})
|
||||
// - vB renames foo -> qux
|
||||
// vB calls RegisterTypeMigration("foo", &qux{})
|
||||
// - vA and vB are connected
|
||||
// - vA sends an error to vB:
|
||||
// - vA translates the error key upon send from bar to foo's key
|
||||
// - vB recognizes that "foo" refers to qux
|
||||
//
|
||||
// Scenario 3: migrated error passing through
|
||||
// - v2 renames foo -> bar
|
||||
// v2 calls: RegisterTypeMigration("foo", &bar{})
|
||||
// - v2.a, v2.b and v1 are connected: v2.a -> v1 -> v2.b
|
||||
// - v2.a sends an error to v2.b via v1:
|
||||
// - v2.a encodes using foo's key, v1 receives as foo
|
||||
// - v1 encodes using foo's key
|
||||
// - v2.b receive's foo's key, knows about migration, decodes as bar
|
||||
//
|
||||
// Scenario 4: migrated error passing through node that does not know
|
||||
// about it whatsoever (the key is preserved).
|
||||
// - v2 renames foo -> bar
|
||||
// v2 calls: RegisterTypeMigration("foo", &bar{})
|
||||
// - v2.a, v2.b and v0 are connected: v2.a -> v0 -> v2.b
|
||||
// (v0 does not know about error foo at all)
|
||||
// - v2.a sends an error to v2.b via v0:
|
||||
// - v2.a encodes using foo's key, v0 receives as "unknown foo"
|
||||
// - v0 passes through unchanged
|
||||
// - v2.b receive's foo's key, knows about migration, decodes as bar
|
||||
//
|
||||
// Scenario 5: comparison between migrated and non-migrated errors
|
||||
// on 3rd party node.
|
||||
// - v2 renames foo -> bar
|
||||
// - v2 sends error bar to v0
|
||||
// - v1 sends an equivalent error with type foo to v0
|
||||
// - v0 (that doesn't know about the type) compares the two errors.
|
||||
// Here we're expecting v0 to properly ascertain the errors are equivalent.
|
||||
|
||||
// RegisterTypeMigration tells the library that the type of the error
|
||||
// given as 3rd argument was previously known with type
|
||||
// previousTypeName, located at previousPkgPath.
|
||||
//
|
||||
// The value of previousTypeName must be the result of calling
|
||||
// reflect.TypeOf(err).String() on the original error object.
|
||||
// This is usually composed as follows:
|
||||
// [*]<shortpackage>.<errortype>
|
||||
//
|
||||
// For example, Go's standard error type has name "*errors.errorString".
|
||||
// The asterisk indicates that `errorString` implements the `error`
|
||||
// interface via pointer receiver.
|
||||
//
|
||||
// Meanwhile, the singleton error type context.DeadlineExceeded
|
||||
// has name "context.deadlineExceededError", without asterisk
|
||||
// because the type implements `error` by value.
|
||||
//
|
||||
// Remember that the short package name inside the error type name and
|
||||
// the last component of the package path can be different. This is
|
||||
// why they must be specified separately.
|
||||
func RegisterTypeMigration(previousPkgPath, previousTypeName string, newType error) {
|
||||
prevKey := TypeKey(makeTypeKey(previousPkgPath, previousTypeName))
|
||||
newKey := TypeKey(getFullTypeName(newType))
|
||||
|
||||
// Register the backward migration: make the encode function
|
||||
// aware of the old name.
|
||||
if f, ok := backwardRegistry[newKey]; ok {
|
||||
panic(fmt.Errorf("migration to type %q already registered (from %q)", newKey, f))
|
||||
}
|
||||
backwardRegistry[newKey] = prevKey
|
||||
// If any other key was registered as a migration from newKey,
|
||||
// we'll forward those as well.
|
||||
// This changes X -> newKey to X -> prevKey for every X.
|
||||
for new, prev := range backwardRegistry {
|
||||
if prev == newKey {
|
||||
backwardRegistry[new] = prevKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// registry used when encoding an error, so that the receiver observes
|
||||
// the original key. This maps new keys to old keys.
|
||||
var backwardRegistry = map[TypeKey]TypeKey{}
|
||||
|
||||
// TestingWithEmptyMigrationRegistry is intended for use by tests.
|
||||
func TestingWithEmptyMigrationRegistry() (restore func()) {
|
||||
save := backwardRegistry
|
||||
backwardRegistry = map[TypeKey]TypeKey{}
|
||||
return func() { backwardRegistry = save }
|
||||
}
|
||||
137
vendor/github.com/cockroachdb/errors/errbase/opaque.go
generated
vendored
Normal file
137
vendor/github.com/cockroachdb/errors/errbase/opaque.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 errbase
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errorspb"
|
||||
"github.com/cockroachdb/redact"
|
||||
)
|
||||
|
||||
// opaqueLeaf is used when receiving an unknown leaf type.
|
||||
// Its important property is that if it is communicated
|
||||
// back to some network system that _does_ know about
|
||||
// the type, the original object can be restored.
|
||||
type opaqueLeaf struct {
|
||||
msg string
|
||||
details errorspb.EncodedErrorDetails
|
||||
}
|
||||
|
||||
// opaqueLeafCauses is used when receiving an unknown multi-cause
|
||||
// wrapper type. Its important property is that if it is communicated
|
||||
// back to some network system that _does_ know about the type, the
|
||||
// original object can be restored. We encode multi-cause errors as
|
||||
// leaf nodes over the network, in order to support backwards
|
||||
// compatibility with existing single-cause wrapper messages.
|
||||
//
|
||||
// This struct *must* be initialized with a non-nil causes value in
|
||||
// order to comply with go stdlib expectations for `Unwrap()`.
|
||||
type opaqueLeafCauses struct {
|
||||
opaqueLeaf
|
||||
causes []error
|
||||
}
|
||||
|
||||
var _ error = (*opaqueLeaf)(nil)
|
||||
var _ SafeDetailer = (*opaqueLeaf)(nil)
|
||||
var _ fmt.Formatter = (*opaqueLeaf)(nil)
|
||||
var _ SafeFormatter = (*opaqueLeaf)(nil)
|
||||
|
||||
var _ error = (*opaqueLeafCauses)(nil)
|
||||
var _ SafeDetailer = (*opaqueLeafCauses)(nil)
|
||||
var _ fmt.Formatter = (*opaqueLeafCauses)(nil)
|
||||
var _ SafeFormatter = (*opaqueLeafCauses)(nil)
|
||||
|
||||
// opaqueWrapper is used when receiving an unknown wrapper type.
|
||||
// Its important property is that if it is communicated
|
||||
// back to some network system that _does_ know about
|
||||
// the type, the original object can be restored.
|
||||
type opaqueWrapper struct {
|
||||
cause error
|
||||
prefix string
|
||||
details errorspb.EncodedErrorDetails
|
||||
messageType MessageType
|
||||
}
|
||||
|
||||
var _ error = (*opaqueWrapper)(nil)
|
||||
var _ SafeDetailer = (*opaqueWrapper)(nil)
|
||||
var _ fmt.Formatter = (*opaqueWrapper)(nil)
|
||||
var _ SafeFormatter = (*opaqueWrapper)(nil)
|
||||
|
||||
func (e *opaqueLeaf) Error() string { return e.msg }
|
||||
|
||||
func (e *opaqueWrapper) Error() string {
|
||||
if e.messageType == FullMessage {
|
||||
return e.prefix
|
||||
}
|
||||
if e.prefix == "" {
|
||||
return e.cause.Error()
|
||||
}
|
||||
return fmt.Sprintf("%s: %s", e.prefix, e.cause)
|
||||
}
|
||||
|
||||
// the opaque wrapper is a wrapper.
|
||||
func (e *opaqueWrapper) Cause() error { return e.cause }
|
||||
func (e *opaqueWrapper) Unwrap() error { return e.cause }
|
||||
|
||||
func (e *opaqueLeaf) SafeDetails() []string { return e.details.ReportablePayload }
|
||||
func (e *opaqueWrapper) SafeDetails() []string { return e.details.ReportablePayload }
|
||||
|
||||
func (e *opaqueLeaf) Format(s fmt.State, verb rune) { FormatError(e, s, verb) }
|
||||
func (e *opaqueLeafCauses) Format(s fmt.State, verb rune) { FormatError(e, s, verb) }
|
||||
func (e *opaqueWrapper) Format(s fmt.State, verb rune) { FormatError(e, s, verb) }
|
||||
|
||||
// opaqueLeafCauses is a multi-cause wrapper
|
||||
func (e *opaqueLeafCauses) Unwrap() []error { return e.causes }
|
||||
|
||||
func (e *opaqueLeaf) SafeFormatError(p Printer) (next error) {
|
||||
p.Print(e.msg)
|
||||
if p.Detail() {
|
||||
p.Printf("\n(opaque error leaf)")
|
||||
p.Printf("\ntype name: %s", redact.Safe(e.details.OriginalTypeName))
|
||||
for i, d := range e.details.ReportablePayload {
|
||||
p.Printf("\nreportable %d:\n%s", redact.Safe(i), redact.Safe(d))
|
||||
}
|
||||
if e.details.FullDetails != nil {
|
||||
p.Printf("\npayload type: %s", redact.Safe(e.details.FullDetails.TypeUrl))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *opaqueWrapper) SafeFormatError(p Printer) (next error) {
|
||||
if len(e.prefix) > 0 {
|
||||
// We use the condition if len(msg) > 0 because
|
||||
// otherwise an empty string would cause a "redactable
|
||||
// empty string" to be emitted (something that looks like "<>")
|
||||
// and the error formatting code only cleanly elides
|
||||
// the prefix properly if the output string is completely empty.
|
||||
p.Print(e.prefix)
|
||||
}
|
||||
if p.Detail() {
|
||||
p.Printf("\n(opaque error wrapper)")
|
||||
p.Printf("\ntype name: %s", redact.Safe(e.details.OriginalTypeName))
|
||||
for i, d := range e.details.ReportablePayload {
|
||||
p.Printf("\nreportable %d:\n%s", redact.Safe(i), redact.Safe(d))
|
||||
}
|
||||
if e.details.FullDetails != nil {
|
||||
p.Printf("\npayload type: %s", redact.Safe(e.details.FullDetails.TypeUrl))
|
||||
}
|
||||
}
|
||||
if e.messageType == FullMessage {
|
||||
return nil
|
||||
}
|
||||
return e.cause
|
||||
}
|
||||
24
vendor/github.com/cockroachdb/errors/errbase/oserror_go116.go
generated
vendored
Normal file
24
vendor/github.com/cockroachdb/errors/errbase/oserror_go116.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2021 The Cockroach Authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// +build go1.16
|
||||
|
||||
package errbase
|
||||
|
||||
import "io/fs"
|
||||
|
||||
func registerOsPathErrorMigration() {
|
||||
// The os.PathError type was migrated to io.fs.PathError in Go 1.16.
|
||||
RegisterTypeMigration("os", "*os.PathError", &fs.PathError{})
|
||||
}
|
||||
19
vendor/github.com/cockroachdb/errors/errbase/oserror_pre116.go
generated
vendored
Normal file
19
vendor/github.com/cockroachdb/errors/errbase/oserror_pre116.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2021 The Cockroach Authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// +build !go1.16
|
||||
|
||||
package errbase
|
||||
|
||||
func registerOsPathErrorMigration() {}
|
||||
93
vendor/github.com/cockroachdb/errors/errbase/safe_details.go
generated
vendored
Normal file
93
vendor/github.com/cockroachdb/errors/errbase/safe_details.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 errbase
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errorspb"
|
||||
pkgErr "github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// SafeDetailer is an interface that can be implemented by errors that
|
||||
// can provide PII-free additional strings suitable for reporting or
|
||||
// telemetry.
|
||||
type SafeDetailer interface {
|
||||
SafeDetails() []string
|
||||
}
|
||||
|
||||
// GetAllSafeDetails collects the safe details from the given error object
|
||||
// and all its causes.
|
||||
// The details are collected from outermost to innermost level of cause.
|
||||
func GetAllSafeDetails(err error) []SafeDetailPayload {
|
||||
var details []SafeDetailPayload
|
||||
for ; err != nil; err = UnwrapOnce(err) {
|
||||
details = append(details, GetSafeDetails(err))
|
||||
}
|
||||
return details
|
||||
}
|
||||
|
||||
// GetSafeDetails collects the safe details from the given error
|
||||
// object. If it is a wrapper, only the details from the wrapper are
|
||||
// returned.
|
||||
func GetSafeDetails(err error) (payload SafeDetailPayload) {
|
||||
origTypeName, famName, ext := getTypeDetails(err, false /*onlyFamily*/)
|
||||
payload.OriginalTypeName = origTypeName
|
||||
payload.ErrorTypeMark = errorspb.ErrorTypeMark{
|
||||
FamilyName: famName,
|
||||
Extension: ext,
|
||||
}
|
||||
payload.SafeDetails = getDetails(err)
|
||||
return
|
||||
}
|
||||
|
||||
func getDetails(err error) []string {
|
||||
if sd, ok := err.(SafeDetailer); ok {
|
||||
return sd.SafeDetails()
|
||||
}
|
||||
// For convenience, we also know how to extract stack traces
|
||||
// in the style of github.com/pkg/errors.
|
||||
if st, ok := err.(interface{ StackTrace() pkgErr.StackTrace }); ok {
|
||||
return []string{fmt.Sprintf("%+v", st.StackTrace())}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SafeDetailPayload captures the safe strings for one
|
||||
// level of wrapping.
|
||||
type SafeDetailPayload struct {
|
||||
// OriginalTypeName is the concrete type of the error that the details
|
||||
// are coming from.
|
||||
OriginalTypeName string
|
||||
// ErrorTypeMark is the mark of the error that the details are
|
||||
// coming from. This may contain a different type name than
|
||||
// OriginalTypeName in case an error type was migrated.
|
||||
ErrorTypeMark errorspb.ErrorTypeMark
|
||||
// SafeDetails are the PII-free strings.
|
||||
SafeDetails []string
|
||||
}
|
||||
|
||||
// Fill can be used to concatenate multiple SafeDetailPayloads.
|
||||
func (s *SafeDetailPayload) Fill(slice []string) []string {
|
||||
if len(s.SafeDetails) == 0 {
|
||||
return slice
|
||||
}
|
||||
slice = append(slice, fmt.Sprintf("details for %s::%s:",
|
||||
s.ErrorTypeMark.FamilyName, s.ErrorTypeMark.Extension))
|
||||
for _, sd := range s.SafeDetails {
|
||||
slice = append(slice, " "+sd)
|
||||
}
|
||||
return slice
|
||||
}
|
||||
71
vendor/github.com/cockroachdb/errors/errbase/unwrap.go
generated
vendored
Normal file
71
vendor/github.com/cockroachdb/errors/errbase/unwrap.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 errbase
|
||||
|
||||
// Sadly the go 2/1.13 design for errors has promoted the name
|
||||
// `Unwrap()` for the method that accesses the cause, whilst the
|
||||
// ecosystem has already chosen `Cause()`. In order to unwrap
|
||||
// reliably, we must thus support both.
|
||||
//
|
||||
// See: https://github.com/golang/go/issues/31778
|
||||
|
||||
// UnwrapOnce accesses the direct cause of the error if any, otherwise
|
||||
// returns nil.
|
||||
//
|
||||
// It supports both errors implementing causer (`Cause()` method, from
|
||||
// github.com/pkg/errors) and `Wrapper` (`Unwrap()` method, from the
|
||||
// Go 2 error proposal).
|
||||
//
|
||||
// UnwrapOnce treats multi-errors (those implementing the
|
||||
// `Unwrap() []error` interface as leaf-nodes since they cannot
|
||||
// reasonably be iterated through to a single cause. These errors
|
||||
// are typically constructed as a result of `fmt.Errorf` which results
|
||||
// in a `wrapErrors` instance that contains an interpolated error
|
||||
// string along with a list of causes.
|
||||
//
|
||||
// The go stdlib does not define output on `Unwrap()` for a multi-cause
|
||||
// error, so we default to nil here.
|
||||
func UnwrapOnce(err error) (cause error) {
|
||||
switch e := err.(type) {
|
||||
case interface{ Cause() error }:
|
||||
return e.Cause()
|
||||
case interface{ Unwrap() error }:
|
||||
return e.Unwrap()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnwrapAll accesses the root cause object of the error.
|
||||
// If the error has no cause (leaf error), it is returned directly.
|
||||
// UnwrapAll treats multi-errors as leaf nodes.
|
||||
func UnwrapAll(err error) error {
|
||||
for {
|
||||
if cause := UnwrapOnce(err); cause != nil {
|
||||
err = cause
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// UnwrapMulti access the slice of causes that an error contains, if it is a
|
||||
// multi-error.
|
||||
func UnwrapMulti(err error) []error {
|
||||
if me, ok := err.(interface{ Unwrap() []error }); ok {
|
||||
return me.Unwrap()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
253
vendor/github.com/cockroachdb/errors/errbase_api.go
generated
vendored
Normal file
253
vendor/github.com/cockroachdb/errors/errbase_api.go
generated
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
)
|
||||
|
||||
// UnwrapOnce accesses the direct cause of the error if any, otherwise
|
||||
// returns nil.
|
||||
//
|
||||
// It supports both errors implementing causer (`Cause()` method, from
|
||||
// github.com/pkg/errors) and `Wrapper` (`Unwrap()` method, from the
|
||||
// Go 2 error proposal).
|
||||
func UnwrapOnce(err error) error { return errbase.UnwrapOnce(err) }
|
||||
|
||||
// UnwrapAll accesses the root cause object of the error.
|
||||
// If the error has no cause (leaf error), it is returned directly.
|
||||
func UnwrapAll(err error) error { return errbase.UnwrapAll(err) }
|
||||
|
||||
// EncodedError is the type of an encoded (and protobuf-encodable) error.
|
||||
type EncodedError = errbase.EncodedError
|
||||
|
||||
// EncodeError encodes an error.
|
||||
func EncodeError(ctx context.Context, err error) EncodedError { return errbase.EncodeError(ctx, err) }
|
||||
|
||||
// DecodeError decodes an error.
|
||||
func DecodeError(ctx context.Context, enc EncodedError) error { return errbase.DecodeError(ctx, enc) }
|
||||
|
||||
// SafeDetailer is an interface that can be implemented by errors that
|
||||
// can provide PII-free additional strings suitable for reporting or
|
||||
// telemetry.
|
||||
type SafeDetailer = errbase.SafeDetailer
|
||||
|
||||
// GetAllSafeDetails collects the safe details from the given error object
|
||||
// and all its causes.
|
||||
// The details are collected from outermost to innermost level of cause.
|
||||
func GetAllSafeDetails(err error) []SafeDetailPayload { return errbase.GetAllSafeDetails(err) }
|
||||
|
||||
// GetSafeDetails collects the safe details from the given error
|
||||
// object. If it is a wrapper, only the details from the wrapper are
|
||||
// returned.
|
||||
func GetSafeDetails(err error) (payload SafeDetailPayload) { return errbase.GetSafeDetails(err) }
|
||||
|
||||
// SafeDetailPayload captures the safe strings for one
|
||||
// level of wrapping.
|
||||
type SafeDetailPayload = errbase.SafeDetailPayload
|
||||
|
||||
// RegisterLeafDecoder can be used to register new leaf error types to
|
||||
// the library. Registered types will be decoded using their own
|
||||
// Go type when an error is decoded. Wrappers that have not been
|
||||
// registered will be decoded using the opaqueLeaf type.
|
||||
//
|
||||
// Note: if the error type has been migrated from a previous location
|
||||
// or a different type, ensure that RegisterTypeMigration() was called
|
||||
// prior to RegisterLeafDecoder().
|
||||
func RegisterLeafDecoder(typeName TypeKey, decoder LeafDecoder) {
|
||||
errbase.RegisterLeafDecoder(typeName, decoder)
|
||||
}
|
||||
|
||||
// TypeKey identifies an error for the purpose of looking up decoders.
|
||||
// It is equivalent to the "family name" in ErrorTypeMarker.
|
||||
type TypeKey = errbase.TypeKey
|
||||
|
||||
// GetTypeKey retrieve the type key for a given error object. This
|
||||
// is meant for use in combination with the Register functions.
|
||||
func GetTypeKey(err error) TypeKey { return errbase.GetTypeKey(err) }
|
||||
|
||||
// LeafDecoder is to be provided (via RegisterLeafDecoder above)
|
||||
// by additional wrapper types not yet known to this library.
|
||||
// A nil return indicates that decoding was not successful.
|
||||
type LeafDecoder = errbase.LeafDecoder
|
||||
|
||||
// MultiCauseDecoder is to be provided (via RegisterMultiCauseDecoder
|
||||
// above) by additional multi-cause wrapper types not yet known by the
|
||||
// library. A nil return indicates that decoding was not successful.
|
||||
type MultiCauseDecoder = errbase.MultiCauseDecoder
|
||||
|
||||
// RegisterMultiCauseDecoder can be used to register new multi-cause
|
||||
// wrapper types to the library. Registered wrappers will be decoded
|
||||
// using their own Go type when an error is decoded. Multi-cause
|
||||
// wrappers that have not been registered will be decoded using the
|
||||
// opaqueWrapper type.
|
||||
func RegisterMultiCauseDecoder(theType TypeKey, decoder MultiCauseDecoder) {
|
||||
errbase.RegisterMultiCauseDecoder(theType, decoder)
|
||||
}
|
||||
|
||||
// RegisterWrapperDecoder can be used to register new wrapper types to
|
||||
// the library. Registered wrappers will be decoded using their own
|
||||
// Go type when an error is decoded. Wrappers that have not been
|
||||
// registered will be decoded using the opaqueWrapper type.
|
||||
//
|
||||
// Note: if the error type has been migrated from a previous location
|
||||
// or a different type, ensure that RegisterTypeMigration() was called
|
||||
// prior to RegisterWrapperDecoder().
|
||||
func RegisterWrapperDecoder(typeName TypeKey, decoder WrapperDecoder) {
|
||||
errbase.RegisterWrapperDecoder(typeName, decoder)
|
||||
}
|
||||
|
||||
// WrapperDecoder is to be provided (via RegisterWrapperDecoder above)
|
||||
// by additional wrapper types not yet known to this library.
|
||||
// A nil return indicates that decoding was not successful.
|
||||
type WrapperDecoder = errbase.WrapperDecoder
|
||||
|
||||
// RegisterLeafEncoder can be used to register new leaf error types to
|
||||
// the library. Registered types will be encoded using their own
|
||||
// Go type when an error is encoded. Wrappers that have not been
|
||||
// registered will be encoded using the opaqueLeaf type.
|
||||
//
|
||||
// Note: if the error type has been migrated from a previous location
|
||||
// or a different type, ensure that RegisterTypeMigration() was called
|
||||
// prior to RegisterLeafEncoder().
|
||||
func RegisterLeafEncoder(typeName TypeKey, encoder LeafEncoder) {
|
||||
errbase.RegisterLeafEncoder(typeName, encoder)
|
||||
}
|
||||
|
||||
// LeafEncoder is to be provided (via RegisterLeafEncoder above)
|
||||
// by additional wrapper types not yet known to this library.
|
||||
type LeafEncoder = errbase.LeafEncoder
|
||||
|
||||
// RegisterWrapperEncoder can be used to register new wrapper types to
|
||||
// the library. Registered wrappers will be encoded using their own
|
||||
// Go type when an error is encoded. Wrappers that have not been
|
||||
// registered will be encoded using the opaqueWrapper type.
|
||||
//
|
||||
// Note: if the error type has been migrated from a previous location
|
||||
// or a different type, ensure that RegisterTypeMigration() was called
|
||||
// prior to RegisterWrapperEncoder().
|
||||
func RegisterWrapperEncoder(typeName TypeKey, encoder WrapperEncoder) {
|
||||
errbase.RegisterWrapperEncoder(typeName, encoder)
|
||||
}
|
||||
|
||||
// WrapperEncoder is to be provided (via RegisterWrapperEncoder above)
|
||||
// by additional wrapper types not yet known to this library.
|
||||
type WrapperEncoder = errbase.WrapperEncoder
|
||||
|
||||
// RegisterWrapperEncoderWithMessageType can be used to register new wrapper
|
||||
// types to the library. These wrappers can optionally override the child error
|
||||
// messages with their own error string instead of relying on iterative
|
||||
// concatenation. Registered wrappers will be encoded using their own Go type
|
||||
// when an error is encoded. Wrappers that have not been registered will be
|
||||
// encoded using the opaqueWrapper type.
|
||||
//
|
||||
// Note: if the error type has been migrated from a previous location
|
||||
// or a different type, ensure that RegisterTypeMigration() was called
|
||||
// prior to RegisterWrapperEncoder().
|
||||
func RegisterWrapperEncoderWithMessageType(typeName TypeKey, encoder WrapperEncoderWithMessageType) {
|
||||
errbase.RegisterWrapperEncoderWithMessageType(typeName, encoder)
|
||||
}
|
||||
|
||||
// WrapperEncoderWithMessageType is to be provided (via
|
||||
// RegisterWrapperEncoderWithMessageType) by additional wrapper
|
||||
// types not yet known to this library.
|
||||
type WrapperEncoderWithMessageType = errbase.WrapperEncoderWithMessageType
|
||||
|
||||
// RegisterMultiCauseEncoder can be used to register new multi-cause
|
||||
// error types to the library. Registered types will be encoded using
|
||||
// their own Go type when an error is encoded. Multi-cause wrappers
|
||||
// that have not been registered will be encoded using the
|
||||
// opaqueWrapper type.
|
||||
func RegisterMultiCauseEncoder(typeName TypeKey, encoder MultiCauseEncoder) {
|
||||
errbase.RegisterMultiCauseEncoder(typeName, encoder)
|
||||
}
|
||||
|
||||
// MultiCauseEncoder is to be provided (via RegisterMultiCauseEncoder
|
||||
// above) by additional multi-cause wrapper types not yet known to this
|
||||
// library. The encoder will automatically extract and encode the
|
||||
// causes of this error by calling `Unwrap()` and expecting a slice of
|
||||
// errors.
|
||||
type MultiCauseEncoder = errbase.MultiCauseEncoder
|
||||
|
||||
// SetWarningFn enables configuration of the warning function.
|
||||
func SetWarningFn(fn func(context.Context, string, ...interface{})) { errbase.SetWarningFn(fn) }
|
||||
|
||||
// A Formatter formats error messages.
|
||||
//
|
||||
// NB: Consider implementing SafeFormatter instead. This will ensure
|
||||
// that error displays can distinguish bits that are PII-safe.
|
||||
type Formatter = errbase.Formatter
|
||||
|
||||
// SafeFormatter is implemented by error leaf or wrapper types that want
|
||||
// to separate safe and non-safe information when printed out.
|
||||
//
|
||||
// When multiple errors are chained (e.g. via errors.Wrap), intermediate
|
||||
// layers in the error that do not implement SafeError are considered
|
||||
// “unsafe”
|
||||
type SafeFormatter = errbase.SafeFormatter
|
||||
|
||||
// A Printer formats error messages.
|
||||
//
|
||||
// The most common implementation of Printer is the one provided by package fmt
|
||||
// during Printf (as of Go 1.13). Localization packages such as golang.org/x/text/message
|
||||
// typically provide their own implementations.
|
||||
type Printer = errbase.Printer
|
||||
|
||||
// FormatError formats an error according to s and verb.
|
||||
// This is a helper meant for use when implementing the fmt.Formatter
|
||||
// interface on custom error objects.
|
||||
//
|
||||
// If the error implements errors.Formatter, FormatError calls its
|
||||
// FormatError method of f with an errors.Printer configured according
|
||||
// to s and verb, and writes the result to s.
|
||||
//
|
||||
// Otherwise, if it is a wrapper, FormatError prints out its error prefix,
|
||||
// then recurses on its cause.
|
||||
//
|
||||
// Otherwise, its Error() text is printed.
|
||||
func FormatError(err error, s fmt.State, verb rune) { errbase.FormatError(err, s, verb) }
|
||||
|
||||
// Formattable wraps an error into a fmt.Formatter which
|
||||
// will provide "smart" formatting even if the outer layer
|
||||
// of the error does not implement the Formatter interface.
|
||||
func Formattable(err error) fmt.Formatter { return errbase.Formattable(err) }
|
||||
|
||||
// RegisterTypeMigration tells the library that the type of the error
|
||||
// given as 3rd argument was previously known with type
|
||||
// previousTypeName, located at previousPkgPath.
|
||||
//
|
||||
// The value of previousTypeName must be the result of calling
|
||||
// reflect.TypeOf(err).String() on the original error object.
|
||||
// This is usually composed as follows:
|
||||
//
|
||||
// [*]<shortpackage>.<errortype>
|
||||
//
|
||||
// For example, Go's standard error type has name "*errors.errorString".
|
||||
// The asterisk indicates that `errorString` implements the `error`
|
||||
// interface via pointer receiver.
|
||||
//
|
||||
// Meanwhile, the singleton error type context.DeadlineExceeded
|
||||
// has name "context.deadlineExceededError", without asterisk
|
||||
// because the type implements `error` by value.
|
||||
//
|
||||
// Remember that the short package name inside the error type name and
|
||||
// the last component of the package path can be different. This is
|
||||
// why they must be specified separately.
|
||||
func RegisterTypeMigration(previousPkgPath, previousTypeName string, newType error) {
|
||||
errbase.RegisterTypeMigration(previousPkgPath, previousTypeName, newType)
|
||||
}
|
||||
21
vendor/github.com/cockroachdb/errors/errorspb/errors.go
generated
vendored
Normal file
21
vendor/github.com/cockroachdb/errors/errorspb/errors.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2021 The Cockroach Authors.
|
||||
//
|
||||
// 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 errorspb
|
||||
|
||||
// IsSet returns true if the EncodedError contains an error, or false if it is
|
||||
// empty.
|
||||
func (m *EncodedError) IsSet() bool {
|
||||
return m.Error != nil
|
||||
}
|
||||
2167
vendor/github.com/cockroachdb/errors/errorspb/errors.pb.go
generated
vendored
Normal file
2167
vendor/github.com/cockroachdb/errors/errorspb/errors.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
149
vendor/github.com/cockroachdb/errors/errorspb/errors.proto
generated
vendored
Normal file
149
vendor/github.com/cockroachdb/errors/errorspb/errors.proto
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
syntax = "proto3";
|
||||
package cockroach.errorspb;
|
||||
option go_package = "errorspb";
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
import "gogoproto/gogo.proto";
|
||||
|
||||
// EncodedError is the wire-encodable representation
|
||||
// of an error (or error cause chain).
|
||||
message EncodedError {
|
||||
oneof error {
|
||||
// This is used for leaf error objects.
|
||||
EncodedErrorLeaf leaf = 1;
|
||||
// This is used for wrapper errors.
|
||||
EncodedWrapper wrapper = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// EncodedErrorLeaf is the wire-encodable representation
|
||||
// of an error leaf or a multi-cause wrapper from go 1.20+
|
||||
message EncodedErrorLeaf {
|
||||
// The main error message (mandatory), that can be printed to human
|
||||
// users and may contain PII. This contains the value of the leaf
|
||||
// error's Error(), or using a registered encoder.
|
||||
string message = 1;
|
||||
|
||||
// The error details.
|
||||
EncodedErrorDetails details = 2 [(gogoproto.nullable) = false];
|
||||
|
||||
// multierror_causes is a list of errors that contain the causal tree
|
||||
// of this leaf. If this field is not empty, then this leaf encodes
|
||||
// an error from go 1.20 or later that encodes multiple causes in its
|
||||
// chain.
|
||||
repeated EncodedError multierror_causes = 3;
|
||||
}
|
||||
|
||||
message EncodedErrorDetails {
|
||||
// The original fully qualified error type name (mandatory).
|
||||
// This is primarily used to print out error details
|
||||
// in error reports and Format().
|
||||
//
|
||||
// It is additionally used to populate the error mark
|
||||
// below when the family name is not known/set.
|
||||
// See the `markers` error package and the
|
||||
// RFC on error handling for details.
|
||||
string original_type_name = 1;
|
||||
|
||||
// The error mark. This is used to determine error equivalence and
|
||||
// identifying a decode function.
|
||||
// See the `markers` error package and the
|
||||
// RFC on error handling for details.
|
||||
ErrorTypeMark error_type_mark = 2 [(gogoproto.nullable) = false];
|
||||
|
||||
// The reportable payload (optional), which is as descriptive as
|
||||
// possible but may not contain PII.
|
||||
//
|
||||
// This is extracted automatically using a registered encoder, if
|
||||
// any, or the SafeDetailer interface.
|
||||
repeated string reportable_payload = 3;
|
||||
|
||||
// An arbitrary payload that (presumably) encodes the
|
||||
// native error object. This is also optional.
|
||||
//
|
||||
// This is extracted automatically using a registered encoder, if
|
||||
// any.
|
||||
google.protobuf.Any full_details = 4;
|
||||
}
|
||||
|
||||
// MessageType encodes information regarding the interpretation of an
|
||||
// error's message string.
|
||||
enum MessageType {
|
||||
// Keeping zero value as default for backwards compatibility.
|
||||
// PREFIX is a message that should be prepended to its cause.
|
||||
PREFIX = 0;
|
||||
// FULL_MESSAGE is a complete error message that can be displayed
|
||||
// without its cause.
|
||||
FULL_MESSAGE = 1;
|
||||
}
|
||||
|
||||
// EncodedWrapper is the wire-encodable representation
|
||||
// of an error wrapper.
|
||||
message EncodedWrapper {
|
||||
// The cause error. Mandatory.
|
||||
EncodedError cause = 1 [(gogoproto.nullable) = false];
|
||||
|
||||
// The wrapper message. This could either be a full error message
|
||||
// that can be printed independently, or a (potentially empty) prefix
|
||||
// which is printed before the cause's own message to construct the
|
||||
// full message. This may contain PII.
|
||||
//
|
||||
// This is extracted automatically:
|
||||
//
|
||||
// - for wrappers that have a registered encoder,
|
||||
// - otherwise, when the wrapper's Error() has its cause's Error() as suffix.
|
||||
string message = 2;
|
||||
|
||||
// The error details.
|
||||
EncodedErrorDetails details = 3 [(gogoproto.nullable) = false];
|
||||
|
||||
// message_type encodes the interpretation of `message`. Prior
|
||||
// versions will not set this field and it will be left as `PREFIX`.
|
||||
// This retains backwards compatibility since the new behavior is
|
||||
// only enabled when this enum is set to `FULL_MESSAGE`.
|
||||
MessageType message_type = 4;
|
||||
}
|
||||
|
||||
// ErrorTypeMark identifies an error type for the purpose of determining
|
||||
// error equivalences and looking up decoder functions.
|
||||
message ErrorTypeMark {
|
||||
// The family name identifies the error type.
|
||||
// This is equal to original_type_name above in the common case, but
|
||||
// can be overridden when e.g. the package that defines the type
|
||||
// changes path.
|
||||
// This is the field also used for looking up a decode function.
|
||||
string family_name = 1;
|
||||
|
||||
// This marker string is used in combination with
|
||||
// the family name for the purpose of determining error equivalence.
|
||||
// This can be used to separate error instances that have the same type
|
||||
// into separate equivalence classes.
|
||||
// See the `markers` error package and the
|
||||
// RFC on error handling for details.
|
||||
string extension = 2;
|
||||
}
|
||||
|
||||
// StringsPayload is used to encode the payload of certain error
|
||||
// types.
|
||||
message StringsPayload {
|
||||
repeated string details = 1;
|
||||
}
|
||||
|
||||
// ErrnoPayload is used to encode the payload of syscall.Errno
|
||||
// errors.
|
||||
message ErrnoPayload {
|
||||
// The original errno numeric code.
|
||||
int64 orig_errno = 1;
|
||||
// The platform where the syscall.Errno was encoded. This
|
||||
// is needed because the numeric values of syscall.Errno
|
||||
// have different meanings depending on the platform.
|
||||
// When decoding, if the arch field does not match we
|
||||
// use a substitute data type instead.
|
||||
string arch = 2;
|
||||
|
||||
bool is_permission = 3;
|
||||
bool is_exist = 4;
|
||||
bool is_not_exist = 5;
|
||||
bool is_timeout = 6;
|
||||
bool is_temporary = 7;
|
||||
}
|
||||
302
vendor/github.com/cockroachdb/errors/errorspb/hintdetail.pb.go
generated
vendored
Normal file
302
vendor/github.com/cockroachdb/errors/errorspb/hintdetail.pb.go
generated
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: errorspb/hintdetail.proto
|
||||
|
||||
package errorspb
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type StringPayload struct {
|
||||
Msg string `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"`
|
||||
}
|
||||
|
||||
func (m *StringPayload) Reset() { *m = StringPayload{} }
|
||||
func (m *StringPayload) String() string { return proto.CompactTextString(m) }
|
||||
func (*StringPayload) ProtoMessage() {}
|
||||
func (*StringPayload) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_d99b88ec9cc4bc22, []int{0}
|
||||
}
|
||||
func (m *StringPayload) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *StringPayload) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
func (m *StringPayload) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_StringPayload.Merge(m, src)
|
||||
}
|
||||
func (m *StringPayload) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *StringPayload) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_StringPayload.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_StringPayload proto.InternalMessageInfo
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*StringPayload)(nil), "cockroach.errorspb.StringPayload")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("errorspb/hintdetail.proto", fileDescriptor_d99b88ec9cc4bc22) }
|
||||
|
||||
var fileDescriptor_d99b88ec9cc4bc22 = []byte{
|
||||
// 143 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0x2d, 0x2a, 0xca,
|
||||
0x2f, 0x2a, 0x2e, 0x48, 0xd2, 0xcf, 0xc8, 0xcc, 0x2b, 0x49, 0x49, 0x2d, 0x49, 0xcc, 0xcc, 0xd1,
|
||||
0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x4a, 0xce, 0x4f, 0xce, 0x2e, 0xca, 0x4f, 0x4c, 0xce,
|
||||
0xd0, 0x83, 0x29, 0x52, 0x52, 0xe4, 0xe2, 0x0d, 0x2e, 0x29, 0xca, 0xcc, 0x4b, 0x0f, 0x48, 0xac,
|
||||
0xcc, 0xc9, 0x4f, 0x4c, 0x11, 0x12, 0xe0, 0x62, 0xce, 0x2d, 0x4e, 0x97, 0x60, 0x54, 0x60, 0xd4,
|
||||
0xe0, 0x0c, 0x02, 0x31, 0x9d, 0xb4, 0x4e, 0x3c, 0x94, 0x63, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2,
|
||||
0x23, 0x39, 0xc6, 0x1b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1,
|
||||
0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0x38, 0x60, 0xc6, 0x25, 0xb1, 0x81, 0x6d,
|
||||
0x32, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xe2, 0xbd, 0x3a, 0x3e, 0x86, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *StringPayload) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *StringPayload) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *StringPayload) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Msg) > 0 {
|
||||
i -= len(m.Msg)
|
||||
copy(dAtA[i:], m.Msg)
|
||||
i = encodeVarintHintdetail(dAtA, i, uint64(len(m.Msg)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintHintdetail(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovHintdetail(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *StringPayload) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Msg)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovHintdetail(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovHintdetail(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func sozHintdetail(x uint64) (n int) {
|
||||
return sovHintdetail(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *StringPayload) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHintdetail
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: StringPayload: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: StringPayload: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHintdetail
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthHintdetail
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthHintdetail
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Msg = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipHintdetail(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthHintdetail
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipHintdetail(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowHintdetail
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowHintdetail
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowHintdetail
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthHintdetail
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroupHintdetail
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthHintdetail
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthHintdetail = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowHintdetail = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupHintdetail = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
||||
7
vendor/github.com/cockroachdb/errors/errorspb/hintdetail.proto
generated
vendored
Normal file
7
vendor/github.com/cockroachdb/errors/errorspb/hintdetail.proto
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
syntax = "proto3";
|
||||
package cockroach.errorspb;
|
||||
option go_package = "errorspb";
|
||||
|
||||
message StringPayload {
|
||||
string msg = 1;
|
||||
}
|
||||
19
vendor/github.com/cockroachdb/errors/errorspb/markers.go
generated
vendored
Normal file
19
vendor/github.com/cockroachdb/errors/errorspb/markers.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 errorspb
|
||||
|
||||
func (m ErrorTypeMark) Equals(o ErrorTypeMark) bool {
|
||||
return m.FamilyName == o.FamilyName && m.Extension == o.Extension
|
||||
}
|
||||
365
vendor/github.com/cockroachdb/errors/errorspb/markers.pb.go
generated
vendored
Normal file
365
vendor/github.com/cockroachdb/errors/errorspb/markers.pb.go
generated
vendored
Normal file
@@ -0,0 +1,365 @@
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: errorspb/markers.proto
|
||||
|
||||
package errorspb
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
// MarkPayload is the error payload for a forced marker.
|
||||
// See errors/markers/markers.go and the RFC on
|
||||
// error handling for details.
|
||||
type MarkPayload struct {
|
||||
Msg string `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"`
|
||||
Types []ErrorTypeMark `protobuf:"bytes,2,rep,name=types,proto3" json:"types"`
|
||||
}
|
||||
|
||||
func (m *MarkPayload) Reset() { *m = MarkPayload{} }
|
||||
func (m *MarkPayload) String() string { return proto.CompactTextString(m) }
|
||||
func (*MarkPayload) ProtoMessage() {}
|
||||
func (*MarkPayload) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_84c3fd24ba37816d, []int{0}
|
||||
}
|
||||
func (m *MarkPayload) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *MarkPayload) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
func (m *MarkPayload) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_MarkPayload.Merge(m, src)
|
||||
}
|
||||
func (m *MarkPayload) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *MarkPayload) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_MarkPayload.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_MarkPayload proto.InternalMessageInfo
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*MarkPayload)(nil), "cockroach.errorspb.MarkPayload")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("errorspb/markers.proto", fileDescriptor_84c3fd24ba37816d) }
|
||||
|
||||
var fileDescriptor_84c3fd24ba37816d = []byte{
|
||||
// 198 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4b, 0x2d, 0x2a, 0xca,
|
||||
0x2f, 0x2a, 0x2e, 0x48, 0xd2, 0xcf, 0x4d, 0x2c, 0xca, 0x4e, 0x2d, 0x2a, 0xd6, 0x2b, 0x28, 0xca,
|
||||
0x2f, 0xc9, 0x17, 0x12, 0x4a, 0xce, 0x4f, 0xce, 0x2e, 0xca, 0x4f, 0x4c, 0xce, 0xd0, 0x83, 0xa9,
|
||||
0x90, 0x12, 0x85, 0xab, 0x85, 0x30, 0x20, 0x4a, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x4c,
|
||||
0x7d, 0x10, 0x0b, 0x22, 0xaa, 0x14, 0xc7, 0xc5, 0xed, 0x9b, 0x58, 0x94, 0x1d, 0x90, 0x58, 0x99,
|
||||
0x93, 0x9f, 0x98, 0x22, 0x24, 0xc0, 0xc5, 0x9c, 0x5b, 0x9c, 0x2e, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1,
|
||||
0x19, 0x04, 0x62, 0x0a, 0xd9, 0x72, 0xb1, 0x96, 0x54, 0x16, 0xa4, 0x16, 0x4b, 0x30, 0x29, 0x30,
|
||||
0x6b, 0x70, 0x1b, 0x29, 0xea, 0x61, 0xda, 0xa8, 0xe7, 0x0a, 0x62, 0x84, 0x54, 0x16, 0xa4, 0x82,
|
||||
0x8c, 0x72, 0x62, 0x39, 0x71, 0x4f, 0x9e, 0x21, 0x08, 0xa2, 0xcb, 0x49, 0xeb, 0xc4, 0x43, 0x39,
|
||||
0x86, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0xbc, 0xf1, 0x48, 0x8e, 0xf1, 0xc1, 0x23,
|
||||
0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x8a,
|
||||
0x03, 0x66, 0x4c, 0x12, 0x1b, 0xd8, 0x49, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x43,
|
||||
0x45, 0xef, 0xed, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *MarkPayload) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *MarkPayload) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *MarkPayload) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Types) > 0 {
|
||||
for iNdEx := len(m.Types) - 1; iNdEx >= 0; iNdEx-- {
|
||||
{
|
||||
size, err := m.Types[iNdEx].MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintMarkers(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
}
|
||||
if len(m.Msg) > 0 {
|
||||
i -= len(m.Msg)
|
||||
copy(dAtA[i:], m.Msg)
|
||||
i = encodeVarintMarkers(dAtA, i, uint64(len(m.Msg)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintMarkers(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovMarkers(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *MarkPayload) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Msg)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovMarkers(uint64(l))
|
||||
}
|
||||
if len(m.Types) > 0 {
|
||||
for _, e := range m.Types {
|
||||
l = e.Size()
|
||||
n += 1 + l + sovMarkers(uint64(l))
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovMarkers(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func sozMarkers(x uint64) (n int) {
|
||||
return sovMarkers(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *MarkPayload) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowMarkers
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: MarkPayload: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: MarkPayload: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowMarkers
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthMarkers
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthMarkers
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Msg = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Types", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowMarkers
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthMarkers
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthMarkers
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Types = append(m.Types, ErrorTypeMark{})
|
||||
if err := m.Types[len(m.Types)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipMarkers(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthMarkers
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipMarkers(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowMarkers
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowMarkers
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowMarkers
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthMarkers
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroupMarkers
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthMarkers
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthMarkers = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowMarkers = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupMarkers = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
||||
14
vendor/github.com/cockroachdb/errors/errorspb/markers.proto
generated
vendored
Normal file
14
vendor/github.com/cockroachdb/errors/errorspb/markers.proto
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
syntax = "proto3";
|
||||
package cockroach.errorspb;
|
||||
option go_package = "errorspb";
|
||||
|
||||
import "errorspb/errors.proto";
|
||||
import "gogoproto/gogo.proto";
|
||||
|
||||
// MarkPayload is the error payload for a forced marker.
|
||||
// See errors/markers/markers.go and the RFC on
|
||||
// error handling for details.
|
||||
message MarkPayload {
|
||||
string msg = 1;
|
||||
repeated ErrorTypeMark types = 2 [(gogoproto.nullable) = false];
|
||||
}
|
||||
525
vendor/github.com/cockroachdb/errors/errorspb/tags.pb.go
generated
vendored
Normal file
525
vendor/github.com/cockroachdb/errors/errorspb/tags.pb.go
generated
vendored
Normal file
@@ -0,0 +1,525 @@
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: errorspb/tags.proto
|
||||
|
||||
package errorspb
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
// TagsPayload is the error payload for a WithContext
|
||||
// marker.
|
||||
// See errors/contexttags/withcontext.go and the RFC on
|
||||
// error handling for details.
|
||||
type TagsPayload struct {
|
||||
Tags []TagPayload `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags"`
|
||||
}
|
||||
|
||||
func (m *TagsPayload) Reset() { *m = TagsPayload{} }
|
||||
func (m *TagsPayload) String() string { return proto.CompactTextString(m) }
|
||||
func (*TagsPayload) ProtoMessage() {}
|
||||
func (*TagsPayload) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2f0d1dc5c54e9f63, []int{0}
|
||||
}
|
||||
func (m *TagsPayload) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *TagsPayload) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
func (m *TagsPayload) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_TagsPayload.Merge(m, src)
|
||||
}
|
||||
func (m *TagsPayload) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *TagsPayload) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_TagsPayload.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_TagsPayload proto.InternalMessageInfo
|
||||
|
||||
type TagPayload struct {
|
||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (m *TagPayload) Reset() { *m = TagPayload{} }
|
||||
func (m *TagPayload) String() string { return proto.CompactTextString(m) }
|
||||
func (*TagPayload) ProtoMessage() {}
|
||||
func (*TagPayload) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2f0d1dc5c54e9f63, []int{1}
|
||||
}
|
||||
func (m *TagPayload) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *TagPayload) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
func (m *TagPayload) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_TagPayload.Merge(m, src)
|
||||
}
|
||||
func (m *TagPayload) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *TagPayload) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_TagPayload.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_TagPayload proto.InternalMessageInfo
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*TagsPayload)(nil), "cockroach.errorspb.TagsPayload")
|
||||
proto.RegisterType((*TagPayload)(nil), "cockroach.errorspb.TagPayload")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("errorspb/tags.proto", fileDescriptor_2f0d1dc5c54e9f63) }
|
||||
|
||||
var fileDescriptor_2f0d1dc5c54e9f63 = []byte{
|
||||
// 201 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4e, 0x2d, 0x2a, 0xca,
|
||||
0x2f, 0x2a, 0x2e, 0x48, 0xd2, 0x2f, 0x49, 0x4c, 0x2f, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17,
|
||||
0x12, 0x4a, 0xce, 0x4f, 0xce, 0x2e, 0xca, 0x4f, 0x4c, 0xce, 0xd0, 0x83, 0x49, 0x4b, 0x89, 0xa4,
|
||||
0xe7, 0xa7, 0xe7, 0x83, 0xa5, 0xf5, 0x41, 0x2c, 0x88, 0x4a, 0x25, 0x77, 0x2e, 0xee, 0x90, 0xc4,
|
||||
0xf4, 0xe2, 0x80, 0xc4, 0xca, 0x9c, 0xfc, 0xc4, 0x14, 0x21, 0x0b, 0x2e, 0x16, 0x90, 0x31, 0x12,
|
||||
0x8c, 0x0a, 0xcc, 0x1a, 0xdc, 0x46, 0x72, 0x7a, 0x98, 0xe6, 0xe8, 0x85, 0x24, 0xa6, 0x43, 0x55,
|
||||
0x3b, 0xb1, 0x9c, 0xb8, 0x27, 0xcf, 0x10, 0x04, 0xd6, 0xa1, 0x64, 0xc2, 0xc5, 0x85, 0x90, 0x11,
|
||||
0x12, 0xe0, 0x62, 0x2e, 0x49, 0x4c, 0x97, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x02, 0x31, 0x85,
|
||||
0x44, 0xb8, 0x58, 0xcb, 0x12, 0x73, 0x4a, 0x53, 0x25, 0x98, 0xc0, 0x62, 0x10, 0x8e, 0x93, 0xd6,
|
||||
0x89, 0x87, 0x72, 0x0c, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0x78, 0xe3, 0x91, 0x1c,
|
||||
0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1,
|
||||
0x1c, 0x43, 0x14, 0x07, 0xcc, 0xe2, 0x24, 0x36, 0xb0, 0x8b, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff,
|
||||
0xff, 0x0a, 0x90, 0xd1, 0xc9, 0xf2, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *TagsPayload) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *TagsPayload) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *TagsPayload) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Tags) > 0 {
|
||||
for iNdEx := len(m.Tags) - 1; iNdEx >= 0; iNdEx-- {
|
||||
{
|
||||
size, err := m.Tags[iNdEx].MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintTags(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *TagPayload) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *TagPayload) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *TagPayload) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Value) > 0 {
|
||||
i -= len(m.Value)
|
||||
copy(dAtA[i:], m.Value)
|
||||
i = encodeVarintTags(dAtA, i, uint64(len(m.Value)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
if len(m.Tag) > 0 {
|
||||
i -= len(m.Tag)
|
||||
copy(dAtA[i:], m.Tag)
|
||||
i = encodeVarintTags(dAtA, i, uint64(len(m.Tag)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintTags(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovTags(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *TagsPayload) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Tags) > 0 {
|
||||
for _, e := range m.Tags {
|
||||
l = e.Size()
|
||||
n += 1 + l + sovTags(uint64(l))
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *TagPayload) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Tag)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovTags(uint64(l))
|
||||
}
|
||||
l = len(m.Value)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovTags(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovTags(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func sozTags(x uint64) (n int) {
|
||||
return sovTags(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *TagsPayload) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTags
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: TagsPayload: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: TagsPayload: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Tags", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTags
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthTags
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthTags
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Tags = append(m.Tags, TagPayload{})
|
||||
if err := m.Tags[len(m.Tags)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipTags(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthTags
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *TagPayload) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTags
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: TagPayload: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: TagPayload: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Tag", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTags
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthTags
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthTags
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Tag = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTags
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthTags
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthTags
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Value = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipTags(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthTags
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipTags(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowTags
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowTags
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowTags
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthTags
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroupTags
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthTags
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthTags = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowTags = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupTags = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
||||
18
vendor/github.com/cockroachdb/errors/errorspb/tags.proto
generated
vendored
Normal file
18
vendor/github.com/cockroachdb/errors/errorspb/tags.proto
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
syntax = "proto3";
|
||||
package cockroach.errorspb;
|
||||
option go_package = "errorspb";
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
|
||||
// TagsPayload is the error payload for a WithContext
|
||||
// marker.
|
||||
// See errors/contexttags/withcontext.go and the RFC on
|
||||
// error handling for details.
|
||||
message TagsPayload {
|
||||
repeated TagPayload tags = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message TagPayload {
|
||||
string tag = 1;
|
||||
string value = 2;
|
||||
}
|
||||
18
vendor/github.com/cockroachdb/errors/errorspb/testing.go
generated
vendored
Normal file
18
vendor/github.com/cockroachdb/errors/errorspb/testing.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 errorspb
|
||||
|
||||
// Error implements the error interface.
|
||||
func (t *TestError) Error() string { return "test error" }
|
||||
258
vendor/github.com/cockroachdb/errors/errorspb/testing.pb.go
generated
vendored
Normal file
258
vendor/github.com/cockroachdb/errors/errorspb/testing.pb.go
generated
vendored
Normal file
@@ -0,0 +1,258 @@
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: errorspb/testing.proto
|
||||
|
||||
package errorspb
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
// TestError is meant for use in testing only.
|
||||
type TestError struct {
|
||||
}
|
||||
|
||||
func (m *TestError) Reset() { *m = TestError{} }
|
||||
func (m *TestError) String() string { return proto.CompactTextString(m) }
|
||||
func (*TestError) ProtoMessage() {}
|
||||
func (*TestError) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_0551f0d913d6118f, []int{0}
|
||||
}
|
||||
func (m *TestError) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *TestError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
func (m *TestError) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_TestError.Merge(m, src)
|
||||
}
|
||||
func (m *TestError) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *TestError) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_TestError.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_TestError proto.InternalMessageInfo
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*TestError)(nil), "cockroach.errorspb.TestError")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("errorspb/testing.proto", fileDescriptor_0551f0d913d6118f) }
|
||||
|
||||
var fileDescriptor_0551f0d913d6118f = []byte{
|
||||
// 118 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4b, 0x2d, 0x2a, 0xca,
|
||||
0x2f, 0x2a, 0x2e, 0x48, 0xd2, 0x2f, 0x49, 0x2d, 0x2e, 0xc9, 0xcc, 0x4b, 0xd7, 0x2b, 0x28, 0xca,
|
||||
0x2f, 0xc9, 0x17, 0x12, 0x4a, 0xce, 0x4f, 0xce, 0x2e, 0xca, 0x4f, 0x4c, 0xce, 0xd0, 0x83, 0xa9,
|
||||
0x50, 0xe2, 0xe6, 0xe2, 0x0c, 0x49, 0x2d, 0x2e, 0x71, 0x05, 0xf1, 0x9d, 0xb4, 0x4e, 0x3c, 0x94,
|
||||
0x63, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x1b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c,
|
||||
0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2,
|
||||
0x38, 0x60, 0x1a, 0x93, 0xd8, 0xc0, 0x66, 0x1a, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x4b, 0xf3,
|
||||
0x3e, 0x92, 0x6d, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *TestError) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *TestError) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *TestError) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintTesting(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovTesting(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *TestError) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
return n
|
||||
}
|
||||
|
||||
func sovTesting(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func sozTesting(x uint64) (n int) {
|
||||
return sovTesting(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *TestError) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTesting
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: TestError: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: TestError: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipTesting(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthTesting
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipTesting(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowTesting
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowTesting
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowTesting
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthTesting
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroupTesting
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthTesting
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthTesting = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowTesting = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupTesting = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
||||
6
vendor/github.com/cockroachdb/errors/errorspb/testing.proto
generated
vendored
Normal file
6
vendor/github.com/cockroachdb/errors/errorspb/testing.proto
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
syntax = "proto3";
|
||||
package cockroach.errorspb;
|
||||
option go_package = "errorspb";
|
||||
|
||||
// TestError is meant for use in testing only.
|
||||
message TestError{}
|
||||
74
vendor/github.com/cockroachdb/errors/errutil/as.go
generated
vendored
Normal file
74
vendor/github.com/cockroachdb/errors/errutil/as.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 errutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
)
|
||||
|
||||
// As finds the first error in err's chain that matches the type to which target
|
||||
// points, and if so, sets the target to its value and returns true. An error
|
||||
// matches a type if it is assignable to the target type, or if it has a method
|
||||
// As(interface{}) bool such that As(target) returns true. As will panic if target
|
||||
// is not a non-nil pointer to a type which implements error or is of interface type.
|
||||
//
|
||||
// The As method should set the target to its value and return true if err
|
||||
// matches the type to which target points.
|
||||
//
|
||||
// Note: this implementation differs from that of xerrors as follows:
|
||||
// - it also supports recursing through causes with Cause().
|
||||
// - if it detects an API use error, its panic object is a valid error.
|
||||
func As(err error, target interface{}) bool {
|
||||
if target == nil {
|
||||
panic(AssertionFailedf("errors.As: target cannot be nil"))
|
||||
}
|
||||
|
||||
// We use introspection for now, of course when/if Go gets generics
|
||||
// all this can go away.
|
||||
val := reflect.ValueOf(target)
|
||||
typ := val.Type()
|
||||
if typ.Kind() != reflect.Ptr || val.IsNil() {
|
||||
panic(AssertionFailedf("errors.As: target must be a non-nil pointer, found %T", target))
|
||||
}
|
||||
if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) {
|
||||
panic(AssertionFailedf("errors.As: *target must be interface or implement error, found %T", target))
|
||||
}
|
||||
|
||||
targetType := typ.Elem()
|
||||
for c := err; c != nil; c = errbase.UnwrapOnce(c) {
|
||||
if reflect.TypeOf(c).AssignableTo(targetType) {
|
||||
val.Elem().Set(reflect.ValueOf(c))
|
||||
return true
|
||||
}
|
||||
if x, ok := c.(interface{ As(interface{}) bool }); ok && x.As(target) {
|
||||
return true
|
||||
}
|
||||
|
||||
// If at any point in the single cause chain including the top,
|
||||
// we encounter a multi-cause chain, recursively explore it.
|
||||
for _, cause := range errbase.UnwrapMulti(c) {
|
||||
if As(cause, target) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var errorType = reflect.TypeOf((*error)(nil)).Elem()
|
||||
80
vendor/github.com/cockroachdb/errors/errutil/assertions.go
generated
vendored
Normal file
80
vendor/github.com/cockroachdb/errors/errutil/assertions.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 errutil
|
||||
|
||||
import (
|
||||
"github.com/cockroachdb/errors/assert"
|
||||
"github.com/cockroachdb/errors/barriers"
|
||||
"github.com/cockroachdb/errors/withstack"
|
||||
)
|
||||
|
||||
// AssertionFailedf creates an internal error.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`, shows redacted strings.
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func AssertionFailedf(format string, args ...interface{}) error {
|
||||
return AssertionFailedWithDepthf(1, format, args...)
|
||||
}
|
||||
|
||||
// AssertionFailedWithDepthf creates an internal error
|
||||
// with a stack trace collected at the specified depth.
|
||||
// See the doc of `AssertionFailedf()` for more details.
|
||||
func AssertionFailedWithDepthf(depth int, format string, args ...interface{}) error {
|
||||
err := NewWithDepthf(1+depth, format, args...)
|
||||
err = assert.WithAssertionFailure(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// HandleAsAssertionFailure hides an error and turns it into
|
||||
// an assertion failure. Both details from the original error and the
|
||||
// context of the caller are preserved. The original error is not
|
||||
// visible as cause any more. The original error message is preserved.
|
||||
// See the doc of `AssertionFailedf()` for more details.
|
||||
func HandleAsAssertionFailure(origErr error) error {
|
||||
return HandleAsAssertionFailureDepth(1, origErr)
|
||||
}
|
||||
|
||||
// HandleAsAssertionFailureDepth is like HandleAsAssertionFailure but
|
||||
// the depth at which the call stack is captured can be specified.
|
||||
func HandleAsAssertionFailureDepth(depth int, origErr error) error {
|
||||
err := barriers.Handled(origErr)
|
||||
err = withstack.WithStackDepth(err, 1+depth)
|
||||
err = assert.WithAssertionFailure(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// NewAssertionErrorWithWrappedErrf wraps an error and turns it into
|
||||
// an assertion error. Both details from the original error and the
|
||||
// context of the caller are preserved. The original error is not
|
||||
// visible as cause any more. The original error message is preserved.
|
||||
// See the doc of `AssertionFailedf()` for more details.
|
||||
func NewAssertionErrorWithWrappedErrf(origErr error, format string, args ...interface{}) error {
|
||||
return NewAssertionErrorWithWrappedErrDepthf(1, origErr, format, args...)
|
||||
}
|
||||
|
||||
// NewAssertionErrorWithWrappedErrDepthf is like
|
||||
// NewAssertionErrorWithWrappedErrf but the depth at which the call
|
||||
// stack is captured can be specified.
|
||||
// See the doc of `AssertionFailedf()` for more details.
|
||||
func NewAssertionErrorWithWrappedErrDepthf(
|
||||
depth int, origErr error, format string, args ...interface{},
|
||||
) error {
|
||||
err := barriers.Handled(origErr)
|
||||
err = WrapWithDepthf(depth+1, err, format, args...)
|
||||
err = assert.WithAssertionFailure(err)
|
||||
return err
|
||||
}
|
||||
19
vendor/github.com/cockroachdb/errors/errutil/doc.go
generated
vendored
Normal file
19
vendor/github.com/cockroachdb/errors/errutil/doc.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 errutil combines primitives from the library, the Go errors
|
||||
// package and github.com/pkg/errors. It aims to serve as drop-in
|
||||
// replacement to github.com/pkg/errors and replace the legacy
|
||||
// implementation of `pgerrors`.
|
||||
package errutil
|
||||
88
vendor/github.com/cockroachdb/errors/errutil/format_error_special.go
generated
vendored
Normal file
88
vendor/github.com/cockroachdb/errors/errutil/format_error_special.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
// Copyright 2020 The Cockroach Authors.
|
||||
//
|
||||
// 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 errutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/errors/markers"
|
||||
"github.com/cockroachdb/redact"
|
||||
)
|
||||
|
||||
func init() {
|
||||
errbase.RegisterSpecialCasePrinter(specialCaseFormat)
|
||||
}
|
||||
|
||||
func specialCaseFormat(err error, p errbase.Printer, isLeaf bool) (handled bool, next error) {
|
||||
if isLeaf && markers.IsAny(err,
|
||||
context.DeadlineExceeded,
|
||||
context.Canceled,
|
||||
os.ErrInvalid,
|
||||
os.ErrPermission,
|
||||
os.ErrExist,
|
||||
os.ErrNotExist,
|
||||
os.ErrClosed,
|
||||
os.ErrNoDeadline) {
|
||||
p.Print(redact.Safe(err.Error()))
|
||||
return true, nil
|
||||
}
|
||||
|
||||
switch v := err.(type) {
|
||||
// The following two types are safe too.
|
||||
case runtime.Error:
|
||||
p.Print(redact.Safe(v.Error()))
|
||||
return true, err
|
||||
case syscall.Errno:
|
||||
p.Print(redact.Safe(v.Error()))
|
||||
return true, err
|
||||
case *os.SyscallError:
|
||||
p.Print(redact.Safe(v.Syscall))
|
||||
return true, err
|
||||
case *os.PathError:
|
||||
p.Printf("%s %s", redact.Safe(v.Op), v.Path)
|
||||
return true, err
|
||||
case *os.LinkError:
|
||||
p.Printf("%s %s %s", redact.Safe(v.Op), v.Old, v.New)
|
||||
return true, err
|
||||
case *net.OpError:
|
||||
p.Print(redact.Safe(v.Op))
|
||||
if v.Net != "" {
|
||||
p.Printf(" %s", redact.Safe(v.Net))
|
||||
}
|
||||
if v.Source != nil {
|
||||
p.Printf(" %s", v.Source)
|
||||
}
|
||||
if v.Addr != nil {
|
||||
if v.Source != nil {
|
||||
p.Printf(" ->")
|
||||
}
|
||||
p.Printf(" %s", v.Addr)
|
||||
}
|
||||
return true, err
|
||||
case redact.SafeMessager:
|
||||
// Backward-compatibility with previous versions
|
||||
// of the errors library: if an error type implements
|
||||
// SafeMessage(), use that instead of its error message.
|
||||
p.Print(redact.Safe(v.SafeMessage()))
|
||||
// It also short-cuts any further causes.
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
45
vendor/github.com/cockroachdb/errors/errutil/message.go
generated
vendored
Normal file
45
vendor/github.com/cockroachdb/errors/errutil/message.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 errutil
|
||||
|
||||
import "github.com/cockroachdb/redact"
|
||||
|
||||
// WithMessage annotates err with a new message.
|
||||
// If err is nil, WithMessage returns nil.
|
||||
// The message is considered safe for reporting
|
||||
// and is included in Sentry reports.
|
||||
func WithMessage(err error, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withPrefix{
|
||||
cause: err,
|
||||
prefix: redact.Sprint(redact.Safe(message)),
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessagef annotates err with the format specifier.
|
||||
// If err is nil, WithMessagef returns nil.
|
||||
// The message is formatted as per redact.Sprintf,
|
||||
// to separate safe and unsafe strings for Sentry reporting.
|
||||
func WithMessagef(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withPrefix{
|
||||
cause: err,
|
||||
prefix: redact.Sprintf(format, args...),
|
||||
}
|
||||
}
|
||||
163
vendor/github.com/cockroachdb/errors/errutil/redactable.go
generated
vendored
Normal file
163
vendor/github.com/cockroachdb/errors/errutil/redactable.go
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
package errutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/errors/errorspb"
|
||||
"github.com/cockroachdb/redact"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// leafError is like the basic error string in the stdlib except the
|
||||
// message can contain redactable and non-redactable parts.
|
||||
type leafError struct {
|
||||
msg redact.RedactableString
|
||||
}
|
||||
|
||||
var _ error = (*leafError)(nil)
|
||||
var _ fmt.Formatter = (*leafError)(nil)
|
||||
var _ errbase.SafeFormatter = (*leafError)(nil)
|
||||
var _ errbase.SafeDetailer = (*leafError)(nil)
|
||||
|
||||
func (l *leafError) Error() string { return l.msg.StripMarkers() }
|
||||
func (l *leafError) Format(s fmt.State, verb rune) { errbase.FormatError(l, s, verb) }
|
||||
func (l *leafError) SafeFormatError(p errbase.Printer) (next error) {
|
||||
p.Print(l.msg)
|
||||
return nil
|
||||
}
|
||||
func (l *leafError) SafeDetails() []string {
|
||||
return []string{l.msg.Redact().StripMarkers()}
|
||||
}
|
||||
|
||||
func encodeLeaf(_ context.Context, err error) (string, []string, proto.Message) {
|
||||
l := err.(*leafError)
|
||||
return l.Error(), l.SafeDetails(), &errorspb.StringPayload{Msg: string(l.msg)}
|
||||
}
|
||||
|
||||
func decodeLeaf(_ context.Context, _ string, _ []string, payload proto.Message) error {
|
||||
m, ok := payload.(*errorspb.StringPayload)
|
||||
if !ok {
|
||||
// If this ever happens, this means some version of the library
|
||||
// (presumably future) changed the payload type, and we're
|
||||
// receiving this here. In this case, give up and let
|
||||
// DecodeError use the opaque type.
|
||||
return nil
|
||||
}
|
||||
return &leafError{msg: redact.RedactableString(m.Msg)}
|
||||
}
|
||||
|
||||
func init() {
|
||||
errbase.RegisterLeafEncoder(errbase.GetTypeKey((*leafError)(nil)), encodeLeaf)
|
||||
errbase.RegisterLeafDecoder(errbase.GetTypeKey((*leafError)(nil)), decodeLeaf)
|
||||
}
|
||||
|
||||
// withPrefix is like withMessage but the
|
||||
// message can contain redactable and non-redactable parts.
|
||||
type withPrefix struct {
|
||||
cause error
|
||||
prefix redact.RedactableString
|
||||
}
|
||||
|
||||
var _ error = (*withPrefix)(nil)
|
||||
var _ fmt.Formatter = (*withPrefix)(nil)
|
||||
var _ errbase.SafeFormatter = (*withPrefix)(nil)
|
||||
var _ errbase.SafeDetailer = (*withPrefix)(nil)
|
||||
|
||||
func (l *withPrefix) Error() string {
|
||||
if l.prefix == "" {
|
||||
return l.cause.Error()
|
||||
}
|
||||
return fmt.Sprintf("%s: %v", l.prefix.StripMarkers(), l.cause)
|
||||
}
|
||||
|
||||
func (l *withPrefix) Cause() error { return l.cause }
|
||||
func (l *withPrefix) Unwrap() error { return l.cause }
|
||||
|
||||
func (l *withPrefix) Format(s fmt.State, verb rune) { errbase.FormatError(l, s, verb) }
|
||||
func (l *withPrefix) SafeFormatError(p errbase.Printer) (next error) {
|
||||
p.Print(l.prefix)
|
||||
return l.cause
|
||||
}
|
||||
|
||||
func (l *withPrefix) SafeDetails() []string {
|
||||
return []string{l.prefix.Redact().StripMarkers()}
|
||||
}
|
||||
|
||||
func encodeWithPrefix(_ context.Context, err error) (string, []string, proto.Message) {
|
||||
l := err.(*withPrefix)
|
||||
return l.Error(), l.SafeDetails(), &errorspb.StringPayload{Msg: string(l.prefix)}
|
||||
}
|
||||
|
||||
func decodeWithPrefix(
|
||||
_ context.Context, cause error, _ string, _ []string, payload proto.Message,
|
||||
) error {
|
||||
m, ok := payload.(*errorspb.StringPayload)
|
||||
if !ok {
|
||||
// If this ever happens, this means some version of the library
|
||||
// (presumably future) changed the payload type, and we're
|
||||
// receiving this here. In this case, give up and let
|
||||
// DecodeError use the opaque type.
|
||||
return nil
|
||||
}
|
||||
return &withPrefix{cause: cause, prefix: redact.RedactableString(m.Msg)}
|
||||
}
|
||||
|
||||
func init() {
|
||||
errbase.RegisterWrapperEncoder(errbase.GetTypeKey((*withPrefix)(nil)), encodeWithPrefix)
|
||||
errbase.RegisterWrapperDecoder(errbase.GetTypeKey((*withPrefix)(nil)), decodeWithPrefix)
|
||||
}
|
||||
|
||||
// withNewMessage is like withPrefix but the message completely
|
||||
// overrides that of the underlying error.
|
||||
type withNewMessage struct {
|
||||
cause error
|
||||
message redact.RedactableString
|
||||
}
|
||||
|
||||
var _ error = (*withNewMessage)(nil)
|
||||
var _ fmt.Formatter = (*withNewMessage)(nil)
|
||||
var _ errbase.SafeFormatter = (*withNewMessage)(nil)
|
||||
var _ errbase.SafeDetailer = (*withNewMessage)(nil)
|
||||
|
||||
func (l *withNewMessage) Error() string {
|
||||
return l.message.StripMarkers()
|
||||
}
|
||||
|
||||
func (l *withNewMessage) Cause() error { return l.cause }
|
||||
func (l *withNewMessage) Unwrap() error { return l.cause }
|
||||
|
||||
func (l *withNewMessage) Format(s fmt.State, verb rune) { errbase.FormatError(l, s, verb) }
|
||||
func (l *withNewMessage) SafeFormatError(p errbase.Printer) (next error) {
|
||||
p.Print(l.message)
|
||||
return nil /* nil here overrides the cause's message */
|
||||
}
|
||||
|
||||
func (l *withNewMessage) SafeDetails() []string {
|
||||
return []string{l.message.Redact().StripMarkers()}
|
||||
}
|
||||
|
||||
func encodeWithNewMessage(_ context.Context, err error) (string, []string, proto.Message) {
|
||||
l := err.(*withNewMessage)
|
||||
return l.Error(), l.SafeDetails(), &errorspb.StringPayload{Msg: string(l.message)}
|
||||
}
|
||||
|
||||
func decodeWithNewMessage(
|
||||
_ context.Context, cause error, _ string, _ []string, payload proto.Message,
|
||||
) error {
|
||||
m, ok := payload.(*errorspb.StringPayload)
|
||||
if !ok {
|
||||
// If this ever happens, this means some version of the library
|
||||
// (presumably future) changed the payload type, and we're
|
||||
// receiving this here. In this case, give up and let
|
||||
// DecodeError use the opaque type.
|
||||
return nil
|
||||
}
|
||||
return &withNewMessage{cause: cause, message: redact.RedactableString(m.Msg)}
|
||||
}
|
||||
|
||||
func init() {
|
||||
errbase.RegisterWrapperEncoder(errbase.GetTypeKey((*withNewMessage)(nil)), encodeWithNewMessage)
|
||||
errbase.RegisterWrapperDecoder(errbase.GetTypeKey((*withNewMessage)(nil)), decodeWithNewMessage)
|
||||
}
|
||||
168
vendor/github.com/cockroachdb/errors/errutil/utilities.go
generated
vendored
Normal file
168
vendor/github.com/cockroachdb/errors/errutil/utilities.go
generated
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 errutil
|
||||
|
||||
import (
|
||||
"github.com/cockroachdb/errors/join"
|
||||
"github.com/cockroachdb/errors/secondary"
|
||||
"github.com/cockroachdb/errors/withstack"
|
||||
"github.com/cockroachdb/redact"
|
||||
)
|
||||
|
||||
// New creates an error with a simple error message.
|
||||
// A stack trace is retained.
|
||||
//
|
||||
// Note: the message string is assumed to not contain
|
||||
// PII and is included in Sentry reports.
|
||||
// Use errors.Newf("%s", <unsafestring>) for errors
|
||||
// strings that may contain PII information.
|
||||
//
|
||||
// Detail output:
|
||||
// - message via `Error()` and formatting using `%v`/`%s`/`%q`.
|
||||
// - everything when formatting with `%+v`.
|
||||
// - stack trace and message via `errors.GetSafeDetails()`.
|
||||
// - stack trace and message in Sentry reports.
|
||||
func New(msg string) error {
|
||||
return NewWithDepth(1, msg)
|
||||
}
|
||||
|
||||
// NewWithDepth is like New() except the depth to capture the stack
|
||||
// trace is configurable.
|
||||
// See the doc of `New()` for more details.
|
||||
func NewWithDepth(depth int, msg string) error {
|
||||
err := error(&leafError{redact.Sprint(redact.Safe(msg))})
|
||||
err = withstack.WithStackDepth(err, 1+depth)
|
||||
return err
|
||||
}
|
||||
|
||||
// Newf creates an error with a formatted error message.
|
||||
// A stack trace is retained.
|
||||
//
|
||||
// Note: the format string is assumed to not contain
|
||||
// PII and is included in Sentry reports.
|
||||
// Use errors.Newf("%s", <unsafestring>) for errors
|
||||
// strings that may contain PII information.
|
||||
//
|
||||
// See the doc of `New()` for more details.
|
||||
func Newf(format string, args ...interface{}) error {
|
||||
return NewWithDepthf(1, format, args...)
|
||||
}
|
||||
|
||||
// NewWithDepthf is like Newf() except the depth to capture the stack
|
||||
// trace is configurable.
|
||||
// See the doc of `New()` for more details.
|
||||
func NewWithDepthf(depth int, format string, args ...interface{}) error {
|
||||
// If there's the verb %w in here, shortcut to fmt.Errorf()
|
||||
// and store the safe details as extra payload. That's
|
||||
// because we don't want to re-implement the error wrapping
|
||||
// logic from 'fmt' in there.
|
||||
var err error
|
||||
var errRefs []error
|
||||
for _, a := range args {
|
||||
if e, ok := a.(error); ok {
|
||||
errRefs = append(errRefs, e)
|
||||
}
|
||||
}
|
||||
redactable, wrappedErr := redact.HelperForErrorf(format, args...)
|
||||
if wrappedErr != nil {
|
||||
err = &withNewMessage{cause: wrappedErr, message: redactable}
|
||||
} else {
|
||||
err = &leafError{redactable}
|
||||
}
|
||||
for _, e := range errRefs {
|
||||
err = secondary.WithSecondaryError(err, e)
|
||||
}
|
||||
err = withstack.WithStackDepth(err, 1+depth)
|
||||
return err
|
||||
}
|
||||
|
||||
// Wrap wraps an error with a message prefix.
|
||||
// A stack trace is retained.
|
||||
//
|
||||
// Note: the prefix string is assumed to not contain
|
||||
// PII and is included in Sentry reports.
|
||||
// Use errors.Wrapf(err, "%s", <unsafestring>) for errors
|
||||
// strings that may contain PII information.
|
||||
//
|
||||
// Detail output:
|
||||
// - original error message + prefix via `Error()` and formatting using `%v`/`%s`/`%q`.
|
||||
// - everything when formatting with `%+v`.
|
||||
// - stack trace and message via `errors.GetSafeDetails()`.
|
||||
// - stack trace and message in Sentry reports.
|
||||
func Wrap(err error, msg string) error {
|
||||
return WrapWithDepth(1, err, msg)
|
||||
}
|
||||
|
||||
// WrapWithDepth is like Wrap except the depth to capture the stack
|
||||
// trace is configurable.
|
||||
// The the doc of `Wrap()` for more details.
|
||||
func WrapWithDepth(depth int, err error, msg string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if msg != "" {
|
||||
err = WithMessage(err, msg)
|
||||
}
|
||||
err = withstack.WithStackDepth(err, depth+1)
|
||||
return err
|
||||
}
|
||||
|
||||
// Wrapf wraps an error with a formatted message prefix. A stack
|
||||
// trace is also retained. If the format is empty, no prefix is added,
|
||||
// but the extra arguments are still processed for reportable strings.
|
||||
//
|
||||
// Note: the format string is assumed to not contain
|
||||
// PII and is included in Sentry reports.
|
||||
// Use errors.Wrapf(err, "%s", <unsafestring>) for errors
|
||||
// strings that may contain PII information.
|
||||
//
|
||||
// Detail output:
|
||||
// - original error message + prefix via `Error()` and formatting using `%v`/`%s`/`%q`.
|
||||
// - everything when formatting with `%+v`.
|
||||
// - stack trace, format, and redacted details via `errors.GetSafeDetails()`.
|
||||
// - stack trace, format, and redacted details in Sentry reports.
|
||||
func Wrapf(err error, format string, args ...interface{}) error {
|
||||
return WrapWithDepthf(1, err, format, args...)
|
||||
}
|
||||
|
||||
// WrapWithDepthf is like Wrapf except the depth to capture the stack
|
||||
// trace is configurable.
|
||||
// The the doc of `Wrapf()` for more details.
|
||||
func WrapWithDepthf(depth int, err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
var errRefs []error
|
||||
for _, a := range args {
|
||||
if e, ok := a.(error); ok {
|
||||
errRefs = append(errRefs, e)
|
||||
}
|
||||
}
|
||||
if format != "" || len(args) > 0 {
|
||||
err = WithMessagef(err, format, args...)
|
||||
}
|
||||
for _, e := range errRefs {
|
||||
err = secondary.WithSecondaryError(err, e)
|
||||
}
|
||||
err = withstack.WithStackDepth(err, depth+1)
|
||||
return err
|
||||
}
|
||||
|
||||
// JoinWithDepth constructs a Join error with the provided list of
|
||||
// errors as arguments, and wraps it in a `WithStackDepth` to capture a
|
||||
// stacktrace alongside.
|
||||
func JoinWithDepth(depth int, errs ...error) error {
|
||||
return withstack.WithStackDepth(join.Join(errs...), depth+1)
|
||||
}
|
||||
210
vendor/github.com/cockroachdb/errors/errutil_api.go
generated
vendored
Normal file
210
vendor/github.com/cockroachdb/errors/errutil_api.go
generated
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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
|
||||
|
||||
import (
|
||||
"github.com/cockroachdb/errors/barriers"
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/errors/errutil"
|
||||
)
|
||||
|
||||
// New creates an error with a simple error message.
|
||||
// A stack trace is retained.
|
||||
//
|
||||
// Note: the message string is assumed to not contain
|
||||
// PII and is included in Sentry reports.
|
||||
// Use errors.Newf("%s", <unsafestring>) for errors
|
||||
// strings that may contain PII information.
|
||||
//
|
||||
// Detail output:
|
||||
// - message via `Error()` and formatting using `%v`/`%s`/`%q`.
|
||||
// - everything when formatting with `%+v`.
|
||||
// - stack trace and message via `errors.GetSafeDetails()`.
|
||||
// - stack trace and message in Sentry reports.
|
||||
func New(msg string) error { return errutil.NewWithDepth(1, msg) }
|
||||
|
||||
// NewWithDepth is like New() except the depth to capture the stack
|
||||
// trace is configurable.
|
||||
// See the doc of `New()` for more details.
|
||||
func NewWithDepth(depth int, msg string) error { return errutil.NewWithDepth(depth+1, msg) }
|
||||
|
||||
// Newf creates an error with a formatted error message.
|
||||
// A stack trace is retained.
|
||||
//
|
||||
// Note: the format string is assumed to not contain
|
||||
// PII and is included in Sentry reports.
|
||||
// Use errors.Newf("%s", <unsafestring>) for errors
|
||||
// strings that may contain PII information.
|
||||
//
|
||||
// See the doc of `New()` for more details.
|
||||
func Newf(format string, args ...interface{}) error { return errutil.NewWithDepthf(1, format, args...) }
|
||||
|
||||
// NewWithDepthf is like Newf() except the depth to capture the stack
|
||||
// trace is configurable.
|
||||
// See the doc of `New()` for more details.
|
||||
func NewWithDepthf(depth int, format string, args ...interface{}) error {
|
||||
return errutil.NewWithDepthf(depth+1, format, args...)
|
||||
}
|
||||
|
||||
// Errorf aliases Newf().
|
||||
func Errorf(format string, args ...interface{}) error {
|
||||
return errutil.NewWithDepthf(1, format, args...)
|
||||
}
|
||||
|
||||
// Cause aliases UnwrapAll() for compatibility with github.com/pkg/errors.
|
||||
func Cause(err error) error { return errbase.UnwrapAll(err) }
|
||||
|
||||
// Unwrap aliases UnwrapOnce() for compatibility with xerrors.
|
||||
func Unwrap(err error) error { return errbase.UnwrapOnce(err) }
|
||||
|
||||
// Wrapper is the type of an error wrapper.
|
||||
type Wrapper interface {
|
||||
Unwrap() error
|
||||
}
|
||||
|
||||
// Opaque aliases barrier.Handled(), for compatibility with xerrors.
|
||||
func Opaque(err error) error { return barriers.Handled(err) }
|
||||
|
||||
// WithMessage annotates err with a new message.
|
||||
// If err is nil, WithMessage returns nil.
|
||||
// The message is considered safe for reporting
|
||||
// and is included in Sentry reports.
|
||||
func WithMessage(err error, msg string) error { return errutil.WithMessage(err, msg) }
|
||||
|
||||
// WithMessagef annotates err with the format specifier.
|
||||
// If err is nil, WithMessagef returns nil.
|
||||
// The message is formatted as per redact.Sprintf,
|
||||
// to separate safe and unsafe strings for Sentry reporting.
|
||||
func WithMessagef(err error, format string, args ...interface{}) error {
|
||||
return errutil.WithMessagef(err, format, args...)
|
||||
}
|
||||
|
||||
// Wrap wraps an error with a message prefix.
|
||||
// A stack trace is retained.
|
||||
//
|
||||
// Note: the prefix string is assumed to not contain
|
||||
// PII and is included in Sentry reports.
|
||||
// Use errors.Wrapf(err, "%s", <unsafestring>) for errors
|
||||
// strings that may contain PII information.
|
||||
//
|
||||
// Detail output:
|
||||
// - original error message + prefix via `Error()` and formatting using `%v`/`%s`/`%q`.
|
||||
// - everything when formatting with `%+v`.
|
||||
// - stack trace and message via `errors.GetSafeDetails()`.
|
||||
// - stack trace and message in Sentry reports.
|
||||
func Wrap(err error, msg string) error { return errutil.WrapWithDepth(1, err, msg) }
|
||||
|
||||
// WrapWithDepth is like Wrap except the depth to capture the stack
|
||||
// trace is configurable.
|
||||
// The the doc of `Wrap()` for more details.
|
||||
func WrapWithDepth(depth int, err error, msg string) error {
|
||||
return errutil.WrapWithDepth(depth+1, err, msg)
|
||||
}
|
||||
|
||||
// Wrapf wraps an error with a formatted message prefix. A stack
|
||||
// trace is also retained. If the format is empty, no prefix is added,
|
||||
// but the extra arguments are still processed for reportable strings.
|
||||
//
|
||||
// Note: the format string is assumed to not contain
|
||||
// PII and is included in Sentry reports.
|
||||
// Use errors.Wrapf(err, "%s", <unsafestring>) for errors
|
||||
// strings that may contain PII information.
|
||||
//
|
||||
// Detail output:
|
||||
// - original error message + prefix via `Error()` and formatting using `%v`/`%s`/`%q`.
|
||||
// - everything when formatting with `%+v`.
|
||||
// - stack trace, format, and redacted details via `errors.GetSafeDetails()`.
|
||||
// - stack trace, format, and redacted details in Sentry reports.
|
||||
func Wrapf(err error, format string, args ...interface{}) error {
|
||||
return errutil.WrapWithDepthf(1, err, format, args...)
|
||||
}
|
||||
|
||||
// WrapWithDepthf is like Wrapf except the depth to capture the stack
|
||||
// trace is configurable.
|
||||
// The the doc of `Wrapf()` for more details.
|
||||
func WrapWithDepthf(depth int, err error, format string, args ...interface{}) error {
|
||||
return errutil.WrapWithDepthf(depth+1, err, format, args...)
|
||||
}
|
||||
|
||||
// AssertionFailedf creates an internal error.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`, shows redacted strings.
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func AssertionFailedf(format string, args ...interface{}) error {
|
||||
return errutil.AssertionFailedWithDepthf(1, format, args...)
|
||||
}
|
||||
|
||||
// AssertionFailedWithDepthf creates an internal error
|
||||
// with a stack trace collected at the specified depth.
|
||||
// See the doc of `AssertionFailedf()` for more details.
|
||||
func AssertionFailedWithDepthf(depth int, format string, args ...interface{}) error {
|
||||
return errutil.AssertionFailedWithDepthf(depth+1, format, args...)
|
||||
}
|
||||
|
||||
// NewAssertionErrorWithWrappedErrf wraps an error and turns it into
|
||||
// an assertion error. Both details from the original error and the
|
||||
// context of the caller are preserved. The original error is not
|
||||
// visible as cause any more. The original error message is preserved.
|
||||
// See the doc of `AssertionFailedf()` for more details.
|
||||
func NewAssertionErrorWithWrappedErrf(origErr error, format string, args ...interface{}) error {
|
||||
return errutil.NewAssertionErrorWithWrappedErrDepthf(1, origErr, format, args...)
|
||||
}
|
||||
|
||||
// HandleAsAssertionFailure hides an error and turns it into
|
||||
// an assertion failure. Both details from the original error and the
|
||||
// context of the caller are preserved. The original error is not
|
||||
// visible as cause any more. The original error message is preserved.
|
||||
// See the doc of `AssertionFailedf()` for more details.
|
||||
func HandleAsAssertionFailure(origErr error) error {
|
||||
return errutil.HandleAsAssertionFailureDepth(1, origErr)
|
||||
}
|
||||
|
||||
// HandleAsAssertionFailureDepth is like HandleAsAssertionFailure but
|
||||
// the depth at which the call stack is captured can be specified.
|
||||
func HandleAsAssertionFailureDepth(depth int, origErr error) error {
|
||||
return errutil.HandleAsAssertionFailureDepth(1+depth, origErr)
|
||||
}
|
||||
|
||||
// As finds the first error in err's chain that matches the type to which target
|
||||
// points, and if so, sets the target to its value and returns true. An error
|
||||
// matches a type if it is assignable to the target type, or if it has a method
|
||||
// As(interface{}) bool such that As(target) returns true. As will panic if target
|
||||
// is not a non-nil pointer to a type which implements error or is of interface type.
|
||||
//
|
||||
// The As method should set the target to its value and return true if err
|
||||
// matches the type to which target points.
|
||||
//
|
||||
// Note: this implementation differs from that of xerrors as follows:
|
||||
// - it also supports recursing through causes with Cause().
|
||||
// - if it detects an API use error, its panic object is a valid error.
|
||||
func As(err error, target interface{}) bool { return errutil.As(err, target) }
|
||||
|
||||
// Join returns an error that wraps the given errors.
|
||||
// Any nil error values are discarded.
|
||||
// Join returns nil if errs contains no non-nil values.
|
||||
// The error formats as the concatenation of the strings obtained
|
||||
// by calling the Error method of each element of errs, with a newline
|
||||
// between each string. A stack trace is also retained.
|
||||
func Join(errs ...error) error {
|
||||
return errutil.JoinWithDepth(1, errs...)
|
||||
}
|
||||
|
||||
// JoinWithDepth is like Join but the depth at which the call stack is
|
||||
// captured can be specified.
|
||||
func JoinWithDepth(depth int, errs ...error) error {
|
||||
return errutil.JoinWithDepth(depth+1, errs...)
|
||||
}
|
||||
165
vendor/github.com/cockroachdb/errors/hintdetail/hintdetail.go
generated
vendored
Normal file
165
vendor/github.com/cockroachdb/errors/hintdetail/hintdetail.go
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 hintdetail
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
)
|
||||
|
||||
// WithHint decorates an error with a textual hint.
|
||||
// The hint may contain PII and thus will not reportable.
|
||||
// The suggested use case for hint is to relay information to end users.
|
||||
//
|
||||
// Hint is shown:
|
||||
// - when formatting with `%+v`.
|
||||
// - with `GetAllHints()` / `FlattenHints()` below.
|
||||
//
|
||||
// Note: the hint does not appear in the main error message returned
|
||||
// with Error(). Use GetAllHints() or FlattenHints() to retrieve it.
|
||||
func WithHint(err error, msg string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &withHint{cause: err, hint: msg}
|
||||
}
|
||||
|
||||
// WithHintf is a helper that formats the hint.
|
||||
func WithHintf(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &withHint{cause: err, hint: fmt.Sprintf(format, args...)}
|
||||
}
|
||||
|
||||
// GetAllHints retrieves the hints from the error using in post-order
|
||||
// traversal. The hints are de-duplicated. Assertion failures, issue
|
||||
// links and unimplemented errors are detected and receive standard
|
||||
// hints.
|
||||
func GetAllHints(err error) []string {
|
||||
return getAllHintsInternal(err, nil, make(map[string]struct{}))
|
||||
}
|
||||
|
||||
// FlattenHints retrieves the hints as per GetAllHints() and
|
||||
// concatenates them into a single string.
|
||||
func FlattenHints(err error) string {
|
||||
var b bytes.Buffer
|
||||
sep := ""
|
||||
for _, h := range GetAllHints(err) {
|
||||
b.WriteString(sep)
|
||||
b.WriteString(h)
|
||||
sep = "\n--\n"
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func getAllHintsInternal(err error, hints []string, seen map[string]struct{}) []string {
|
||||
if c := errbase.UnwrapOnce(err); c != nil {
|
||||
hints = getAllHintsInternal(c, hints, seen)
|
||||
}
|
||||
|
||||
hint := ""
|
||||
if w, ok := err.(ErrorHinter); ok {
|
||||
hint = w.ErrorHint()
|
||||
}
|
||||
|
||||
if hint != "" {
|
||||
// De-duplicate hints.
|
||||
if _, ok := seen[hint]; !ok {
|
||||
hints = append(hints, hint)
|
||||
seen[hint] = struct{}{}
|
||||
}
|
||||
}
|
||||
return hints
|
||||
}
|
||||
|
||||
// ErrorHinter is implemented by types that can provide
|
||||
// user-informing detail strings. This is implemented by withHint
|
||||
// here, withIssueLink, assertionFailure and pgerror.Error.
|
||||
type ErrorHinter interface {
|
||||
ErrorHint() string
|
||||
}
|
||||
|
||||
// WithDetail decorates an error with a textual detail.
|
||||
// The detail may contain PII and thus will not reportable.
|
||||
// The suggested use case for detail is to augment errors with information
|
||||
// useful for debugging.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - when formatting with `%+v`.
|
||||
// - with `GetAllDetails()` / `FlattenDetails()` below.
|
||||
//
|
||||
// Note: the detail does not appear in the main error message returned
|
||||
// with Error(). Use GetAllDetails() or FlattenDetails() to retrieve
|
||||
// it.
|
||||
func WithDetail(err error, msg string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &withDetail{cause: err, detail: msg}
|
||||
}
|
||||
|
||||
// WithDetailf is a helper that formats the detail string.
|
||||
func WithDetailf(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &withDetail{cause: err, detail: fmt.Sprintf(format, args...)}
|
||||
}
|
||||
|
||||
// GetAllDetails retrieves the details from the error using in post-order
|
||||
// traversal.
|
||||
func GetAllDetails(err error) []string {
|
||||
return getAllDetailsInternal(err, nil)
|
||||
}
|
||||
|
||||
// FlattenDetails retrieves the details as per GetAllDetails() and
|
||||
// concatenates them into a single string.
|
||||
func FlattenDetails(err error) string {
|
||||
var b bytes.Buffer
|
||||
sep := ""
|
||||
for _, h := range GetAllDetails(err) {
|
||||
b.WriteString(sep)
|
||||
b.WriteString(h)
|
||||
sep = "\n--\n"
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func getAllDetailsInternal(err error, details []string) []string {
|
||||
if c := errbase.UnwrapOnce(err); c != nil {
|
||||
details = getAllDetailsInternal(c, details)
|
||||
}
|
||||
if w, ok := err.(ErrorDetailer); ok {
|
||||
d := w.ErrorDetail()
|
||||
if d != "" {
|
||||
details = append(details, w.ErrorDetail())
|
||||
}
|
||||
}
|
||||
return details
|
||||
}
|
||||
|
||||
// ErrorDetailer is implemented by types that can provide
|
||||
// user-informing detail strings. This is implemented by withDetail
|
||||
// here and pgerror.Error.
|
||||
type ErrorDetailer interface {
|
||||
ErrorDetail() string
|
||||
}
|
||||
72
vendor/github.com/cockroachdb/errors/hintdetail/with_detail.go
generated
vendored
Normal file
72
vendor/github.com/cockroachdb/errors/hintdetail/with_detail.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 hintdetail
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/errors/errorspb"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type withDetail struct {
|
||||
cause error
|
||||
detail string
|
||||
}
|
||||
|
||||
var _ error = (*withDetail)(nil)
|
||||
var _ ErrorDetailer = (*withDetail)(nil)
|
||||
var _ fmt.Formatter = (*withDetail)(nil)
|
||||
var _ errbase.Formatter = (*withDetail)(nil)
|
||||
|
||||
func (w *withDetail) ErrorDetail() string { return w.detail }
|
||||
func (w *withDetail) Error() string { return w.cause.Error() }
|
||||
func (w *withDetail) Cause() error { return w.cause }
|
||||
func (w *withDetail) Unwrap() error { return w.cause }
|
||||
|
||||
func (w *withDetail) Format(s fmt.State, verb rune) { errbase.FormatError(w, s, verb) }
|
||||
|
||||
func (w *withDetail) FormatError(p errbase.Printer) error {
|
||||
if p.Detail() {
|
||||
p.Print(w.detail)
|
||||
}
|
||||
return w.cause
|
||||
}
|
||||
|
||||
func encodeWithDetail(_ context.Context, err error) (string, []string, proto.Message) {
|
||||
w := err.(*withDetail)
|
||||
return "", nil, &errorspb.StringPayload{Msg: w.detail}
|
||||
}
|
||||
|
||||
func decodeWithDetail(
|
||||
_ context.Context, cause error, _ string, _ []string, payload proto.Message,
|
||||
) error {
|
||||
m, ok := payload.(*errorspb.StringPayload)
|
||||
if !ok {
|
||||
// If this ever happens, this means some version of the library
|
||||
// (presumably future) changed the payload type, and we're
|
||||
// receiving this here. In this case, give up and let
|
||||
// DecodeError use the opaque type.
|
||||
return nil
|
||||
}
|
||||
return &withDetail{cause: cause, detail: m.Msg}
|
||||
}
|
||||
|
||||
func init() {
|
||||
errbase.RegisterWrapperEncoder(errbase.GetTypeKey((*withDetail)(nil)), encodeWithDetail)
|
||||
errbase.RegisterWrapperDecoder(errbase.GetTypeKey((*withDetail)(nil)), decodeWithDetail)
|
||||
}
|
||||
72
vendor/github.com/cockroachdb/errors/hintdetail/with_hint.go
generated
vendored
Normal file
72
vendor/github.com/cockroachdb/errors/hintdetail/with_hint.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 hintdetail
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/errors/errorspb"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type withHint struct {
|
||||
cause error
|
||||
hint string
|
||||
}
|
||||
|
||||
var _ error = (*withHint)(nil)
|
||||
var _ ErrorHinter = (*withHint)(nil)
|
||||
var _ fmt.Formatter = (*withHint)(nil)
|
||||
var _ errbase.Formatter = (*withHint)(nil)
|
||||
|
||||
func (w *withHint) ErrorHint() string { return w.hint }
|
||||
func (w *withHint) Error() string { return w.cause.Error() }
|
||||
func (w *withHint) Cause() error { return w.cause }
|
||||
func (w *withHint) Unwrap() error { return w.cause }
|
||||
|
||||
func (w *withHint) Format(s fmt.State, verb rune) { errbase.FormatError(w, s, verb) }
|
||||
|
||||
func (w *withHint) FormatError(p errbase.Printer) error {
|
||||
if p.Detail() {
|
||||
p.Print(w.hint)
|
||||
}
|
||||
return w.cause
|
||||
}
|
||||
|
||||
func encodeWithHint(_ context.Context, err error) (string, []string, proto.Message) {
|
||||
w := err.(*withHint)
|
||||
return "", nil, &errorspb.StringPayload{Msg: w.hint}
|
||||
}
|
||||
|
||||
func decodeWithHint(
|
||||
_ context.Context, cause error, _ string, _ []string, payload proto.Message,
|
||||
) error {
|
||||
m, ok := payload.(*errorspb.StringPayload)
|
||||
if !ok {
|
||||
// If this ever happens, this means some version of the library
|
||||
// (presumably future) changed the payload type, and we're
|
||||
// receiving this here. In this case, give up and let
|
||||
// DecodeError use the opaque type.
|
||||
return nil
|
||||
}
|
||||
return &withHint{cause: cause, hint: m.Msg}
|
||||
}
|
||||
|
||||
func init() {
|
||||
errbase.RegisterWrapperEncoder(errbase.GetTypeKey((*withHint)(nil)), encodeWithHint)
|
||||
errbase.RegisterWrapperDecoder(errbase.GetTypeKey((*withHint)(nil)), decodeWithHint)
|
||||
}
|
||||
82
vendor/github.com/cockroachdb/errors/hintdetail_api.go
generated
vendored
Normal file
82
vendor/github.com/cockroachdb/errors/hintdetail_api.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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
|
||||
|
||||
import "github.com/cockroachdb/errors/hintdetail"
|
||||
|
||||
// ErrorHinter is implemented by types that can provide
|
||||
// user-informing detail strings. This is implemented by withHint
|
||||
// here, withIssueLink, assertionFailure and pgerror.Error.
|
||||
type ErrorHinter = hintdetail.ErrorHinter
|
||||
|
||||
// ErrorDetailer is implemented by types that can provide
|
||||
// user-informing detail strings.
|
||||
type ErrorDetailer = hintdetail.ErrorDetailer
|
||||
|
||||
// WithHint decorates an error with a textual hint.
|
||||
// The hint may contain PII and thus will not reportable.
|
||||
// The suggested use case for hint is to relay information to end users.
|
||||
//
|
||||
// Hint is shown:
|
||||
// - when formatting with `%+v`.
|
||||
// - with `GetAllHints()` / `FlattenHints()` below.
|
||||
//
|
||||
// Note: the hint does not appear in the main error message returned
|
||||
// with Error(). Use GetAllHints() or FlattenHints() to retrieve it.
|
||||
func WithHint(err error, msg string) error { return hintdetail.WithHint(err, msg) }
|
||||
|
||||
// WithHintf is a helper that formats the hint.
|
||||
// See the documentation of WithHint() for details.
|
||||
func WithHintf(err error, format string, args ...interface{}) error {
|
||||
return hintdetail.WithHintf(err, format, args...)
|
||||
}
|
||||
|
||||
// WithDetail decorates an error with a textual detail.
|
||||
// The detail may contain PII and thus will not reportable.
|
||||
// The suggested use case for detail is to augment errors with information
|
||||
// useful for debugging.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - when formatting with `%+v`.
|
||||
// - with `GetAllDetails()` / `FlattenDetails()` below.
|
||||
//
|
||||
// Note: the detail does not appear in the main error message returned
|
||||
// with Error(). Use GetAllDetails() or FlattenDetails() to retrieve
|
||||
// it.
|
||||
func WithDetail(err error, msg string) error { return hintdetail.WithDetail(err, msg) }
|
||||
|
||||
// WithDetailf is a helper that formats the detail string.
|
||||
// See the documentation of WithDetail() for details.
|
||||
func WithDetailf(err error, format string, args ...interface{}) error {
|
||||
return hintdetail.WithDetailf(err, format, args...)
|
||||
}
|
||||
|
||||
// GetAllHints retrieves the hints from the error using in post-order
|
||||
// traversal. The hints are de-duplicated. Assertion failures, issue
|
||||
// links and unimplemented errors are detected and receive standard
|
||||
// hints.
|
||||
func GetAllHints(err error) []string { return hintdetail.GetAllHints(err) }
|
||||
|
||||
// FlattenHints retrieves the hints as per GetAllHints() and
|
||||
// concatenates them into a single string.
|
||||
func FlattenHints(err error) string { return hintdetail.FlattenHints(err) }
|
||||
|
||||
// GetAllDetails retrieves the details from the error using in post-order
|
||||
// traversal.
|
||||
func GetAllDetails(err error) []string { return hintdetail.GetAllDetails(err) }
|
||||
|
||||
// FlattenDetails retrieves the details as per GetAllDetails() and
|
||||
// concatenates them into a single string.
|
||||
func FlattenDetails(err error) string { return hintdetail.FlattenDetails(err) }
|
||||
119
vendor/github.com/cockroachdb/errors/issuelink/issuelink.go
generated
vendored
Normal file
119
vendor/github.com/cockroachdb/errors/issuelink/issuelink.go
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 issuelink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/errors/markers"
|
||||
)
|
||||
|
||||
// WithIssueLink adds an annotation to a know issue
|
||||
// on a web issue tracker.
|
||||
//
|
||||
// The url and detail strings may contain PII and will
|
||||
// be considered reportable.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
// - via `errors.GetAllHints()` / `errors.FlattenHints()`
|
||||
func WithIssueLink(err error, issue IssueLink) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withIssueLink{cause: err, IssueLink: issue}
|
||||
}
|
||||
|
||||
// HasIssueLink returns true iff the error or one of its
|
||||
// causes has a linked issue payload.
|
||||
func HasIssueLink(err error) bool {
|
||||
_, ok := markers.If(err, func(err error) (v interface{}, ok bool) {
|
||||
v, ok = err.(*withIssueLink)
|
||||
return
|
||||
})
|
||||
return ok
|
||||
}
|
||||
|
||||
// IsIssueLink returns true iff the error (not its
|
||||
// causes) has a linked issue payload.
|
||||
func IsIssueLink(err error) bool {
|
||||
_, ok := err.(*withIssueLink)
|
||||
return ok
|
||||
}
|
||||
|
||||
// GetAllIssueLinks retrieves the linked issue carried
|
||||
// by the error or its direct causes.
|
||||
func GetAllIssueLinks(err error) (issues []IssueLink) {
|
||||
for ; err != nil; err = errbase.UnwrapOnce(err) {
|
||||
if issue, ok := GetIssueLink(err); ok {
|
||||
issues = append(issues, issue)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// UnimplementedError creates a new leaf error that indicates that
|
||||
// some feature was not (yet) implemented.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
// - via `errors.GetAllHints()` / `errors.FlattenHints()`
|
||||
func UnimplementedError(issueLink IssueLink, msg string) error {
|
||||
return &unimplementedError{IssueLink: issueLink, msg: msg}
|
||||
}
|
||||
|
||||
// UnimplementedErrorf creates a new leaf error that indicates that
|
||||
// some feature was not (yet) implemented. The message is formatted.
|
||||
func UnimplementedErrorf(issueLink IssueLink, format string, args ...interface{}) error {
|
||||
return &unimplementedError{IssueLink: issueLink, msg: fmt.Sprintf(format, args...)}
|
||||
}
|
||||
|
||||
// IsUnimplementedError returns iff if err is an unimplemented error.
|
||||
func IsUnimplementedError(err error) bool {
|
||||
_, ok := err.(*unimplementedError)
|
||||
return ok
|
||||
}
|
||||
|
||||
// HasUnimplementedError returns iff if err or its cause is an
|
||||
// unimplemented error.
|
||||
func HasUnimplementedError(err error) bool {
|
||||
_, ok := errbase.UnwrapAll(err).(*unimplementedError)
|
||||
return ok
|
||||
}
|
||||
|
||||
// GetIssueLink retrieves the linked issue annotation carried
|
||||
// by the error, or false if there is no such annotation.
|
||||
func GetIssueLink(err error) (IssueLink, bool) {
|
||||
switch w := err.(type) {
|
||||
case *withIssueLink:
|
||||
return w.IssueLink, true
|
||||
case *unimplementedError:
|
||||
return w.IssueLink, true
|
||||
}
|
||||
return IssueLink{}, false
|
||||
}
|
||||
|
||||
// IssueLink is the payload for a linked issue annotation.
|
||||
type IssueLink struct {
|
||||
// URL to the issue on a tracker.
|
||||
IssueURL string
|
||||
// Annotation that characterizes a sub-issue.
|
||||
Detail string
|
||||
}
|
||||
87
vendor/github.com/cockroachdb/errors/issuelink/unimplemented_error.go
generated
vendored
Normal file
87
vendor/github.com/cockroachdb/errors/issuelink/unimplemented_error.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 issuelink
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/redact"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type unimplementedError struct {
|
||||
// For now, msg is non-reportable.
|
||||
msg string
|
||||
IssueLink
|
||||
}
|
||||
|
||||
var _ error = (*unimplementedError)(nil)
|
||||
var _ fmt.Formatter = (*unimplementedError)(nil)
|
||||
var _ errbase.SafeFormatter = (*unimplementedError)(nil)
|
||||
var _ errbase.SafeDetailer = (*unimplementedError)(nil)
|
||||
|
||||
func (w *unimplementedError) Error() string { return w.msg }
|
||||
func (w *unimplementedError) SafeDetails() []string {
|
||||
return []string{w.IssueURL, w.Detail}
|
||||
}
|
||||
|
||||
// ErrorHint implements the hintdetail.ErrorHinter interface.
|
||||
func (w *unimplementedError) ErrorHint() string {
|
||||
var hintText bytes.Buffer
|
||||
hintText.WriteString(UnimplementedErrorHint)
|
||||
maybeAppendReferral(&hintText, w.IssueLink)
|
||||
return hintText.String()
|
||||
}
|
||||
|
||||
// UnimplementedErrorHint is the hint emitted upon unimplemented errors.
|
||||
const UnimplementedErrorHint = `You have attempted to use a feature that is not yet implemented.`
|
||||
|
||||
func (w *unimplementedError) Format(s fmt.State, verb rune) { errbase.FormatError(w, s, verb) }
|
||||
|
||||
func (w *unimplementedError) SafeFormatError(p errbase.Printer) error {
|
||||
// For now, msg is non-reportable.
|
||||
p.Print(w.msg)
|
||||
if p.Detail() {
|
||||
// But the details are.
|
||||
p.Printf("unimplemented")
|
||||
if w.IssueURL != "" {
|
||||
p.Printf("\nissue: %s", redact.Safe(w.IssueURL))
|
||||
}
|
||||
if w.Detail != "" {
|
||||
p.Printf("\ndetail: %s", redact.Safe(w.Detail))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeUnimplementedError(
|
||||
_ context.Context, msg string, details []string, _ proto.Message,
|
||||
) error {
|
||||
var issueLink IssueLink
|
||||
if len(details) > 0 {
|
||||
issueLink.IssueURL = details[0]
|
||||
}
|
||||
if len(details) > 1 {
|
||||
issueLink.Detail = details[1]
|
||||
}
|
||||
return &unimplementedError{msg: msg, IssueLink: issueLink}
|
||||
}
|
||||
|
||||
func init() {
|
||||
errbase.RegisterLeafDecoder(errbase.GetTypeKey((*unimplementedError)(nil)), decodeUnimplementedError)
|
||||
}
|
||||
97
vendor/github.com/cockroachdb/errors/issuelink/with_issuelink.go
generated
vendored
Normal file
97
vendor/github.com/cockroachdb/errors/issuelink/with_issuelink.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 issuelink
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/errors/stdstrings"
|
||||
"github.com/cockroachdb/redact"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type withIssueLink struct {
|
||||
cause error
|
||||
IssueLink
|
||||
}
|
||||
|
||||
var _ error = (*withIssueLink)(nil)
|
||||
var _ errbase.SafeDetailer = (*withIssueLink)(nil)
|
||||
var _ fmt.Formatter = (*withIssueLink)(nil)
|
||||
var _ errbase.SafeFormatter = (*withIssueLink)(nil)
|
||||
|
||||
func (w *withIssueLink) Error() string { return w.cause.Error() }
|
||||
func (w *withIssueLink) Cause() error { return w.cause }
|
||||
func (w *withIssueLink) Unwrap() error { return w.cause }
|
||||
|
||||
func (w *withIssueLink) SafeDetails() []string {
|
||||
return []string{w.IssueURL, w.Detail}
|
||||
}
|
||||
|
||||
// ErrorHint implements the hintdetail.ErrorHinter interface.
|
||||
func (w *withIssueLink) ErrorHint() string {
|
||||
var hintText bytes.Buffer
|
||||
maybeAppendReferral(&hintText, w.IssueLink)
|
||||
return hintText.String()
|
||||
}
|
||||
|
||||
func maybeAppendReferral(buf *bytes.Buffer, link IssueLink) {
|
||||
if link.IssueURL != "" {
|
||||
// If there is a URL, refer to that.
|
||||
if buf.Len() > 0 {
|
||||
buf.WriteByte('\n')
|
||||
}
|
||||
fmt.Fprintf(buf, "See: %s", link.IssueURL)
|
||||
} else {
|
||||
// No URL: tell the user to send details.
|
||||
buf.WriteString(stdstrings.IssueReferral)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *withIssueLink) Format(s fmt.State, verb rune) { errbase.FormatError(w, s, verb) }
|
||||
|
||||
func (w *withIssueLink) SafeFormatError(p errbase.Printer) error {
|
||||
if p.Detail() {
|
||||
sep := redact.SafeString("")
|
||||
if w.IssueURL != "" {
|
||||
p.Printf("issue: %s", redact.Safe(w.IssueURL))
|
||||
sep = "\n"
|
||||
}
|
||||
if w.Detail != "" {
|
||||
p.Printf("%sdetail: %s", sep, redact.Safe(w.Detail))
|
||||
}
|
||||
}
|
||||
return w.cause
|
||||
}
|
||||
|
||||
func decodeWithIssueLink(
|
||||
_ context.Context, cause error, _ string, details []string, _ proto.Message,
|
||||
) error {
|
||||
var issueLink IssueLink
|
||||
if len(details) > 0 {
|
||||
issueLink.IssueURL = details[0]
|
||||
}
|
||||
if len(details) > 1 {
|
||||
issueLink.Detail = details[1]
|
||||
}
|
||||
return &withIssueLink{cause: cause, IssueLink: issueLink}
|
||||
}
|
||||
|
||||
func init() {
|
||||
errbase.RegisterWrapperDecoder(errbase.GetTypeKey((*withIssueLink)(nil)), decodeWithIssueLink)
|
||||
}
|
||||
73
vendor/github.com/cockroachdb/errors/issuelink_api.go
generated
vendored
Normal file
73
vendor/github.com/cockroachdb/errors/issuelink_api.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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
|
||||
|
||||
import "github.com/cockroachdb/errors/issuelink"
|
||||
|
||||
// WithIssueLink adds an annotation to a know issue
|
||||
// on a web issue tracker.
|
||||
//
|
||||
// The url and detail strings may contain PII and will
|
||||
// be considered reportable.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
// - via `errors.GetAllHints()` / `errors.FlattenHints()`
|
||||
func WithIssueLink(err error, issue IssueLink) error { return issuelink.WithIssueLink(err, issue) }
|
||||
|
||||
// IssueLink is the payload for a linked issue annotation.
|
||||
type IssueLink = issuelink.IssueLink
|
||||
|
||||
// UnimplementedError creates a new leaf error that indicates that
|
||||
// some feature was not (yet) implemented.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
// - via `errors.GetAllHints()` / `errors.FlattenHints()`
|
||||
func UnimplementedError(issueLink IssueLink, msg string) error {
|
||||
return issuelink.UnimplementedError(issueLink, msg)
|
||||
}
|
||||
|
||||
// UnimplementedErrorf creates a new leaf error that indicates that
|
||||
// some feature was not (yet) implemented. The message is formatted.
|
||||
func UnimplementedErrorf(issueLink IssueLink, format string, args ...interface{}) error {
|
||||
return issuelink.UnimplementedErrorf(issueLink, format, args...)
|
||||
}
|
||||
|
||||
// GetAllIssueLinks retrieves the linked issue carried
|
||||
// by the error or its direct causes.
|
||||
func GetAllIssueLinks(err error) (issues []IssueLink) { return issuelink.GetAllIssueLinks(err) }
|
||||
|
||||
// HasIssueLink returns true iff the error or one of its
|
||||
// causes has a linked issue payload.
|
||||
func HasIssueLink(err error) bool { return issuelink.HasIssueLink(err) }
|
||||
|
||||
// IsIssueLink returns true iff the error (not its
|
||||
// causes) has a linked issue payload.
|
||||
func IsIssueLink(err error) bool { return issuelink.IsIssueLink(err) }
|
||||
|
||||
// HasUnimplementedError returns iff if err or its cause is an
|
||||
// unimplemented error.
|
||||
func HasUnimplementedError(err error) bool { return issuelink.HasUnimplementedError(err) }
|
||||
|
||||
// IsUnimplementedError returns iff if err is an unimplemented error.
|
||||
func IsUnimplementedError(err error) bool { return issuelink.IsUnimplementedError(err) }
|
||||
|
||||
// UnimplementedErrorHint is the hint emitted upon unimplemented errors.
|
||||
const UnimplementedErrorHint = issuelink.UnimplementedErrorHint
|
||||
105
vendor/github.com/cockroachdb/errors/join/join.go
generated
vendored
Normal file
105
vendor/github.com/cockroachdb/errors/join/join.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 join
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/redact"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// Join returns an error that wraps the given errors.
|
||||
// Any nil error values are discarded.
|
||||
// Join returns nil if errs contains no non-nil values.
|
||||
// The error formats as the concatenation of the strings obtained
|
||||
// by calling the Error method of each element of errs, with a newline
|
||||
// between each string.
|
||||
func Join(errs ...error) error {
|
||||
n := 0
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
n++
|
||||
}
|
||||
}
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
e := &joinError{
|
||||
errs: make([]error, 0, n),
|
||||
}
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
e.errs = append(e.errs, err)
|
||||
}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
type joinError struct {
|
||||
errs []error
|
||||
}
|
||||
|
||||
var _ error = (*joinError)(nil)
|
||||
var _ fmt.Formatter = (*joinError)(nil)
|
||||
var _ errbase.SafeFormatter = (*joinError)(nil)
|
||||
|
||||
func (e *joinError) Error() string {
|
||||
return redact.Sprint(e).StripMarkers()
|
||||
}
|
||||
|
||||
func (e *joinError) Unwrap() []error {
|
||||
return e.errs
|
||||
}
|
||||
|
||||
func (e *joinError) SafeFormatError(p errbase.Printer) error {
|
||||
for i, err := range e.errs {
|
||||
if i > 0 {
|
||||
p.Print("\n")
|
||||
}
|
||||
p.Print(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *joinError) Format(s fmt.State, verb rune) {
|
||||
errbase.FormatError(e, s, verb)
|
||||
}
|
||||
|
||||
func init() {
|
||||
errbase.RegisterMultiCauseEncoder(
|
||||
errbase.GetTypeKey(&joinError{}),
|
||||
func(
|
||||
ctx context.Context,
|
||||
err error,
|
||||
) (msg string, safeDetails []string, payload proto.Message) {
|
||||
return "", nil, nil
|
||||
},
|
||||
)
|
||||
errbase.RegisterMultiCauseDecoder(
|
||||
errbase.GetTypeKey(&joinError{}),
|
||||
func(
|
||||
ctx context.Context,
|
||||
causes []error,
|
||||
msgPrefix string,
|
||||
safeDetails []string,
|
||||
payload proto.Message,
|
||||
) error {
|
||||
return Join(causes...)
|
||||
},
|
||||
)
|
||||
}
|
||||
318
vendor/github.com/cockroachdb/errors/markers/markers.go
generated
vendored
Normal file
318
vendor/github.com/cockroachdb/errors/markers/markers.go
generated
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 markers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/errors/errorspb"
|
||||
"github.com/cockroachdb/redact"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// Is determines whether one of the causes of the given error or any
|
||||
// of its causes is equivalent to some reference error.
|
||||
//
|
||||
// As in the Go standard library, an error is considered to match a
|
||||
// reference error if it is equal to that target or if it implements a
|
||||
// method Is(error) bool such that Is(reference) returns true.
|
||||
//
|
||||
// Note: the inverse is not true - making an Is(reference) method
|
||||
// return false does not imply that errors.Is() also returns
|
||||
// false. Errors can be equal because their network equality marker is
|
||||
// the same. To force errors to appear different to Is(), use
|
||||
// errors.Mark().
|
||||
//
|
||||
// Note: if any of the error types has been migrated from a previous
|
||||
// package location or a different type, ensure that
|
||||
// RegisterTypeMigration() was called prior to Is().
|
||||
func Is(err, reference error) bool {
|
||||
if reference == nil {
|
||||
return err == nil
|
||||
}
|
||||
|
||||
isComparable := reflect.TypeOf(reference).Comparable()
|
||||
|
||||
// Direct reference comparison is the fastest, and most
|
||||
// likely to be true, so do this first.
|
||||
for c := err; c != nil; c = errbase.UnwrapOnce(c) {
|
||||
if isComparable && c == reference {
|
||||
return true
|
||||
}
|
||||
// Compatibility with std go errors: if the error object itself
|
||||
// implements Is(), try to use that.
|
||||
if tryDelegateToIsMethod(c, reference) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Recursively try multi-error causes, if applicable.
|
||||
for _, me := range errbase.UnwrapMulti(c) {
|
||||
if Is(me, reference) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
// Err is nil and reference is non-nil, so it cannot match. We
|
||||
// want to short-circuit the loop below in this case, otherwise
|
||||
// we're paying the expense of getMark() without need.
|
||||
return false
|
||||
}
|
||||
|
||||
// Not directly equal. Try harder, using error marks. We don't do
|
||||
// this during the loop above as it may be more expensive.
|
||||
//
|
||||
// Note: there is a more effective recursive algorithm that ensures
|
||||
// that any pair of string only gets compared once. Should the
|
||||
// following code become a performance bottleneck, that algorithm
|
||||
// can be considered instead.
|
||||
refMark := getMark(reference)
|
||||
for c := err; c != nil; c = errbase.UnwrapOnce(c) {
|
||||
if equalMarks(getMark(c), refMark) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func tryDelegateToIsMethod(err, reference error) bool {
|
||||
if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(reference) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// HasType returns true iff err contains an error whose concrete type
|
||||
// matches that of referenceType.
|
||||
func HasType(err error, referenceType error) bool {
|
||||
typ := reflect.TypeOf(referenceType)
|
||||
_, isType := If(err, func(err error) (interface{}, bool) {
|
||||
return nil, reflect.TypeOf(err) == typ
|
||||
})
|
||||
return isType
|
||||
}
|
||||
|
||||
// HasInterface returns true if err contains an error which implements the
|
||||
// interface pointed to by referenceInterface. The type of referenceInterface
|
||||
// must be a pointer to an interface type. If referenceInterface is not a
|
||||
// pointer to an interface, this function will panic.
|
||||
func HasInterface(err error, referenceInterface interface{}) bool {
|
||||
iface := getInterfaceType("HasInterface", referenceInterface)
|
||||
_, isType := If(err, func(err error) (interface{}, bool) {
|
||||
return nil, reflect.TypeOf(err).Implements(iface)
|
||||
})
|
||||
return isType
|
||||
}
|
||||
|
||||
func getInterfaceType(context string, referenceInterface interface{}) reflect.Type {
|
||||
typ := reflect.TypeOf(referenceInterface)
|
||||
if typ == nil || typ.Kind() != reflect.Ptr || typ.Elem().Kind() != reflect.Interface {
|
||||
panic(fmt.Errorf("errors.%s: referenceInterface must be a pointer to an interface, "+
|
||||
"found %T", context, referenceInterface))
|
||||
}
|
||||
return typ.Elem()
|
||||
}
|
||||
|
||||
// If iterates on the error's causal chain and returns a predicate's
|
||||
// return value the first time the predicate returns true.
|
||||
//
|
||||
// Note: if any of the error types has been migrated from a previous
|
||||
// package location or a different type, ensure that
|
||||
// RegisterTypeMigration() was called prior to If().
|
||||
func If(err error, pred func(err error) (interface{}, bool)) (interface{}, bool) {
|
||||
for c := err; c != nil; c = errbase.UnwrapOnce(c) {
|
||||
if v, ok := pred(c); ok {
|
||||
return v, ok
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// IsAny is like Is except that multiple references are compared.
|
||||
//
|
||||
// Note: if any of the error types has been migrated from a previous
|
||||
// package location or a different type, ensure that
|
||||
// RegisterTypeMigration() was called prior to IsAny().
|
||||
func IsAny(err error, references ...error) bool {
|
||||
if err == nil {
|
||||
for _, refErr := range references {
|
||||
if refErr == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// The mark-based comparison below will never match anything if
|
||||
// the error is nil, so don't bother with computing the marks in
|
||||
// that case. This avoids the computational expense of computing
|
||||
// the reference marks upfront.
|
||||
return false
|
||||
}
|
||||
|
||||
// First try using direct reference comparison.
|
||||
for c := err; c != nil; c = errbase.UnwrapOnce(c) {
|
||||
for _, refErr := range references {
|
||||
if refErr == nil {
|
||||
continue
|
||||
}
|
||||
isComparable := reflect.TypeOf(refErr).Comparable()
|
||||
if isComparable && c == refErr {
|
||||
return true
|
||||
}
|
||||
// Compatibility with std go errors: if the error object itself
|
||||
// implements Is(), try to use that.
|
||||
if tryDelegateToIsMethod(c, refErr) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively try multi-error causes, if applicable.
|
||||
for _, me := range errbase.UnwrapMulti(c) {
|
||||
if IsAny(me, references...) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try harder with marks.
|
||||
// Note: there is a more effective recursive algorithm that ensures
|
||||
// that any pair of string only gets compared once. Should this
|
||||
// become a performance bottleneck, that algorithm can be considered
|
||||
// instead.
|
||||
refMarks := make([]errorMark, 0, len(references))
|
||||
for _, refErr := range references {
|
||||
if refErr == nil {
|
||||
continue
|
||||
}
|
||||
refMarks = append(refMarks, getMark(refErr))
|
||||
}
|
||||
for c := err; c != nil; c = errbase.UnwrapOnce(c) {
|
||||
errMark := getMark(c)
|
||||
for _, refMark := range refMarks {
|
||||
if equalMarks(errMark, refMark) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type errorMark struct {
|
||||
msg string
|
||||
types []errorspb.ErrorTypeMark
|
||||
}
|
||||
|
||||
// equalMarks compares two error markers.
|
||||
func equalMarks(m1, m2 errorMark) bool {
|
||||
if m1.msg != m2.msg {
|
||||
return false
|
||||
}
|
||||
for i, t := range m1.types {
|
||||
if !t.Equals(m2.types[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// getMark computes a marker for the given error.
|
||||
func getMark(err error) errorMark {
|
||||
if m, ok := err.(*withMark); ok {
|
||||
return m.mark
|
||||
}
|
||||
m := errorMark{msg: safeGetErrMsg(err), types: []errorspb.ErrorTypeMark{errbase.GetTypeMark(err)}}
|
||||
for c := errbase.UnwrapOnce(err); c != nil; c = errbase.UnwrapOnce(c) {
|
||||
m.types = append(m.types, errbase.GetTypeMark(c))
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// safeGetErrMsg extracts an error's Error() but tolerates panics.
|
||||
func safeGetErrMsg(err error) (result string) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
result = fmt.Sprintf("(%p).Error() panic: %v", err, r)
|
||||
}
|
||||
}()
|
||||
result = err.Error()
|
||||
return
|
||||
}
|
||||
|
||||
// Mark creates an explicit mark for the given error, using
|
||||
// the same mark as some reference error.
|
||||
//
|
||||
// Note: if any of the error types has been migrated from a previous
|
||||
// package location or a different type, ensure that
|
||||
// RegisterTypeMigration() was called prior to Mark().
|
||||
func Mark(err error, reference error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
refMark := getMark(reference)
|
||||
return &withMark{cause: err, mark: refMark}
|
||||
}
|
||||
|
||||
// withMark carries an explicit mark.
|
||||
type withMark struct {
|
||||
cause error
|
||||
mark errorMark
|
||||
}
|
||||
|
||||
var _ error = (*withMark)(nil)
|
||||
var _ fmt.Formatter = (*withMark)(nil)
|
||||
var _ errbase.SafeFormatter = (*withMark)(nil)
|
||||
|
||||
func (m *withMark) Error() string { return m.cause.Error() }
|
||||
func (m *withMark) Cause() error { return m.cause }
|
||||
func (m *withMark) Unwrap() error { return m.cause }
|
||||
|
||||
func (m *withMark) Format(s fmt.State, verb rune) { errbase.FormatError(m, s, verb) }
|
||||
|
||||
func (m *withMark) SafeFormatError(p errbase.Printer) error {
|
||||
if p.Detail() {
|
||||
p.Printf("forced error mark\n")
|
||||
p.Printf("%q\n%s::%s",
|
||||
m.mark.msg,
|
||||
redact.Safe(m.mark.types[0].FamilyName),
|
||||
redact.Safe(m.mark.types[0].Extension),
|
||||
)
|
||||
}
|
||||
return m.cause
|
||||
}
|
||||
|
||||
func encodeMark(_ context.Context, err error) (msg string, _ []string, payload proto.Message) {
|
||||
m := err.(*withMark)
|
||||
payload = &errorspb.MarkPayload{Msg: m.mark.msg, Types: m.mark.types}
|
||||
return "", nil, payload
|
||||
}
|
||||
|
||||
func decodeMark(_ context.Context, cause error, _ string, _ []string, payload proto.Message) error {
|
||||
m, ok := payload.(*errorspb.MarkPayload)
|
||||
if !ok {
|
||||
// If this ever happens, this means some version of the library
|
||||
// (presumably future) changed the payload type, and we're
|
||||
// receiving this here. In this case, give up and let
|
||||
// DecodeError use the opaque type.
|
||||
return nil
|
||||
}
|
||||
return &withMark{cause: cause, mark: errorMark{msg: m.Msg, types: m.Types}}
|
||||
}
|
||||
|
||||
func init() {
|
||||
errbase.RegisterWrapperEncoder(errbase.GetTypeKey((*withMark)(nil)), encodeMark)
|
||||
errbase.RegisterWrapperDecoder(errbase.GetTypeKey((*withMark)(nil)), decodeMark)
|
||||
}
|
||||
72
vendor/github.com/cockroachdb/errors/markers_api.go
generated
vendored
Normal file
72
vendor/github.com/cockroachdb/errors/markers_api.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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
|
||||
|
||||
import "github.com/cockroachdb/errors/markers"
|
||||
|
||||
// Is determines whether one of the causes of the given error or any
|
||||
// of its causes is equivalent to some reference error.
|
||||
//
|
||||
// As in the Go standard library, an error is considered to match a
|
||||
// reference error if it is equal to that target or if it implements a
|
||||
// method Is(error) bool such that Is(reference) returns true.
|
||||
//
|
||||
// Note: the inverse is not true - making an Is(reference) method
|
||||
// return false does not imply that errors.Is() also returns
|
||||
// false. Errors can be equal because their network equality marker is
|
||||
// the same. To force errors to appear different to Is(), use
|
||||
// errors.Mark().
|
||||
//
|
||||
// Note: if any of the error types has been migrated from a previous
|
||||
// package location or a different type, ensure that
|
||||
// RegisterTypeMigration() was called prior to Is().
|
||||
func Is(err, reference error) bool { return markers.Is(err, reference) }
|
||||
|
||||
// HasType returns true iff err contains an error whose concrete type
|
||||
// matches that of referenceType.
|
||||
func HasType(err, referenceType error) bool { return markers.HasType(err, referenceType) }
|
||||
|
||||
// HasInterface returns true if err contains an error which implements the
|
||||
// interface pointed to by referenceInterface. The type of referenceInterface
|
||||
// must be a pointer to an interface type. If referenceInterface is not a
|
||||
// pointer to an interface, this function will panic.
|
||||
func HasInterface(err error, referenceInterface interface{}) bool {
|
||||
return markers.HasInterface(err, referenceInterface)
|
||||
}
|
||||
|
||||
// If iterates on the error's causal chain and returns a predicate's
|
||||
// return value the first time the predicate returns true.
|
||||
//
|
||||
// Note: if any of the error types has been migrated from a previous
|
||||
// package location or a different type, ensure that
|
||||
// RegisterTypeMigration() was called prior to If().
|
||||
func If(err error, pred func(err error) (interface{}, bool)) (interface{}, bool) {
|
||||
return markers.If(err, pred)
|
||||
}
|
||||
|
||||
// IsAny is like Is except that multiple references are compared.
|
||||
//
|
||||
// Note: if any of the error types has been migrated from a previous
|
||||
// package location or a different type, ensure that
|
||||
// RegisterTypeMigration() was called prior to IsAny().
|
||||
func IsAny(err error, references ...error) bool { return markers.IsAny(err, references...) }
|
||||
|
||||
// Mark creates an explicit mark for the given error, using
|
||||
// the same mark as some reference error.
|
||||
//
|
||||
// Note: if any of the error types has been migrated from a previous
|
||||
// package location or a different type, ensure that
|
||||
// RegisterTypeMigration() was called prior to Mark().
|
||||
func Mark(err error, reference error) error { return markers.Mark(err, reference) }
|
||||
120
vendor/github.com/cockroachdb/errors/oserror/oserror.go
generated
vendored
Normal file
120
vendor/github.com/cockroachdb/errors/oserror/oserror.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
// Copyright 2020 The Cockroach Authors.
|
||||
//
|
||||
// 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 oserror
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
)
|
||||
|
||||
// Portable analogs of some common system call errors.
|
||||
//
|
||||
// Errors returned from this package may be tested against these errors
|
||||
// with errors.Is.
|
||||
var (
|
||||
ErrInvalid = os.ErrInvalid
|
||||
ErrPermission = os.ErrPermission
|
||||
ErrExist = os.ErrExist
|
||||
ErrNotExist = os.ErrNotExist
|
||||
ErrClosed = os.ErrClosed
|
||||
)
|
||||
|
||||
// IsPermission returns a boolean indicating whether the error is
|
||||
// known to report that permission is denied. It is satisfied by
|
||||
// ErrPermission as well as some syscall errors.
|
||||
//
|
||||
// This function differs from os.IsPermission() in that it
|
||||
// can identify an error through wrapping layers.
|
||||
func IsPermission(err error) bool {
|
||||
// errors.Is() is not able to peek through os.SyscallError,
|
||||
// whereas os.IsPermission() can. Conversely, os.IsPermission()
|
||||
// cannot peek through Unwrap, whereas errors.Is() can. So we
|
||||
// need to try both.
|
||||
if errors.Is(err, ErrPermission) || os.IsPermission(errors.UnwrapAll(err)) {
|
||||
return true
|
||||
}
|
||||
// If a syscall errno representing ErrPermission was encoded on a
|
||||
// different platform, and decoded here, then it will show up as
|
||||
// neither a syscall errno here nor an ErrPermission; instead it
|
||||
// shows up as an OpaqueErrno. We test this here.
|
||||
if o := (*errbase.OpaqueErrno)(nil); errors.As(err, &o) {
|
||||
return o.Is(ErrPermission)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsExist returns a boolean indicating whether the error is known to report
|
||||
// that a file or directory already exists. It is satisfied by ErrExist as
|
||||
// well as some syscall errors.
|
||||
//
|
||||
// This function differs from os.IsExist() in that it
|
||||
// can identify an error through wrapping layers.
|
||||
func IsExist(err error) bool {
|
||||
// errors.Is() is not able to peek through os.SyscallError,
|
||||
// whereas os.IsExist() can. Conversely, os.IsExist()
|
||||
// cannot peek through Unwrap, whereas errors.Is() can. So we
|
||||
// need to try both.
|
||||
if errors.Is(err, ErrExist) || os.IsExist(errors.UnwrapAll(err)) {
|
||||
return true
|
||||
}
|
||||
// If a syscall errno representing ErrExist was encoded on a
|
||||
// different platform, and decoded here, then it will show up as
|
||||
// neither a syscall errno here nor an ErrExist; instead it
|
||||
// shows up as an OpaqueErrno. We test this here.
|
||||
if o := (*errbase.OpaqueErrno)(nil); errors.As(err, &o) {
|
||||
return o.Is(ErrExist)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsNotExist returns a boolean indicating whether the error is known to
|
||||
// report that a file or directory does not exist. It is satisfied by
|
||||
// ErrNotExist as well as some syscall errors.
|
||||
//
|
||||
// This function differs from os.IsNotExist() in that it
|
||||
// can identify an error through wrapping layers.
|
||||
func IsNotExist(err error) bool {
|
||||
// errors.Is() is not able to peek through os.SyscallError,
|
||||
// whereas os.IsNotExist() can. Conversely, os.IsNotExist()
|
||||
// cannot peek through Unwrap, whereas errors.Is() can. So we
|
||||
// need to try both.
|
||||
if errors.Is(err, ErrNotExist) || os.IsNotExist(errors.UnwrapAll(err)) {
|
||||
return true
|
||||
}
|
||||
// If a syscall errno representing ErrNotExist was encoded on a
|
||||
// different platform, and decoded here, then it will show up as
|
||||
// neither a syscall errno here nor an ErrNotExist; instead it
|
||||
// shows up as an OpaqueErrno. We test this here.
|
||||
if o := (*errbase.OpaqueErrno)(nil); errors.As(err, &o) {
|
||||
return o.Is(ErrNotExist)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsTimeout returns a boolean indicating whether the error is known
|
||||
// to report that a timeout occurred.
|
||||
//
|
||||
// This function differs from os.IsTimeout() in that it
|
||||
// can identify an error through wrapping layers.
|
||||
func IsTimeout(err error) bool {
|
||||
// os.IsTimeout() cannot peek through Unwrap. We need errors.If()
|
||||
// for that.
|
||||
_, ok := errors.If(err, func(err error) (interface{}, bool) {
|
||||
return nil, os.IsTimeout(err)
|
||||
})
|
||||
return ok
|
||||
}
|
||||
413
vendor/github.com/cockroachdb/errors/report/report.go
generated
vendored
Normal file
413
vendor/github.com/cockroachdb/errors/report/report.go
generated
vendored
Normal file
@@ -0,0 +1,413 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 report
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cockroachdb/errors/domains"
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/errors/withstack"
|
||||
"github.com/cockroachdb/redact"
|
||||
sentry "github.com/getsentry/sentry-go"
|
||||
)
|
||||
|
||||
// BuildSentryReport builds the components of a sentry report. This
|
||||
// can be used instead of ReportError() below to use additional custom
|
||||
// conditions in the reporting or add additional reporting tags.
|
||||
//
|
||||
// The Sentry Event is populated for maximal utility when exploited in
|
||||
// the Sentry.io web interface and database.
|
||||
//
|
||||
// A Sentry report is displayed visually in the Sentry UI as follows:
|
||||
//
|
||||
// //////////////
|
||||
// Title: (1) some prefix in bold (2) one line for a stack trace
|
||||
// (3) a single-line subtitle
|
||||
//
|
||||
// (4) the tags, as a tag soup (concatenated in a single paragraph,
|
||||
// unsorted)
|
||||
//
|
||||
// (5) a "message"
|
||||
//
|
||||
// (6) zero or more "exceptions", each composed of:
|
||||
//
|
||||
// (7) a bold title
|
||||
// (8) some freeform text
|
||||
// (9) a stack trace
|
||||
//
|
||||
// (10) metadata fields: environment, arch, etc
|
||||
//
|
||||
// (11) "Additional data" fields
|
||||
//
|
||||
// (12) SDK version
|
||||
// ///////////////
|
||||
//
|
||||
// These visual items map to the Sentry Event object as follows:
|
||||
//
|
||||
// (1) the Type field of the 1st Exception object, if any
|
||||
//
|
||||
// otherwise the Message field
|
||||
//
|
||||
// (2) the topmost entry from the Stacktrace field of the 1st Exception object, if any
|
||||
// (3) the Value field of the 1st Exception object, if any, unwrapped as a single line
|
||||
// (4) the Tags field
|
||||
// (5) the Message field
|
||||
// (7) the Type field (same as (1) for 1st exception)
|
||||
// (8) the Value field (same as (3) for 1st exception)
|
||||
// (9) the Stacktrace field (input to (2) on 1st exception)
|
||||
// (10) the other fields on the Event object
|
||||
// (11) the Extra field
|
||||
//
|
||||
// (Note how the top-level title fields (1) (3) are unrelated to the
|
||||
// Message field in the event, which is surprising!)
|
||||
//
|
||||
// Given this mapping, an error object is decomposed as follows:
|
||||
//
|
||||
// (1)/(7): <filename>:<lineno> (<functionname>)
|
||||
// (3)/(8): first line of verbose error printout
|
||||
// (4): not populated in this function, caller is to manage this
|
||||
// (5): detailed structure of the entire error object, with references to
|
||||
//
|
||||
// additional "exception" objects
|
||||
//
|
||||
// (9): generated from innermost stack trace
|
||||
// (6): every exception object after the 1st reports additional stack trace contexts
|
||||
// (11): the detailed error types and their error mark.
|
||||
//
|
||||
// If there is no stack trace in the error, a synthetic Exception
|
||||
// object is still produced to provide visual detail in the Sentry UI.
|
||||
//
|
||||
// Note that if a layer in the error has both a stack trace (ie
|
||||
// provides the `StackTrace()` interface) and also safe details
|
||||
// (`SafeDetails()`) other than the stack trace, only the stack trace
|
||||
// is included in the Sentry report. This does not affect error types
|
||||
// provided by the library, but could impact error types defined by
|
||||
// 3rd parties. This limitation may be lifted in a later version.
|
||||
func BuildSentryReport(err error) (event *sentry.Event, extraDetails map[string]interface{}) {
|
||||
if err == nil {
|
||||
// No error: do nothing.
|
||||
return
|
||||
}
|
||||
|
||||
// First step is to collect the details.
|
||||
var stacks []*withstack.ReportableStackTrace
|
||||
var details []errbase.SafeDetailPayload
|
||||
visitAllMulti(err, func(c error) {
|
||||
st := withstack.GetReportableStackTrace(c)
|
||||
stacks = append(stacks, st)
|
||||
|
||||
sd := errbase.GetSafeDetails(c)
|
||||
details = append(details, sd)
|
||||
})
|
||||
module := string(domains.GetDomain(err))
|
||||
|
||||
// firstDetailLine is the first detail string encountered.
|
||||
// This is added as decoration to the first Exception
|
||||
// payload (either from the error object or synthetic)
|
||||
// so as to populate the Sentry report title.
|
||||
var firstDetailLine string
|
||||
|
||||
// longMsgBuf will become the Message field, which contains the full
|
||||
// structure of the error.
|
||||
var longMsgBuf strings.Builder
|
||||
if f, l, _, ok := withstack.GetOneLineSource(err); ok {
|
||||
fmt.Fprintf(&longMsgBuf, "%s:%d: ", f, l)
|
||||
}
|
||||
// Include the verbose error printout, with sensitive bits redacted out.
|
||||
verboseErr := redact.Sprintf("%+v", err).Redact().StripMarkers()
|
||||
if verboseErr != redactedMarker {
|
||||
idx := strings.IndexByte(verboseErr, '\n')
|
||||
if idx == -1 {
|
||||
firstDetailLine = verboseErr
|
||||
} else {
|
||||
firstDetailLine = verboseErr[:idx]
|
||||
}
|
||||
}
|
||||
fmt.Fprint(&longMsgBuf, verboseErr)
|
||||
|
||||
// sep is used to separate the entries in the longMsgBuf / Message
|
||||
// payload.
|
||||
sep := ""
|
||||
|
||||
// extras will become the per-layer "Additional data" fields.
|
||||
extras := make(map[string]interface{})
|
||||
|
||||
// extraNum counts the number of "Additional data" payloads and is
|
||||
// used to generate the cross-reference counters in the Message
|
||||
// payload.
|
||||
extraNum := 1
|
||||
|
||||
// typesBuf will become the payload for the "error types" Additional
|
||||
// data field. It explains the Go types of the layers in the error
|
||||
// object.
|
||||
var typesBuf strings.Builder
|
||||
|
||||
// exceptions accumulates the Exception payloads.
|
||||
var exceptions []sentry.Exception
|
||||
|
||||
// leafErrorType is the type name of the leaf error.
|
||||
// This is used as fallback when no Exception payload is generated.
|
||||
var leafErrorType string
|
||||
|
||||
// Iterate from the last (innermost) to first (outermost) error
|
||||
// layer. We iterate in this order because we want to describe the
|
||||
// error from innermost to outermost layer in longMsgBuf and
|
||||
// typesBuf.
|
||||
longMsgBuf.WriteString("\n-- report composition:\n")
|
||||
for i := len(details) - 1; i >= 0; i-- {
|
||||
// Collect the type name for this layer of error wrapping, towards
|
||||
// the "error types" additional data field.
|
||||
fullTypeName := details[i].OriginalTypeName
|
||||
mark := details[i].ErrorTypeMark
|
||||
fm := "*"
|
||||
if fullTypeName != mark.FamilyName {
|
||||
// fullTypeName can be different from the family when an error type has
|
||||
// been renamed or moved.
|
||||
fm = mark.FamilyName
|
||||
}
|
||||
fmt.Fprintf(&typesBuf, "%s (%s::%s)\n", fullTypeName, fm, mark.Extension)
|
||||
shortTypename := lastPathComponent(fullTypeName)
|
||||
if i == len(details)-1 {
|
||||
leafErrorType = shortTypename
|
||||
}
|
||||
|
||||
// Compose the Message line for this layer.
|
||||
//
|
||||
// The message line consists of:
|
||||
// - optionally, a file/line reference, if a stack trace was available.
|
||||
// - the error/wrapper type name, with file prefix removed.
|
||||
// - optionally, the first line of the first detail string, if one is available.
|
||||
// - optionally, references to stack trace / details.
|
||||
|
||||
// If not at the first layer, separate from the previous layer
|
||||
// with a newline character.
|
||||
longMsgBuf.WriteString(sep)
|
||||
sep = "\n"
|
||||
// Add a file:lineno prefix, if there's a stack trace entry with
|
||||
// that info.
|
||||
var file, fn string
|
||||
var lineno int
|
||||
if stacks[i] != nil && len(stacks[i].Frames) > 0 {
|
||||
f := stacks[i].Frames[len(stacks[i].Frames)-1]
|
||||
file = lastPathComponent(f.Filename)
|
||||
fn = f.Function
|
||||
lineno = f.Lineno
|
||||
fmt.Fprintf(&longMsgBuf, "%s:%d: ", file, f.Lineno)
|
||||
}
|
||||
longMsgBuf.WriteString(shortTypename)
|
||||
|
||||
// Now decide what kind of payload we want to add to the Event
|
||||
// object.
|
||||
|
||||
// Is there a stack trace?
|
||||
if st := stacks[i]; st != nil {
|
||||
var excType strings.Builder
|
||||
if file != "" {
|
||||
fmt.Fprintf(&excType, "%s:%d ", file, lineno)
|
||||
}
|
||||
if fn != "" {
|
||||
fmt.Fprintf(&excType, "(%s)", fn)
|
||||
}
|
||||
if excType.Len() == 0 {
|
||||
excType.WriteString("<unknown error>")
|
||||
}
|
||||
exc := sentry.Exception{
|
||||
Module: module,
|
||||
Stacktrace: st,
|
||||
Type: excType.String(),
|
||||
Value: shortTypename,
|
||||
}
|
||||
|
||||
// Refer to the exception payload in the Message field.
|
||||
//
|
||||
// We only add a numeric counter for every exception *after* the
|
||||
// first one. This is because the 1st exception payload is
|
||||
// special, it is used as report title for Sentry and we don't
|
||||
// want to pollute that title with a counter.
|
||||
if len(exceptions) == 0 {
|
||||
longMsgBuf.WriteString(" (top exception)")
|
||||
} else {
|
||||
counterStr := fmt.Sprintf("(%d)", extraNum)
|
||||
extraNum++
|
||||
exc.Type = counterStr + " " + exc.Type
|
||||
fmt.Fprintf(&longMsgBuf, " %s", counterStr)
|
||||
}
|
||||
|
||||
exceptions = append(exceptions, exc)
|
||||
} else {
|
||||
// No stack trace.
|
||||
// Are there safe details? If so, print the first safe detail
|
||||
// string (we're assuming that all the important bits will
|
||||
// also be included in the verbose printout, so there's no
|
||||
// need to dig out more safe strings here.)
|
||||
//
|
||||
// TODO(knz): the SafeDetails API is not really meant for Sentry
|
||||
// reporting. Once we have more experience to prove that the
|
||||
// verbose printout is sufficient, we can remove the SafeDetails
|
||||
// from sentry reports.
|
||||
//
|
||||
// Note: we only print the details if no stack trace was found
|
||||
// at that level. This is because stack trace annotations also
|
||||
// produce the stack trace as safe detail string.
|
||||
if len(details[i].SafeDetails) > 0 {
|
||||
d := details[i].SafeDetails[0]
|
||||
if j := strings.IndexByte(d, '\n'); j >= 0 {
|
||||
d = d[:j]
|
||||
}
|
||||
if d != "" {
|
||||
longMsgBuf.WriteString(": ")
|
||||
longMsgBuf.WriteString(d)
|
||||
if firstDetailLine == "" {
|
||||
// Keep the string for later.
|
||||
firstDetailLine = d
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if extraNum > 1 {
|
||||
// Make the message part more informational.
|
||||
longMsgBuf.WriteString("\n(check the extra data payloads)")
|
||||
}
|
||||
|
||||
// Produce the full error type description.
|
||||
extras["error types"] = typesBuf.String()
|
||||
|
||||
// Sentry is mightily annoying.
|
||||
reverseExceptionOrder(exceptions)
|
||||
|
||||
// Start assembling the event.
|
||||
event = sentry.NewEvent()
|
||||
event.Message = longMsgBuf.String()
|
||||
event.Exception = exceptions
|
||||
|
||||
// If there is no exception payload, synthesize one.
|
||||
if len(event.Exception) == 0 {
|
||||
// We know we don't have a stack trace to extract line/function
|
||||
// info from (if we had, we'd have an Exception payload at that
|
||||
// point). Instead, we make a best effort using bits and pieces
|
||||
// assembled so far.
|
||||
event.Exception = append(event.Exception, sentry.Exception{
|
||||
Module: module,
|
||||
Type: leafErrorType,
|
||||
Value: firstDetailLine,
|
||||
})
|
||||
} else {
|
||||
// We have at least one exception payload already. In that case,
|
||||
// decorate the first exception with the first detail line if
|
||||
// there is one. This enhances the title of the Sentry report.
|
||||
//
|
||||
// This goes from:
|
||||
// <file> (func)
|
||||
// <type>
|
||||
//
|
||||
// to:
|
||||
// <file> (func)
|
||||
// wrapped <leaftype>[: <detail>]
|
||||
// via <type>
|
||||
// if wrapped; or if leaf:
|
||||
// <file> (func)
|
||||
// <leaftype>[: <detail>]
|
||||
|
||||
var newValueBuf strings.Builder
|
||||
// Note that "first exception" is the last item in the slice,
|
||||
// because... Sentry is annoying.
|
||||
firstExc := &event.Exception[len(event.Exception)-1]
|
||||
// Add the leaf error type if different from the type at this
|
||||
// level (this is going to be the common case, unless using
|
||||
// pkg/errors.WithStack).
|
||||
wrapped := false
|
||||
if firstExc.Value == leafErrorType {
|
||||
newValueBuf.WriteString(firstExc.Value)
|
||||
} else {
|
||||
newValueBuf.WriteString(leafErrorType)
|
||||
wrapped = true
|
||||
}
|
||||
// Add the detail info line, if any.
|
||||
if firstDetailLine != "" {
|
||||
fmt.Fprintf(&newValueBuf, ": %s", firstDetailLine)
|
||||
}
|
||||
if wrapped {
|
||||
fmt.Fprintf(&newValueBuf, "\nvia %s", firstExc.Value)
|
||||
}
|
||||
firstExc.Value = newValueBuf.String()
|
||||
}
|
||||
|
||||
return event, extras
|
||||
}
|
||||
|
||||
var redactedMarker = redact.RedactableString(redact.RedactedMarker()).StripMarkers()
|
||||
|
||||
// ReportError reports the given error to Sentry. The caller is responsible for
|
||||
// checking whether telemetry is enabled, and calling the sentry.Flush()
|
||||
// function to wait for the report to be uploaded. (By default,
|
||||
// Sentry submits reports asynchronously.)
|
||||
//
|
||||
// Note: an empty 'eventID' can be returned which signifies that the error was
|
||||
// not reported. This can occur when Sentry client hasn't been properly
|
||||
// configured or Sentry client decided to not report the error (due to
|
||||
// configured sampling rate, callbacks, Sentry's event processors, etc).
|
||||
func ReportError(err error) (eventID string) {
|
||||
event, extraDetails := BuildSentryReport(err)
|
||||
|
||||
for extraKey, extraValue := range extraDetails {
|
||||
event.Extra[extraKey] = extraValue
|
||||
}
|
||||
|
||||
// Avoid leaking the machine's hostname by injecting the literal "<redacted>".
|
||||
// Otherwise, sentry.Client.Capture will see an empty ServerName field and
|
||||
// automatically fill in the machine's hostname.
|
||||
event.ServerName = "<redacted>"
|
||||
|
||||
tags := map[string]string{
|
||||
"report_type": "error",
|
||||
}
|
||||
for key, value := range tags {
|
||||
event.Tags[key] = value
|
||||
}
|
||||
|
||||
res := sentry.CaptureEvent(event)
|
||||
if res != nil {
|
||||
eventID = string(*res)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func lastPathComponent(tn string) string {
|
||||
// Strip the path prefix.
|
||||
if i := strings.LastIndexByte(tn, '/'); i >= 0 {
|
||||
tn = tn[i+1:]
|
||||
}
|
||||
return tn
|
||||
}
|
||||
|
||||
func reverseExceptionOrder(ex []sentry.Exception) {
|
||||
for i := 0; i < len(ex)/2; i++ {
|
||||
ex[i], ex[len(ex)-i-1] = ex[len(ex)-i-1], ex[i]
|
||||
}
|
||||
}
|
||||
|
||||
func visitAllMulti(err error, f func(error)) {
|
||||
f(err)
|
||||
if e := errbase.UnwrapOnce(err); e != nil {
|
||||
visitAllMulti(e, f)
|
||||
}
|
||||
for _, e := range errbase.UnwrapMulti(err) {
|
||||
visitAllMulti(e, f)
|
||||
}
|
||||
}
|
||||
37
vendor/github.com/cockroachdb/errors/report/reportables.go
generated
vendored
Normal file
37
vendor/github.com/cockroachdb/errors/report/reportables.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 report
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
)
|
||||
|
||||
// StackTrace is an object suitable for inclusion in errors that can
|
||||
// ultimately be reported with ReportInternalError() or similar.
|
||||
type StackTrace = sentry.Stacktrace
|
||||
|
||||
// PrintStackTrace produces a human-readable partial representation of
|
||||
// the stack trace.
|
||||
func PrintStackTrace(s *StackTrace) string {
|
||||
var buf bytes.Buffer
|
||||
for i := len(s.Frames) - 1; i >= 0; i-- {
|
||||
f := s.Frames[i]
|
||||
fmt.Fprintf(&buf, "%s:%d: in %s()\n", f.Filename, f.Lineno, f.Function)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
103
vendor/github.com/cockroachdb/errors/report_api.go
generated
vendored
Normal file
103
vendor/github.com/cockroachdb/errors/report_api.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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
|
||||
|
||||
import (
|
||||
"github.com/cockroachdb/errors/report"
|
||||
"github.com/getsentry/sentry-go"
|
||||
)
|
||||
|
||||
// BuildSentryReport builds the components of a sentry report. This
|
||||
// can be used instead of ReportError() below to use additional custom
|
||||
// conditions in the reporting or add additional reporting tags.
|
||||
//
|
||||
// The Sentry Event is populated for maximal utility when exploited in
|
||||
// the Sentry.io web interface and database.
|
||||
//
|
||||
// A Sentry report is displayed visually in the Sentry UI as follows:
|
||||
//
|
||||
////////////////
|
||||
// Title: (1) some prefix in bold (2) one line for a stack trace
|
||||
// (3) a single-line subtitle
|
||||
//
|
||||
// (4) the tags, as a tag soup (concatenated in a single paragraph,
|
||||
// unsorted)
|
||||
//
|
||||
// (5) a "message"
|
||||
//
|
||||
// (6) zero or more "exceptions", each composed of:
|
||||
// (7) a bold title
|
||||
// (8) some freeform text
|
||||
// (9) a stack trace
|
||||
//
|
||||
// (10) metadata fields: environment, arch, etc
|
||||
//
|
||||
// (11) "Additional data" fields
|
||||
//
|
||||
// (12) SDK version
|
||||
/////////////////
|
||||
//
|
||||
// These visual items map to the Sentry Event object as follows:
|
||||
//
|
||||
// (1) the Type field of the 1st Exception object, if any
|
||||
// otherwise the Message field
|
||||
// (2) the topmost entry from the Stacktrace field of the 1st Exception object, if any
|
||||
// (3) the Value field of the 1st Exception object, if any, unwrapped as a single line
|
||||
// (4) the Tags field
|
||||
// (5) the Message field
|
||||
// (7) the Type field (same as (1) for 1st exception)
|
||||
// (8) the Value field (same as (3) for 1st exception)
|
||||
// (9) the Stacktrace field (input to (2) on 1st exception)
|
||||
// (10) the other fields on the Event object
|
||||
// (11) the Extra field
|
||||
//
|
||||
// (Note how the top-level title fields (1) (3) are unrelated to the
|
||||
// Message field in the event, which is surprising!)
|
||||
//
|
||||
// Given this mapping, an error object is decomposed as follows:
|
||||
//
|
||||
// (1)/(7): <filename>:<lineno> (<functionname>)
|
||||
// (3)/(8): <error type>: <first safe detail line, if any>
|
||||
// (4): not populated in this function, caller is to manage this
|
||||
// (5): detailed structure of the entire error object, with references to "additional data"
|
||||
// and additional "exception" objects
|
||||
// (9): generated from innermost stack trace
|
||||
// (6): every exception object after the 1st reports additional stack trace contexts
|
||||
// (11): "additional data" populated from safe detail payloads
|
||||
//
|
||||
// If there is no stack trace in the error, a synthetic Exception
|
||||
// object is still produced to provide visual detail in the Sentry UI.
|
||||
//
|
||||
// Note that if a layer in the error has both a stack trace (ie
|
||||
// provides the `StackTrace()` interface) and also safe details
|
||||
// (`SafeDetails()`) other than the stack trace, only the stack trace
|
||||
// is included in the Sentry report. This does not affect error types
|
||||
// provided by the library, but could impact error types defined by
|
||||
// 3rd parties. This limitation may be lifted in a later version.
|
||||
//
|
||||
func BuildSentryReport(err error) (*sentry.Event, map[string]interface{}) {
|
||||
return report.BuildSentryReport(err)
|
||||
}
|
||||
|
||||
// ReportError reports the given error to Sentry. The caller is responsible for
|
||||
// checking whether telemetry is enabled, and calling the sentry.Flush()
|
||||
// function to wait for the report to be uploaded. (By default,
|
||||
// Sentry submits reports asynchronously.)
|
||||
//
|
||||
// Note: an empty 'eventID' can be returned which signifies that the error was
|
||||
// not reported. This can occur when Sentry client hasn't been properly
|
||||
// configured or Sentry client decided to not report the error (due to
|
||||
// configured sampling rate, callbacks, Sentry's event processors, etc).
|
||||
func ReportError(err error) string { return report.ReportError(err) }
|
||||
25
vendor/github.com/cockroachdb/errors/safedetails/redact.go
generated
vendored
Normal file
25
vendor/github.com/cockroachdb/errors/safedetails/redact.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 safedetails
|
||||
|
||||
import "github.com/cockroachdb/redact"
|
||||
|
||||
// Redact returns a redacted version of the supplied item that is safe to use in
|
||||
// anonymized reporting.
|
||||
//
|
||||
// NB: this interface is obsolete. Use redact.Sprint() directly.
|
||||
func Redact(r interface{}) string {
|
||||
return redact.Sprint(r).Redact().StripMarkers()
|
||||
}
|
||||
64
vendor/github.com/cockroachdb/errors/safedetails/safedetails.go
generated
vendored
Normal file
64
vendor/github.com/cockroachdb/errors/safedetails/safedetails.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 safedetails
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/cockroachdb/redact"
|
||||
)
|
||||
|
||||
// WithSafeDetails annotates an error with the given reportable details.
|
||||
// The format is made available as a PII-free string, alongside
|
||||
// with a PII-free representation of every additional argument.
|
||||
// Arguments can be reported as-is (without redaction) by wrapping
|
||||
// them using the Safe() function.
|
||||
//
|
||||
// If the format is empty and there are no arguments, the
|
||||
// error argument is returned unchanged.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func WithSafeDetails(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if len(format) == 0 && len(args) == 0 {
|
||||
return err
|
||||
}
|
||||
details := []string{
|
||||
redact.Sprintf(format, args...).Redact().StripMarkers(),
|
||||
}
|
||||
return &withSafeDetails{cause: err, safeDetails: details}
|
||||
}
|
||||
|
||||
var refSafeType = reflect.TypeOf(redact.Safe(""))
|
||||
|
||||
// SafeMessager is implemented by objects which have a way of
|
||||
// representing themselves suitably redacted for anonymized reporting.
|
||||
//
|
||||
// NB: this interface is obsolete. Use redact.SafeFormatter instead.
|
||||
type SafeMessager = redact.SafeMessager
|
||||
|
||||
// Safe wraps the given object into an opaque struct that implements
|
||||
// SafeMessager: its contents can be included as-is in PII-free
|
||||
// strings in error objects and reports.
|
||||
//
|
||||
// NB: this is obsolete. Use redact.Safe instead.
|
||||
func Safe(v interface{}) redact.SafeValue {
|
||||
return redact.Safe(v)
|
||||
}
|
||||
78
vendor/github.com/cockroachdb/errors/safedetails/with_safedetails.go
generated
vendored
Normal file
78
vendor/github.com/cockroachdb/errors/safedetails/with_safedetails.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 safedetails
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/redact"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type withSafeDetails struct {
|
||||
cause error
|
||||
|
||||
safeDetails []string
|
||||
}
|
||||
|
||||
func (e *withSafeDetails) SafeDetails() []string {
|
||||
return e.safeDetails
|
||||
}
|
||||
|
||||
var _ fmt.Formatter = (*withSafeDetails)(nil)
|
||||
var _ errbase.SafeFormatter = (*withSafeDetails)(nil)
|
||||
|
||||
// Printing a withSecondary reveals the details.
|
||||
func (e *withSafeDetails) Format(s fmt.State, verb rune) { errbase.FormatError(e, s, verb) }
|
||||
|
||||
// SafeFormatError implements errbase.SafeFormatter.
|
||||
func (e *withSafeDetails) SafeFormatError(p errbase.Printer) error {
|
||||
if p.Detail() {
|
||||
comma := redact.SafeString("")
|
||||
if len(e.safeDetails) != 1 {
|
||||
plural := redact.SafeString("s")
|
||||
if len(e.safeDetails) == 1 {
|
||||
plural = ""
|
||||
}
|
||||
p.Printf("%d safe detail%s enclosed", redact.Safe(len(e.safeDetails)), plural)
|
||||
comma = "\n"
|
||||
}
|
||||
// We hide the details from %+v; they are included
|
||||
// during Sentry reporting.
|
||||
for _, s := range e.safeDetails {
|
||||
p.Printf("%s%s", comma, redact.Safe(s))
|
||||
comma = "\n"
|
||||
}
|
||||
}
|
||||
return e.cause
|
||||
}
|
||||
|
||||
func (e *withSafeDetails) Error() string { return e.cause.Error() }
|
||||
func (e *withSafeDetails) Cause() error { return e.cause }
|
||||
func (e *withSafeDetails) Unwrap() error { return e.cause }
|
||||
|
||||
func decodeWithSafeDetails(
|
||||
_ context.Context, cause error, _ string, safeDetails []string, _ proto.Message,
|
||||
) error {
|
||||
return &withSafeDetails{cause: cause, safeDetails: safeDetails}
|
||||
}
|
||||
|
||||
func init() {
|
||||
tn := errbase.GetTypeKey((*withSafeDetails)(nil))
|
||||
errbase.RegisterWrapperDecoder(tn, decodeWithSafeDetails)
|
||||
// Note: no encoder needed, the default implementation is suitable.
|
||||
}
|
||||
56
vendor/github.com/cockroachdb/errors/safedetails_api.go
generated
vendored
Normal file
56
vendor/github.com/cockroachdb/errors/safedetails_api.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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
|
||||
|
||||
import (
|
||||
"github.com/cockroachdb/errors/safedetails"
|
||||
"github.com/cockroachdb/redact"
|
||||
)
|
||||
|
||||
// WithSafeDetails annotates an error with the given reportable details.
|
||||
// The format is made available as a PII-free string, alongside
|
||||
// with a PII-free representation of every additional argument.
|
||||
// Arguments can be reported as-is (without redaction) by wrapping
|
||||
// them using the Safe() function.
|
||||
//
|
||||
// If the format is empty and there are no arguments, the
|
||||
// error argument is returned unchanged.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func WithSafeDetails(err error, format string, args ...interface{}) error {
|
||||
return safedetails.WithSafeDetails(err, format, args...)
|
||||
}
|
||||
|
||||
// SafeMessager aliases redact.SafeMessager.
|
||||
//
|
||||
// NB: this is obsolete. Use redact.SafeFormatter or
|
||||
// errors.SafeFormatter instead.
|
||||
type SafeMessager = redact.SafeMessager
|
||||
|
||||
// Safe wraps the given object into an opaque struct that implements
|
||||
// SafeMessager: its contents can be included as-is in PII-free
|
||||
// strings in error objects and reports.
|
||||
//
|
||||
// NB: this is obsolete. Use redact.Safe instead.
|
||||
func Safe(v interface{}) redact.SafeValue { return safedetails.Safe(v) }
|
||||
|
||||
// Redact returns a redacted version of the supplied item that is safe to use in
|
||||
// anonymized reporting.
|
||||
//
|
||||
// NB: this interface is obsolete. Use redact.Sprint() directly.
|
||||
func Redact(r interface{}) string { return safedetails.Redact(r) }
|
||||
46
vendor/github.com/cockroachdb/errors/secondary/secondary.go
generated
vendored
Normal file
46
vendor/github.com/cockroachdb/errors/secondary/secondary.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 secondary
|
||||
|
||||
// WithSecondaryError enhances the error given as first argument with
|
||||
// an annotation that carries the error given as second argument. The
|
||||
// second error does not participate in cause analysis (Is, etc) and
|
||||
// is only revealed when printing out the error or collecting safe
|
||||
// (PII-free) details for reporting.
|
||||
//
|
||||
// If additionalErr is nil, the first error is returned as-is.
|
||||
//
|
||||
// Tip: consider using CombineErrors() below in the general case.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`, shows details from secondary error.
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func WithSecondaryError(err error, additionalErr error) error {
|
||||
if err == nil || additionalErr == nil {
|
||||
return err
|
||||
}
|
||||
return &withSecondaryError{cause: err, secondaryError: additionalErr}
|
||||
}
|
||||
|
||||
// CombineErrors returns err, or, if err is nil, otherErr.
|
||||
// if err is non-nil, otherErr is attached as secondary error.
|
||||
// See the documentation of `WithSecondaryError()` for details.
|
||||
func CombineErrors(err error, otherErr error) error {
|
||||
if err == nil {
|
||||
return otherErr
|
||||
}
|
||||
return WithSecondaryError(err, otherErr)
|
||||
}
|
||||
89
vendor/github.com/cockroachdb/errors/secondary/with_secondary.go
generated
vendored
Normal file
89
vendor/github.com/cockroachdb/errors/secondary/with_secondary.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 secondary
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type withSecondaryError struct {
|
||||
cause error
|
||||
|
||||
// secondaryError is an additional error payload that provides
|
||||
// additional context towards troubleshooting.
|
||||
secondaryError error
|
||||
}
|
||||
|
||||
var _ error = (*withSecondaryError)(nil)
|
||||
var _ errbase.SafeDetailer = (*withSecondaryError)(nil)
|
||||
var _ fmt.Formatter = (*withSecondaryError)(nil)
|
||||
var _ errbase.SafeFormatter = (*withSecondaryError)(nil)
|
||||
|
||||
// SafeDetails reports the PII-free details from the secondary error.
|
||||
func (e *withSecondaryError) SafeDetails() []string {
|
||||
var details []string
|
||||
for err := e.secondaryError; err != nil; err = errbase.UnwrapOnce(err) {
|
||||
sd := errbase.GetSafeDetails(err)
|
||||
details = sd.Fill(details)
|
||||
}
|
||||
return details
|
||||
}
|
||||
|
||||
// Printing a withSecondary reveals the details.
|
||||
func (e *withSecondaryError) Format(s fmt.State, verb rune) { errbase.FormatError(e, s, verb) }
|
||||
|
||||
func (e *withSecondaryError) SafeFormatError(p errbase.Printer) (next error) {
|
||||
if p.Detail() {
|
||||
p.Printf("secondary error attachment\n%+v", e.secondaryError)
|
||||
}
|
||||
return e.cause
|
||||
}
|
||||
|
||||
func (e *withSecondaryError) Error() string { return e.cause.Error() }
|
||||
func (e *withSecondaryError) Cause() error { return e.cause }
|
||||
func (e *withSecondaryError) Unwrap() error { return e.cause }
|
||||
|
||||
func encodeWithSecondaryError(ctx context.Context, err error) (string, []string, proto.Message) {
|
||||
e := err.(*withSecondaryError)
|
||||
enc := errbase.EncodeError(ctx, e.secondaryError)
|
||||
return "", nil, &enc
|
||||
}
|
||||
|
||||
func decodeWithSecondaryError(
|
||||
ctx context.Context, cause error, _ string, _ []string, payload proto.Message,
|
||||
) error {
|
||||
enc, ok := payload.(*errbase.EncodedError)
|
||||
if !ok {
|
||||
// If this ever happens, this means some version of the library
|
||||
// (presumably future) changed the payload type, and we're
|
||||
// receiving this here. In this case, give up and let
|
||||
// DecodeError use the opaque type.
|
||||
return nil
|
||||
}
|
||||
return &withSecondaryError{
|
||||
cause: cause,
|
||||
secondaryError: errbase.DecodeError(ctx, *enc),
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
tn := errbase.GetTypeKey((*withSecondaryError)(nil))
|
||||
errbase.RegisterWrapperDecoder(tn, decodeWithSecondaryError)
|
||||
errbase.RegisterWrapperEncoder(tn, encodeWithSecondaryError)
|
||||
}
|
||||
42
vendor/github.com/cockroachdb/errors/secondary_api.go
generated
vendored
Normal file
42
vendor/github.com/cockroachdb/errors/secondary_api.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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
|
||||
|
||||
import "github.com/cockroachdb/errors/secondary"
|
||||
|
||||
// WithSecondaryError enhances the error given as first argument with
|
||||
// an annotation that carries the error given as second argument. The
|
||||
// second error does not participate in cause analysis (Is, etc) and
|
||||
// is only revealed when printing out the error or collecting safe
|
||||
// (PII-free) details for reporting.
|
||||
//
|
||||
// If additionalErr is nil, the first error is returned as-is.
|
||||
//
|
||||
// Tip: consider using CombineErrors() below in the general case.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`, shows details from secondary error.
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func WithSecondaryError(err error, additionalErr error) error {
|
||||
return secondary.WithSecondaryError(err, additionalErr)
|
||||
}
|
||||
|
||||
// CombineErrors returns err, or, if err is nil, otherErr.
|
||||
// if err is non-nil, otherErr is attached as secondary error.
|
||||
// See the documentation of `WithSecondaryError()` for details.
|
||||
func CombineErrors(err, otherErr error) error {
|
||||
return secondary.CombineErrors(err, otherErr)
|
||||
}
|
||||
28
vendor/github.com/cockroachdb/errors/stdstrings/strings.go
generated
vendored
Normal file
28
vendor/github.com/cockroachdb/errors/stdstrings/strings.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 stdstrings
|
||||
|
||||
// IssueReferral is the additional hint text provided to ask users for further actions.
|
||||
const IssueReferral = `
|
||||
|
||||
Please check the public issue tracker to check whether this problem is
|
||||
already tracked. If you cannot find it there, please report the error
|
||||
with details by creating a new issue.
|
||||
|
||||
If you would rather not post publicly, please contact us directly
|
||||
using the support form.
|
||||
|
||||
We appreciate your feedback.
|
||||
`
|
||||
52
vendor/github.com/cockroachdb/errors/telemetrykeys/telemetrykeys.go
generated
vendored
Normal file
52
vendor/github.com/cockroachdb/errors/telemetrykeys/telemetrykeys.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 telemetrykeys
|
||||
|
||||
import "github.com/cockroachdb/errors/errbase"
|
||||
|
||||
// WithTelemetry annotates err with the given telemetry key(s).
|
||||
// The telemetry keys must be PII-free.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`.
|
||||
// - via `GetTelemetryKeys()` below.
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func WithTelemetry(err error, keys ...string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &withTelemetry{cause: err, keys: keys}
|
||||
}
|
||||
|
||||
// GetTelemetryKeys retrieves the (de-duplicated) set of
|
||||
// all telemetry keys present in the direct causal chain
|
||||
// of the error. The keys may not be sorted.
|
||||
func GetTelemetryKeys(err error) []string {
|
||||
keys := map[string]struct{}{}
|
||||
for ; err != nil; err = errbase.UnwrapOnce(err) {
|
||||
if w, ok := err.(*withTelemetry); ok {
|
||||
for _, k := range w.keys {
|
||||
keys[k] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
res := make([]string, 0, len(keys))
|
||||
for k := range keys {
|
||||
res = append(res, k)
|
||||
}
|
||||
return res
|
||||
}
|
||||
60
vendor/github.com/cockroachdb/errors/telemetrykeys/with_telemetry.go
generated
vendored
Normal file
60
vendor/github.com/cockroachdb/errors/telemetrykeys/with_telemetry.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 telemetrykeys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/cockroachdb/redact"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type withTelemetry struct {
|
||||
cause error
|
||||
keys []string
|
||||
}
|
||||
|
||||
var _ error = (*withTelemetry)(nil)
|
||||
var _ errbase.SafeDetailer = (*withTelemetry)(nil)
|
||||
var _ fmt.Formatter = (*withTelemetry)(nil)
|
||||
var _ errbase.SafeFormatter = (*withTelemetry)(nil)
|
||||
|
||||
func (w *withTelemetry) Error() string { return w.cause.Error() }
|
||||
func (w *withTelemetry) Cause() error { return w.cause }
|
||||
func (w *withTelemetry) Unwrap() error { return w.cause }
|
||||
|
||||
func (w *withTelemetry) SafeDetails() []string { return w.keys }
|
||||
|
||||
func (w *withTelemetry) Format(s fmt.State, verb rune) { errbase.FormatError(w, s, verb) }
|
||||
|
||||
func (w *withTelemetry) SafeFormatError(p errbase.Printer) (next error) {
|
||||
if p.Detail() {
|
||||
p.Printf("keys: [%s]", redact.Safe(strings.Join(w.keys, " ")))
|
||||
}
|
||||
return w.cause
|
||||
}
|
||||
|
||||
func decodeWithTelemetry(
|
||||
_ context.Context, cause error, _ string, keys []string, _ proto.Message,
|
||||
) error {
|
||||
return &withTelemetry{cause: cause, keys: keys}
|
||||
}
|
||||
|
||||
func init() {
|
||||
errbase.RegisterWrapperDecoder(errbase.GetTypeKey((*withTelemetry)(nil)), decodeWithTelemetry)
|
||||
}
|
||||
32
vendor/github.com/cockroachdb/errors/telemetrykeys_api.go
generated
vendored
Normal file
32
vendor/github.com/cockroachdb/errors/telemetrykeys_api.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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
|
||||
|
||||
import "github.com/cockroachdb/errors/telemetrykeys"
|
||||
|
||||
// WithTelemetry annotates err with the given telemetry key(s).
|
||||
// The telemetry keys must be PII-free.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`.
|
||||
// - via `GetTelemetryKeys()` below.
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
func WithTelemetry(err error, keys ...string) error { return telemetrykeys.WithTelemetry(err, keys...) }
|
||||
|
||||
// GetTelemetryKeys retrieves the (de-duplicated) set of
|
||||
// all telemetry keys present in the direct causal chain
|
||||
// of the error. The keys may not be sorted.
|
||||
func GetTelemetryKeys(err error) []string { return telemetrykeys.GetTelemetryKeys(err) }
|
||||
89
vendor/github.com/cockroachdb/errors/withstack/one_line_source.go
generated
vendored
Normal file
89
vendor/github.com/cockroachdb/errors/withstack/one_line_source.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 withstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
)
|
||||
|
||||
// GetOneLineSource extracts the file/line/function information
|
||||
// of the topmost caller in the innermost recorded stack trace.
|
||||
// The filename is simplified to remove the path prefix.
|
||||
// This is used e.g. to populate the "source" field in
|
||||
// PostgreSQL errors.
|
||||
func GetOneLineSource(err error) (file string, line int, fn string, ok bool) {
|
||||
// We want the innermost entry: start by recursing.
|
||||
if c := errbase.UnwrapOnce(err); c != nil {
|
||||
if file, line, fn, ok = GetOneLineSource(c); ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
// If we reach this point, we haven't found anything in the cause so
|
||||
// far. Look at the current level.
|
||||
|
||||
// If we have a stack trace in the style of github.com/pkg/errors
|
||||
// (either from there or our own withStack), use it.
|
||||
if st, ok := err.(errbase.StackTraceProvider); ok {
|
||||
return getOneLineSourceFromPkgStack(st.StackTrace())
|
||||
}
|
||||
|
||||
// If we have flattened a github.com/pkg/errors-style stack
|
||||
// trace to a string, it will happen in the error's safe details
|
||||
// and we need to parse it.
|
||||
if sd, ok := err.(errbase.SafeDetailer); ok {
|
||||
details := sd.SafeDetails()
|
||||
if len(details) > 0 {
|
||||
switch errbase.GetTypeKey(err) {
|
||||
case pkgFundamental, pkgWithStackName, ourWithStackName:
|
||||
return getOneLineSourceFromPrintedStack(details[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No conversion available - no stack trace.
|
||||
return "", 0, "", false
|
||||
}
|
||||
|
||||
func getOneLineSourceFromPkgStack(
|
||||
st errbase.StackTrace,
|
||||
) (file string, line int, fn string, ok bool) {
|
||||
if len(st) > 0 {
|
||||
st = st[:1]
|
||||
// Note: the stack trace logic changed between go 1.11 and 1.12.
|
||||
// Trying to analyze the frame PCs point-wise will cause
|
||||
// the output to change between the go versions.
|
||||
stS := fmt.Sprintf("%+v", st)
|
||||
return getOneLineSourceFromPrintedStack(stS)
|
||||
}
|
||||
return "", 0, "", false
|
||||
}
|
||||
|
||||
func getOneLineSourceFromPrintedStack(st string) (file string, line int, fn string, ok bool) {
|
||||
// We only need 3 lines: the function/file/line info will be on the first two lines.
|
||||
// See parsePrintedStack() for details.
|
||||
lines := strings.SplitN(strings.TrimSpace(st), "\n", 3)
|
||||
if len(lines) > 0 {
|
||||
_, file, line, fnName := parsePrintedStackEntry(lines, 0)
|
||||
if fnName != "unknown" {
|
||||
_, fn = functionName(fnName)
|
||||
}
|
||||
return filepath.Base(file), line, fn, true
|
||||
}
|
||||
return "", 0, "", false
|
||||
}
|
||||
204
vendor/github.com/cockroachdb/errors/withstack/reportable.go
generated
vendored
Normal file
204
vendor/github.com/cockroachdb/errors/withstack/reportable.go
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 withstack
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
"github.com/getsentry/sentry-go"
|
||||
pkgErr "github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ReportableStackTrace aliases the type of the same name in the sentry
|
||||
// package. This is used by the 'report' error package.
|
||||
type ReportableStackTrace = sentry.Stacktrace
|
||||
|
||||
// GetReportableStackTrace extracts a stack trace embedded in the
|
||||
// given error in the format suitable for Sentry reporting.
|
||||
//
|
||||
// This supports:
|
||||
// - errors generated by github.com/pkg/errors (either generated
|
||||
// locally or after transfer through the network),
|
||||
// - errors generated with WithStack() in this package,
|
||||
// - any other error that implements a StackTrace() method
|
||||
// returning a StackTrace from github.com/pkg/errors.
|
||||
//
|
||||
// Note: Sentry wants the oldest call frame first, so
|
||||
// the entries are reversed in the result.
|
||||
func GetReportableStackTrace(err error) *ReportableStackTrace {
|
||||
// If we have a stack trace in the style of github.com/pkg/errors
|
||||
// (either from there or our own withStack), use it.
|
||||
if st, ok := err.(errbase.StackTraceProvider); ok {
|
||||
return convertPkgStack(st.StackTrace())
|
||||
}
|
||||
|
||||
// If we have flattened a github.com/pkg/errors-style stack
|
||||
// trace to a string, it will happen in the error's safe details
|
||||
// and we need to parse it.
|
||||
if sd, ok := err.(errbase.SafeDetailer); ok {
|
||||
details := sd.SafeDetails()
|
||||
if len(details) > 0 {
|
||||
switch errbase.GetTypeKey(err) {
|
||||
case pkgFundamental, pkgWithStackName, ourWithStackName:
|
||||
return parsePrintedStack(details[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No conversion available - no stack trace.
|
||||
return nil
|
||||
}
|
||||
|
||||
type frame = sentry.Frame
|
||||
|
||||
// convertPkgStack converts a StackTrace from github.com/pkg/errors
|
||||
// to a Stacktrace in github.com/getsentry/sentry-go.
|
||||
func convertPkgStack(st errbase.StackTrace) *ReportableStackTrace {
|
||||
// If there are no frames, the entire stacktrace is nil.
|
||||
if len(st) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Note: the stack trace logic changed between go 1.11 and 1.12.
|
||||
// Trying to analyze the frame PCs point-wise will cause
|
||||
// the output to change between the go versions.
|
||||
return parsePrintedStack(fmt.Sprintf("%+v", st))
|
||||
}
|
||||
|
||||
// trimPath is a copy of the same function in package sentry-go.
|
||||
func trimPath(filename string) string {
|
||||
for _, prefix := range trimPaths {
|
||||
if trimmed := strings.TrimPrefix(filename, prefix); len(trimmed) < len(filename) {
|
||||
return trimmed
|
||||
}
|
||||
}
|
||||
return filename
|
||||
}
|
||||
|
||||
var trimPaths []string
|
||||
|
||||
// init is a copy of the same function in package sentry-go.
|
||||
func init() {
|
||||
// Collect all source directories, and make sure they
|
||||
// end in a trailing "separator"
|
||||
for _, prefix := range build.Default.SrcDirs() {
|
||||
if prefix[len(prefix)-1] != filepath.Separator {
|
||||
prefix += string(filepath.Separator)
|
||||
}
|
||||
trimPaths = append(trimPaths, prefix)
|
||||
}
|
||||
}
|
||||
|
||||
// functionName is an adapted copy of the same function in package sentry-go.
|
||||
func functionName(fnName string) (pack string, name string) {
|
||||
name = fnName
|
||||
// We get this:
|
||||
// runtime/debug.*T·ptrmethod
|
||||
// and want this:
|
||||
// pack = runtime/debug
|
||||
// name = *T.ptrmethod
|
||||
if idx := strings.LastIndex(name, "."); idx != -1 {
|
||||
pack = name[:idx]
|
||||
name = name[idx+1:]
|
||||
}
|
||||
name = strings.Replace(name, "·", ".", -1)
|
||||
return
|
||||
}
|
||||
|
||||
// parsePrintedStack reverse-engineers a reportable stack trace from
|
||||
// the result of printing a github.com/pkg/errors stack trace with format %+v.
|
||||
func parsePrintedStack(st string) *ReportableStackTrace {
|
||||
// A printed stack trace looks like a repetition of either:
|
||||
// "unknown"
|
||||
// or
|
||||
// <result of fn.Name()>
|
||||
// <tab><file>:<linenum>
|
||||
// It's also likely to contain a heading newline character(s).
|
||||
var frames []frame
|
||||
lines := strings.Split(strings.TrimSpace(st), "\n")
|
||||
for i := 0; i < len(lines); i++ {
|
||||
nextI, file, line, fnName := parsePrintedStackEntry(lines, i)
|
||||
i = nextI
|
||||
|
||||
// Compose the frame.
|
||||
frame := frame{
|
||||
AbsPath: file,
|
||||
Filename: trimPath(file),
|
||||
Lineno: line,
|
||||
InApp: true,
|
||||
Module: "unknown",
|
||||
Function: fnName,
|
||||
}
|
||||
if fnName != "unknown" {
|
||||
// Extract the function/module details.
|
||||
frame.Module, frame.Function = functionName(fnName)
|
||||
}
|
||||
frames = append(frames, frame)
|
||||
}
|
||||
|
||||
if frames == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sentry wants the frames with the oldest first, so reverse them.
|
||||
for i, j := 0, len(frames)-1; i < j; i, j = i+1, j-1 {
|
||||
frames[i], frames[j] = frames[j], frames[i]
|
||||
}
|
||||
|
||||
return &ReportableStackTrace{Frames: frames}
|
||||
}
|
||||
|
||||
// parsePrintedStackEntry extracts the stack entry information
|
||||
// in lines at position i. It returns the new value of i if more than
|
||||
// one line was read.
|
||||
func parsePrintedStackEntry(
|
||||
lines []string, i int,
|
||||
) (newI int, file string, line int, fnName string) {
|
||||
// The function name is on the first line.
|
||||
fnName = lines[i]
|
||||
|
||||
// The file:line pair may be on the line after that.
|
||||
if i < len(lines)-1 && strings.HasPrefix(lines[i+1], "\t") {
|
||||
fileLine := strings.TrimSpace(lines[i+1])
|
||||
// Separate file path and line number.
|
||||
lineSep := strings.LastIndexByte(fileLine, ':')
|
||||
if lineSep == -1 {
|
||||
file = fileLine
|
||||
} else {
|
||||
file = fileLine[:lineSep]
|
||||
lineStr := fileLine[lineSep+1:]
|
||||
line, _ = strconv.Atoi(lineStr)
|
||||
}
|
||||
i++
|
||||
}
|
||||
return i, file, line, fnName
|
||||
}
|
||||
|
||||
var pkgFundamental errbase.TypeKey
|
||||
var pkgWithStackName errbase.TypeKey
|
||||
var ourWithStackName errbase.TypeKey
|
||||
|
||||
func init() {
|
||||
err := errors.New("")
|
||||
pkgFundamental = errbase.GetTypeKey(pkgErr.New(""))
|
||||
pkgWithStackName = errbase.GetTypeKey(pkgErr.WithStack(err))
|
||||
ourWithStackName = errbase.GetTypeKey(WithStack(err))
|
||||
}
|
||||
59
vendor/github.com/cockroachdb/errors/withstack/stack.go
generated
vendored
Normal file
59
vendor/github.com/cockroachdb/errors/withstack/stack.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 withstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
)
|
||||
|
||||
// stack represents a stack of program counters.
|
||||
// This mirrors the (non-exported) type of the same name in github.com/pkg/errors.
|
||||
type stack []uintptr
|
||||
|
||||
// Format mirrors the code in github.com/pkg/errors.
|
||||
func (s *stack) Format(st fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case st.Flag('+'):
|
||||
for _, pc := range *s {
|
||||
f := errbase.StackFrame(pc)
|
||||
fmt.Fprintf(st, "\n%+v", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StackTrace mirrors the code in github.com/pkg/errors.
|
||||
func (s *stack) StackTrace() errbase.StackTrace {
|
||||
f := make([]errbase.StackFrame, len(*s))
|
||||
for i := 0; i < len(f); i++ {
|
||||
f[i] = errbase.StackFrame((*s)[i])
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// callers mirrors the code in github.com/pkg/errors,
|
||||
// but makes the depth customizable.
|
||||
func callers(depth int) *stack {
|
||||
const numFrames = 32
|
||||
var pcs [numFrames]uintptr
|
||||
n := runtime.Callers(2+depth, pcs[:])
|
||||
var st stack = pcs[0:n]
|
||||
return &st
|
||||
}
|
||||
84
vendor/github.com/cockroachdb/errors/withstack/withstack.go
generated
vendored
Normal file
84
vendor/github.com/cockroachdb/errors/withstack/withstack.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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 withstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors/errbase"
|
||||
)
|
||||
|
||||
// This file mirrors the WithStack functionality from
|
||||
// github.com/pkg/errors. We would prefer to reuse the withStack
|
||||
// struct from that package directly (the library recognizes it well)
|
||||
// unfortunately github.com/pkg/errors does not enable client code to
|
||||
// customize the depth at which the stack trace is captured.
|
||||
|
||||
// WithStack annotates err with a stack trace at the point WithStack was called.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
// - when innermost stack capture, with `errors.GetOneLineSource()`.
|
||||
func WithStack(err error) error {
|
||||
// Skip the frame of WithStack itself, this mirrors the behavior
|
||||
// of WithStack() in github.com/pkg/errors.
|
||||
return WithStackDepth(err, 1)
|
||||
}
|
||||
|
||||
// WithStackDepth annotates err with a stack trace starting from the
|
||||
// given call depth. The value zero identifies the caller
|
||||
// of WithStackDepth itself.
|
||||
// See the documentation of WithStack() for more details.
|
||||
func WithStackDepth(err error, depth int) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withStack{cause: err, stack: callers(depth + 1)}
|
||||
}
|
||||
|
||||
type withStack struct {
|
||||
cause error
|
||||
|
||||
*stack
|
||||
}
|
||||
|
||||
var _ error = (*withStack)(nil)
|
||||
var _ fmt.Formatter = (*withStack)(nil)
|
||||
var _ errbase.SafeFormatter = (*withStack)(nil)
|
||||
var _ errbase.SafeDetailer = (*withStack)(nil)
|
||||
|
||||
func (w *withStack) Error() string { return w.cause.Error() }
|
||||
func (w *withStack) Cause() error { return w.cause }
|
||||
func (w *withStack) Unwrap() error { return w.cause }
|
||||
|
||||
// Format implements the fmt.Formatter interface.
|
||||
func (w *withStack) Format(s fmt.State, verb rune) { errbase.FormatError(w, s, verb) }
|
||||
|
||||
// SafeFormatError implements the errbase.SafeFormatter interface.
|
||||
func (w *withStack) SafeFormatError(p errbase.Printer) error {
|
||||
if p.Detail() {
|
||||
p.Printf("attached stack trace")
|
||||
}
|
||||
// We do not print the stack trace ourselves - errbase.FormatError()
|
||||
// does this for us.
|
||||
return w.cause
|
||||
}
|
||||
|
||||
// SafeDetails implements the errbase.SafeDetailer interface.
|
||||
func (w *withStack) SafeDetails() []string {
|
||||
return []string{fmt.Sprintf("%+v", w.StackTrace())}
|
||||
}
|
||||
68
vendor/github.com/cockroachdb/errors/withstack_api.go
generated
vendored
Normal file
68
vendor/github.com/cockroachdb/errors/withstack_api.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2019 The Cockroach Authors.
|
||||
//
|
||||
// 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
|
||||
|
||||
import "github.com/cockroachdb/errors/withstack"
|
||||
|
||||
// This file mirrors the WithStack functionality from
|
||||
// github.com/pkg/errors. We would prefer to reuse the withStack
|
||||
// struct from that package directly (the library recognizes it well)
|
||||
// unfortunately github.com/pkg/errors does not enable client code to
|
||||
// customize the depth at which the stack trace is captured.
|
||||
|
||||
// WithStack annotates err with a stack trace at the point WithStack was called.
|
||||
//
|
||||
// Detail is shown:
|
||||
// - via `errors.GetSafeDetails()`
|
||||
// - when formatting with `%+v`.
|
||||
// - in Sentry reports.
|
||||
// - when innermost stack capture, with `errors.GetOneLineSource()`.
|
||||
func WithStack(err error) error { return withstack.WithStackDepth(err, 1) }
|
||||
|
||||
// WithStackDepth annotates err with a stack trace starting from the
|
||||
// given call depth. The value zero identifies the caller
|
||||
// of WithStackDepth itself.
|
||||
// See the documentation of WithStack() for more details.
|
||||
func WithStackDepth(err error, depth int) error { return withstack.WithStackDepth(err, depth+1) }
|
||||
|
||||
// ReportableStackTrace aliases the type of the same name in the sentry
|
||||
// package. This is used by SendReport().
|
||||
type ReportableStackTrace = withstack.ReportableStackTrace
|
||||
|
||||
// GetOneLineSource extracts the file/line/function information
|
||||
// of the topmost caller in the innermost recorded stack trace.
|
||||
// The filename is simplified to remove the path prefix.
|
||||
//
|
||||
// This is used e.g. to populate the "source" field in
|
||||
// PostgreSQL errors in CockroachDB.
|
||||
func GetOneLineSource(err error) (file string, line int, fn string, ok bool) {
|
||||
return withstack.GetOneLineSource(err)
|
||||
}
|
||||
|
||||
// GetReportableStackTrace extracts a stack trace embedded in the
|
||||
// given error in the format suitable for Sentry reporting.
|
||||
//
|
||||
// This supports:
|
||||
// - errors generated by github.com/pkg/errors (either generated
|
||||
// locally or after transfer through the network),
|
||||
// - errors generated with WithStack() in this package,
|
||||
// - any other error that implements a StackTrace() method
|
||||
// returning a StackTrace from github.com/pkg/errors.
|
||||
//
|
||||
// Note: Sentry wants the oldest call frame first, so
|
||||
// the entries are reversed in the result.
|
||||
func GetReportableStackTrace(err error) *ReportableStackTrace {
|
||||
return withstack.GetReportableStackTrace(err)
|
||||
}
|
||||
25
vendor/github.com/cockroachdb/fifo/.gitignore
generated
vendored
Normal file
25
vendor/github.com/cockroachdb/fifo/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# If you prefer the allow list template instead of the deny list, see community template:
|
||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||
#
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
go.work.sum
|
||||
|
||||
.idea/
|
||||
|
||||
201
vendor/github.com/cockroachdb/fifo/LICENSE
generated
vendored
Normal file
201
vendor/github.com/cockroachdb/fifo/LICENSE
generated
vendored
Normal 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 [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
3
vendor/github.com/cockroachdb/fifo/README.md
generated
vendored
Normal file
3
vendor/github.com/cockroachdb/fifo/README.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
DEPRECATED
|
||||
|
||||
Moved to [github.com/cockroachdb/crlib](https://github.com/cockroachdb/crlib/tree/main/fifo)
|
||||
21
vendor/github.com/cockroachdb/fifo/invariants_off.go
generated
vendored
Normal file
21
vendor/github.com/cockroachdb/fifo/invariants_off.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2024 The Cockroach Authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
//go:build !fifo_invariants
|
||||
|
||||
package fifo
|
||||
|
||||
// invariants is false if we were not built with the "fifo_invariants" build
|
||||
// tag.
|
||||
const invariants = false
|
||||
20
vendor/github.com/cockroachdb/fifo/invariants_on.go
generated
vendored
Normal file
20
vendor/github.com/cockroachdb/fifo/invariants_on.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2024 The Cockroach Authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
//go:build fifo_invariants
|
||||
|
||||
package fifo
|
||||
|
||||
// invariants is true if we were built with the "fifo_invariants" build tag.
|
||||
const invariants = true
|
||||
162
vendor/github.com/cockroachdb/fifo/queue.go
generated
vendored
Normal file
162
vendor/github.com/cockroachdb/fifo/queue.go
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright 2024 The Cockroach Authors.
|
||||
//
|
||||
// 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 fifo
|
||||
|
||||
import "sync"
|
||||
|
||||
// Queue implements an allocation efficient FIFO queue. It is not safe for
|
||||
// concurrent access.
|
||||
//
|
||||
// Note that the queue provides pointer access to the internal storage (via
|
||||
// PeekFront and PushBack) so it must be used with care. These pointers must not
|
||||
// be used once the respective element is popped out of the queue.
|
||||
//
|
||||
// -- Implementation --
|
||||
//
|
||||
// The queue is implemented as a linked list of nodes, where each node is a
|
||||
// small ring buffer. The nodes are allocated using a sync.Pool (a single pool
|
||||
// is created for any given type and is used for all queues of that type).
|
||||
type Queue[T any] struct {
|
||||
len int
|
||||
head, tail *queueNode[T]
|
||||
|
||||
pool *QueueBackingPool[T]
|
||||
}
|
||||
|
||||
// MakeQueue constructs a new Queue.
|
||||
//
|
||||
// The pool should be a singleton object initialized with MakeQueueBackingPool.
|
||||
// A single pool can and should be used by all queues of that type.
|
||||
func MakeQueue[T any](pool *QueueBackingPool[T]) Queue[T] {
|
||||
return Queue[T]{
|
||||
pool: pool,
|
||||
}
|
||||
}
|
||||
|
||||
// Len returns the current length of the queue.
|
||||
func (q *Queue[T]) Len() int {
|
||||
return q.len
|
||||
}
|
||||
|
||||
// PushBack adds t to the end of the queue.
|
||||
//
|
||||
// The returned pointer can be used to modify the element while it is in the
|
||||
// queue; it is valid until the element is removed from the queue.
|
||||
func (q *Queue[T]) PushBack(t T) *T {
|
||||
if q.head == nil {
|
||||
q.head = q.pool.get()
|
||||
q.tail = q.head
|
||||
} else if q.tail.IsFull() {
|
||||
newTail := q.pool.get()
|
||||
q.tail.next = newTail
|
||||
q.tail = newTail
|
||||
}
|
||||
q.len++
|
||||
return q.tail.PushBack(t)
|
||||
}
|
||||
|
||||
// PeekFront returns the current head of the queue, or nil if the queue is
|
||||
// empty.
|
||||
//
|
||||
// The result is only valid until the next call to PopFront.
|
||||
func (q *Queue[T]) PeekFront() *T {
|
||||
if q.len == 0 {
|
||||
return nil
|
||||
}
|
||||
return q.head.PeekFront()
|
||||
}
|
||||
|
||||
// PopFront removes the current head of the queue.
|
||||
//
|
||||
// It is illegal to call PopFront on an empty queue.
|
||||
func (q *Queue[T]) PopFront() {
|
||||
q.head.PopFront()
|
||||
// If this is the only node, we don't want to release it; otherwise we would
|
||||
// allocate/free a node every time we transition between the queue being empty
|
||||
// and non-empty.
|
||||
if q.head.len == 0 && q.head.next != nil {
|
||||
oldHead := q.head
|
||||
q.head = oldHead.next
|
||||
q.pool.put(oldHead)
|
||||
}
|
||||
q.len--
|
||||
}
|
||||
|
||||
// QueueBackingPool is a sync.Pool that used to allocate internal nodes
|
||||
// for Queue[T].
|
||||
type QueueBackingPool[T any] struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
|
||||
// MakeQueueBackingPool makes a queue backing pool. It is intented to be used to
|
||||
// initialize a singleton (global) variable. A single pool can and should be
|
||||
// used by all queues of that type.
|
||||
func MakeQueueBackingPool[T any]() QueueBackingPool[T] {
|
||||
return QueueBackingPool[T]{
|
||||
pool: sync.Pool{
|
||||
New: func() interface{} { return &queueNode[T]{} },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (qp *QueueBackingPool[T]) get() *queueNode[T] {
|
||||
return qp.pool.Get().(*queueNode[T])
|
||||
}
|
||||
|
||||
func (qp *QueueBackingPool[T]) put(n *queueNode[T]) {
|
||||
*n = queueNode[T]{}
|
||||
qp.pool.Put(n)
|
||||
}
|
||||
|
||||
// We batch the allocation of this many queue objects. The value was chosen
|
||||
// without experimentation - it provides a reasonable amount of amortization
|
||||
// without a very large increase in memory overhead if T is large.
|
||||
const queueNodeSize = 8
|
||||
|
||||
type queueNode[T any] struct {
|
||||
buf [queueNodeSize]T
|
||||
head, len int32
|
||||
next *queueNode[T]
|
||||
}
|
||||
|
||||
func (qn *queueNode[T]) IsFull() bool {
|
||||
return qn.len == queueNodeSize
|
||||
}
|
||||
|
||||
func (qn *queueNode[T]) PushBack(t T) *T {
|
||||
if invariants && qn.len >= queueNodeSize {
|
||||
panic("cannot push back into a full node")
|
||||
}
|
||||
i := (qn.head + qn.len) % queueNodeSize
|
||||
qn.buf[i] = t
|
||||
qn.len++
|
||||
return &qn.buf[i]
|
||||
}
|
||||
|
||||
func (qn *queueNode[T]) PeekFront() *T {
|
||||
return &qn.buf[qn.head]
|
||||
}
|
||||
|
||||
func (qn *queueNode[T]) PopFront() T {
|
||||
if invariants && qn.len == 0 {
|
||||
panic("cannot pop from empty queue")
|
||||
}
|
||||
t := qn.buf[qn.head]
|
||||
var zero T
|
||||
qn.buf[qn.head] = zero
|
||||
qn.head = (qn.head + 1) % queueNodeSize
|
||||
qn.len--
|
||||
return t
|
||||
}
|
||||
239
vendor/github.com/cockroachdb/fifo/semaphore.go
generated
vendored
Normal file
239
vendor/github.com/cockroachdb/fifo/semaphore.go
generated
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
// Copyright 2024 The Cockroach Authors.
|
||||
//
|
||||
// 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 fifo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Semaphore implements a weighted, dynamically reconfigurable semaphore which
|
||||
// respects context cancellation.
|
||||
//
|
||||
// The semaphore implements a FIFO policy, where Acquire requests are satisfied
|
||||
// in order. This policy provides fairness and prevents starvation but is
|
||||
// susceptible to head-of-line blocking, where a large request that can't be
|
||||
// satisfied blocks many other small requests that could be.
|
||||
type Semaphore struct {
|
||||
mu struct {
|
||||
sync.Mutex
|
||||
|
||||
capacity int64
|
||||
// outstanding can exceed capacity if the capacity is dynamically decreased.
|
||||
outstanding int64
|
||||
|
||||
waiters Queue[semaWaiter]
|
||||
|
||||
// numCanceled is the number of waiters in the waiters queue which have been
|
||||
// canceled. It is used to determine the current number of active waiters in
|
||||
// the queue which is waiters.Len() minus this value.
|
||||
numCanceled int
|
||||
|
||||
// numHadToWait accumulates the total number of Acquire requests which had
|
||||
// to wait because the semaphore was exhausted.
|
||||
numHadToWait int64
|
||||
}
|
||||
}
|
||||
|
||||
// NewSemaphore creates a new semaphore with the given capacity.
|
||||
func NewSemaphore(capacity int64) *Semaphore {
|
||||
if capacity <= 0 {
|
||||
panic("invalid capacity")
|
||||
}
|
||||
s := &Semaphore{}
|
||||
s.mu.capacity = capacity
|
||||
s.mu.waiters = MakeQueue[semaWaiter](&semaQueuePool)
|
||||
return s
|
||||
}
|
||||
|
||||
var semaQueuePool = MakeQueueBackingPool[semaWaiter]()
|
||||
|
||||
var ErrRequestExceedsCapacity = errors.New("request exceeds semaphore capacity")
|
||||
|
||||
// TryAcquire attempts to acquire n units from the semaphore without waiting. On
|
||||
// success, returns true and the caller must later Release the units.
|
||||
func (s *Semaphore) TryAcquire(n int64) bool {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if s.numWaitersLocked() == 0 && s.mu.outstanding+n <= s.mu.capacity {
|
||||
s.mu.outstanding += n
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Acquire n units from the semaphore, waiting if necessary.
|
||||
//
|
||||
// If the context is canceled while we are waiting, returns the context error.
|
||||
// If n exceeds the current capacity, returns ErrRequestExceedsCapacity.
|
||||
// On success, the caller must later Release the units.
|
||||
func (s *Semaphore) Acquire(ctx context.Context, n int64) error {
|
||||
s.mu.Lock()
|
||||
|
||||
// Fast path.
|
||||
if s.numWaitersLocked() == 0 && s.mu.outstanding+n <= s.mu.capacity {
|
||||
s.mu.outstanding += n
|
||||
s.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
if n > s.mu.capacity {
|
||||
s.mu.Unlock()
|
||||
return ErrRequestExceedsCapacity
|
||||
}
|
||||
|
||||
c := chanSyncPool.Get().(chan error)
|
||||
defer chanSyncPool.Put(c)
|
||||
w := s.mu.waiters.PushBack(semaWaiter{n: n, c: c})
|
||||
s.mu.numHadToWait++
|
||||
s.mu.Unlock()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
// We need to check if we raced with a channel notify (which happens under
|
||||
// the lock).
|
||||
select {
|
||||
case err := <-c:
|
||||
// We actually fulfilled or failed the request.
|
||||
return err
|
||||
default:
|
||||
}
|
||||
// Mark the request as canceled.
|
||||
w.c = nil
|
||||
s.mu.numCanceled++
|
||||
// If we are the head of the queue, we may be able to fulfill other waiters.
|
||||
s.processWaitersLocked()
|
||||
return ctx.Err()
|
||||
|
||||
case err := <-c:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Release n units back. These must be units that were acquired by a previous
|
||||
// Acquire call. It is legal to split up or coalesce units when releasing.
|
||||
func (s *Semaphore) Release(n int64) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
s.mu.outstanding -= n
|
||||
if s.mu.outstanding < 0 {
|
||||
panic("releasing more than was acquired")
|
||||
}
|
||||
s.processWaitersLocked()
|
||||
}
|
||||
|
||||
// UpdateCapacity changes the capacity of the semaphore. If the new capacity is
|
||||
// smaller, the already outstanding acquisitions might exceed the new capacity
|
||||
// until they are released.
|
||||
//
|
||||
// If there are Acquire calls that are waiting which are requesting more than
|
||||
// the new capacity, they will error out with ErrRequestExceedsCapacity.
|
||||
func (s *Semaphore) UpdateCapacity(capacity int64) {
|
||||
if capacity <= 0 {
|
||||
panic("invalid capacity")
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.mu.capacity = capacity
|
||||
s.processWaitersLocked()
|
||||
}
|
||||
|
||||
// Stats returns the current state of the semaphore.
|
||||
func (s *Semaphore) Stats() SemaphoreStats {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return SemaphoreStats{
|
||||
Capacity: s.mu.capacity,
|
||||
Outstanding: s.mu.outstanding,
|
||||
NumHadToWait: s.mu.numHadToWait,
|
||||
}
|
||||
}
|
||||
|
||||
// SemaphoreStats contains information about the current state of the semaphore.
|
||||
type SemaphoreStats struct {
|
||||
// Capacity is the current capacity of the semaphore.
|
||||
Capacity int64
|
||||
// Outstanding is the number of units that have been acquired. Note that this
|
||||
// can exceed Capacity if the capacity was recently decreased.
|
||||
Outstanding int64
|
||||
// NumHadToWait is the total number of Acquire calls (since the semaphore was
|
||||
// created) that had to wait because the semaphore was exhausted. Useful for
|
||||
// cumulative metrics.
|
||||
NumHadToWait int64
|
||||
|
||||
// TODO(radu): consider keeping track of the total amount of time the
|
||||
// semaphore was exhausted (i.e. there were waiters queued).
|
||||
}
|
||||
|
||||
func (ss SemaphoreStats) String() string {
|
||||
return fmt.Sprintf("capacity: %d, outstanding: %d, num-had-to-wait: %d",
|
||||
ss.Capacity, ss.Outstanding, ss.NumHadToWait)
|
||||
}
|
||||
|
||||
type semaWaiter struct {
|
||||
// n is the amount that the waiter is trying to acquire.
|
||||
n int64
|
||||
// c is the channel on which Acquire is blocked. If the request is canceled,
|
||||
// it is set to nil.
|
||||
c chan error
|
||||
}
|
||||
|
||||
// numWaitersLocked returns how many requests (that have not been canceled) are
|
||||
// waiting in the queue.
|
||||
func (s *Semaphore) numWaitersLocked() int {
|
||||
return s.mu.waiters.Len() - s.mu.numCanceled
|
||||
}
|
||||
|
||||
// processWaitersLocked processes and notifies as many waiters from the head of
|
||||
// the queue as possible.
|
||||
func (s *Semaphore) processWaitersLocked() {
|
||||
for ; s.mu.waiters.Len() > 0; s.mu.waiters.PopFront() {
|
||||
switch w := s.mu.waiters.PeekFront(); {
|
||||
case w.c == nil:
|
||||
// Request was canceled, we can just clean it up.
|
||||
s.mu.numCanceled--
|
||||
if invariants && s.mu.numCanceled < 0 {
|
||||
panic("negative numCanceled")
|
||||
}
|
||||
|
||||
case s.mu.outstanding+w.n <= s.mu.capacity:
|
||||
// Request can be fulfilled.
|
||||
s.mu.outstanding += w.n
|
||||
w.c <- nil
|
||||
|
||||
case w.n > s.mu.capacity:
|
||||
// Request must be failed. This can happen if the capacity was decreased
|
||||
// while the element was queued.
|
||||
w.c <- ErrRequestExceedsCapacity
|
||||
|
||||
default:
|
||||
// Head of the queue needs to wait some more.
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// chanSyncPool is used to pool allocations of the channels used to notify
|
||||
// goroutines waiting in Acquire.
|
||||
var chanSyncPool = sync.Pool{
|
||||
New: func() interface{} { return make(chan error, 1) },
|
||||
}
|
||||
12
vendor/github.com/cockroachdb/logtags/.gitignore
generated
vendored
Normal file
12
vendor/github.com/cockroachdb/logtags/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
201
vendor/github.com/cockroachdb/logtags/LICENSE
generated
vendored
Normal file
201
vendor/github.com/cockroachdb/logtags/LICENSE
generated
vendored
Normal 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 [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
76
vendor/github.com/cockroachdb/logtags/README.md
generated
vendored
Normal file
76
vendor/github.com/cockroachdb/logtags/README.md
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
# logtags: key/value annotations for Go contexts
|
||||
|
||||
This package provides a way to attach key/value annotations
|
||||
to a Go `context.Context`.
|
||||
|
||||
This feature is used e.g. in CockroachDB to annotate contexts with
|
||||
user-facing details from the call stack, for use in logging output.
|
||||
|
||||
**How to use:**
|
||||
|
||||
- adding k/v data to a context:
|
||||
|
||||
```go
|
||||
func AddTag(ctx context.Context, key string, value interface{}) context.Context
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```go
|
||||
func foo(ctx context.Context) {
|
||||
ctx = logtags.AddTag(ctx, "foo", 123)
|
||||
bar(ctx)
|
||||
}
|
||||
```
|
||||
|
||||
- retrieving k/v data from a context:
|
||||
|
||||
```go
|
||||
func FromContext(ctx context.Context) *Buffer
|
||||
func (b *Buffer) Get() []Tag
|
||||
func (t *Tag) Key() string
|
||||
func (t *Tag) Value() interface{}
|
||||
```
|
||||
|
||||
**How it works:**
|
||||
|
||||
`logtags` stores the provided key/value pairs into an object of type
|
||||
`Buffer`, then uses Go's standard `context.WithValue` to attach the
|
||||
buffer.
|
||||
|
||||
An instance of `Buffer` inside a context is immutable. When adding a
|
||||
new k/v pair to a context that already carries a `Buffer`, a new one
|
||||
is created with all previous k/v pair, and the new k/v pair is added
|
||||
to that.
|
||||
|
||||
The `FromContext()` function retrieves the topmost (most recent)
|
||||
`Buffer`.
|
||||
|
||||
**Advanced uses:**
|
||||
|
||||
To add multiple k/v pairs in one go, without using quadratic space in
|
||||
`Buffer` instances:
|
||||
|
||||
1. manually instantiate a `Buffer`.
|
||||
2. use `func (*Buffer) Add(key string, value interface{})` to populate the buffer.
|
||||
3. use `func AddTags(ctx context.Context, tags *Buffer) context.Context` to embark
|
||||
all the k/v pairs at once.
|
||||
|
||||
To format all the contained k/v pairs in a `Buffer`, use its
|
||||
`String()` or `FormatToString(*strings.Builder)` methods:
|
||||
- when the `value` part is `nil`, only the key is displayed.
|
||||
- when the `value` part is non-nil, and the key is just one character
|
||||
long, the key and value are concatenated for display. This enables e.g.
|
||||
printing k=`"n"`, v=123 as `n123`.
|
||||
- otherwise, the key and value are printed with `=` as separator.
|
||||
|
||||
For example:
|
||||
|
||||
```go
|
||||
ctx = logtags.AddTag(ctx, "foo", 123)
|
||||
ctx = logtags.AddTag(ctx, "x", 456)
|
||||
ctx = logtags.AddTag(ctx, "bar", nil)
|
||||
fmt.Println(logtags.FromContext(ctx).String())
|
||||
// prints foo=123,x456,bar
|
||||
```
|
||||
|
||||
247
vendor/github.com/cockroachdb/logtags/buffer.go
generated
vendored
Normal file
247
vendor/github.com/cockroachdb/logtags/buffer.go
generated
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
// Copyright 2018 The Cockroach Authors.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License included
|
||||
// in the file licenses/BSL.txt and at www.mariadb.com/bsl11.
|
||||
//
|
||||
// Change Date: 2022-10-01
|
||||
//
|
||||
// On the date above, in accordance with the Business Source License, use
|
||||
// of this software will be governed by the Apache License, Version 2.0,
|
||||
// included in the file licenses/APL.txt and at
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
package logtags
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const staticSlots = 4
|
||||
|
||||
// Buffer is an immutable list of Tags.
|
||||
type Buffer struct {
|
||||
tags []Tag
|
||||
prealloc [staticSlots]Tag
|
||||
}
|
||||
|
||||
// SingleTagBuffer returns a Buffer with a single tag.
|
||||
func SingleTagBuffer(key string, value any) *Buffer {
|
||||
b := &Buffer{}
|
||||
b.init(1, 1)
|
||||
b.tags[0] = Tag{key: key, value: value}
|
||||
return b
|
||||
}
|
||||
|
||||
// BuildBuffer is used to build a *Buffer that contains an arbitrary number
|
||||
// of tags. Sample usage:
|
||||
//
|
||||
// bld := BuildBuffer()
|
||||
// bld.Add("a", 1)
|
||||
// bld.Add("b", 2)
|
||||
// buf := bld.Finish()
|
||||
//
|
||||
// It is equivalent to using SingleTagBuffer() followed by Buffer.Add() calls,
|
||||
// but avoids allocating each intermediate buffer.
|
||||
func BuildBuffer() BufferBuilder {
|
||||
bld := BufferBuilder{b: &Buffer{}}
|
||||
bld.b.init(0, 0)
|
||||
return bld
|
||||
}
|
||||
|
||||
// BufferBuilder is returned by BuildBuffer.
|
||||
type BufferBuilder struct {
|
||||
b *Buffer
|
||||
}
|
||||
|
||||
// Add a log tag to the buffer. If the key was added already, the value is
|
||||
// replaced.
|
||||
func (bld *BufferBuilder) Add(key string, value any) {
|
||||
bld.b.addOrReplace(key, value)
|
||||
}
|
||||
|
||||
// Finish returns the buffer with the tags that were added to the builder.
|
||||
func (bld *BufferBuilder) Finish() *Buffer {
|
||||
b := bld.b
|
||||
bld.b = nil
|
||||
return b
|
||||
}
|
||||
|
||||
// Get returns the tags, as a slice. This slice must not be modified.
|
||||
func (b *Buffer) Get() []Tag {
|
||||
return b.tags
|
||||
}
|
||||
|
||||
// GetTag returns the tag corresponding to the given key. If the tag doesn't
|
||||
// exist, the bool return value will be false.
|
||||
func (b *Buffer) GetTag(key string) (Tag, bool) {
|
||||
if b == nil {
|
||||
return Tag{}, false
|
||||
}
|
||||
for _, t := range b.tags {
|
||||
if t.Key() == key {
|
||||
return t, true
|
||||
}
|
||||
}
|
||||
return Tag{}, false
|
||||
}
|
||||
|
||||
// Add returns a new buffer with one more tag. If the tag has the same key as an
|
||||
// earlier tag, that tag is overwritten.
|
||||
// The receiver can be nil.
|
||||
func (b *Buffer) Add(key string, value any) *Buffer {
|
||||
if b == nil {
|
||||
return SingleTagBuffer(key, value)
|
||||
}
|
||||
res := &Buffer{}
|
||||
res.init(len(b.tags), len(b.tags)+1)
|
||||
copy(res.tags, b.tags)
|
||||
res.addOrReplace(key, value)
|
||||
return res
|
||||
}
|
||||
|
||||
// Remove returns a new Buffer with the tag with key `key` removed. If the tag
|
||||
// does not exist, the receiver is returned (unchanged). The bool return value
|
||||
// is true if the tag existed.
|
||||
func (b *Buffer) Remove(key string) (*Buffer, bool) {
|
||||
if b == nil {
|
||||
return nil, false
|
||||
}
|
||||
for i, t := range b.tags {
|
||||
if t.Key() == key {
|
||||
res := &Buffer{}
|
||||
res.init(len(b.tags)-1, 0 /* capacityHint */)
|
||||
copy(res.tags, b.tags[:i])
|
||||
copy(res.tags[i:], b.tags[i+1:])
|
||||
return res, true
|
||||
}
|
||||
}
|
||||
return b, false
|
||||
}
|
||||
|
||||
// Merge returns a new buffer which contains tags from the receiver, followed by
|
||||
// the tags from <other>.
|
||||
//
|
||||
// If both buffers have the same tag, the tag will appear only one time, with
|
||||
// the value it has in <other>. It can appear either in the place of the tag in
|
||||
// <b> or the tag in <other> (depending on which is deemed more efficient).
|
||||
//
|
||||
// The method can return <b> or <other> if the result is identical with one of
|
||||
// them.
|
||||
//
|
||||
// The receiver can be nil.
|
||||
func (b *Buffer) Merge(other *Buffer) *Buffer {
|
||||
if b == nil || len(b.tags) == 0 {
|
||||
return other
|
||||
}
|
||||
if other == nil || len(other.tags) == 0 {
|
||||
return b
|
||||
}
|
||||
|
||||
// Check for a common case where b's tags are a subsequence of the
|
||||
// other tags. In practice this happens when we start with an annotated
|
||||
// context and we annotate it again at a lower level (with more specific
|
||||
// information). Frequent examples seen in practice are when b has a node ID
|
||||
// tag and other has both a node and a store ID tag; and when b has a node ID
|
||||
// and store ID tag and other has node, store, and replica tags.
|
||||
if diff := len(other.tags) - len(b.tags); diff >= 0 {
|
||||
i, j := 0, 0
|
||||
for i < len(b.tags) && j-i <= diff {
|
||||
if b.tags[i].key == other.tags[j].key {
|
||||
i++
|
||||
}
|
||||
j++
|
||||
}
|
||||
if i == len(b.tags) {
|
||||
return other
|
||||
}
|
||||
}
|
||||
|
||||
// Another common case is when we aren't adding any new tags or values; find
|
||||
// and ignore the longest prefix of redundant tags.
|
||||
i := 0
|
||||
for ; i < len(other.tags); i++ {
|
||||
idx := b.find(other.tags[i].key)
|
||||
if idx == -1 || b.tags[idx].value != other.tags[i].value {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == len(other.tags) {
|
||||
return b
|
||||
}
|
||||
|
||||
res := &Buffer{}
|
||||
res.init(len(b.tags), len(b.tags)+len(other.tags)-i)
|
||||
copy(res.tags, b.tags)
|
||||
|
||||
for ; i < len(other.tags); i++ {
|
||||
res.addOrReplace(other.tags[i].key, other.tags[i].value)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// String returns a string representation of the tags.
|
||||
func (b *Buffer) String() string {
|
||||
var buf strings.Builder
|
||||
b.FormatToString(&buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// FormatToString emits the k/v pairs to a strings.Builder.
|
||||
// - the k/v pairs are separated by commas (& no spaces).
|
||||
// - if there is no value, only the key is printed.
|
||||
// - if there is a value, and the key is just 1 character long,
|
||||
// the key and the value are concatenated.
|
||||
// This supports e.g. printing k="n", v=123 as "n123".
|
||||
// - otherwise, it prints "k=v".
|
||||
func (b *Buffer) FormatToString(buf *strings.Builder) {
|
||||
comma := ""
|
||||
for _, t := range b.Get() {
|
||||
buf.WriteString(comma)
|
||||
buf.WriteString(t.Key())
|
||||
if v := t.Value(); v != nil && v != "" {
|
||||
if len(t.Key()) > 1 {
|
||||
buf.WriteByte('=')
|
||||
}
|
||||
fmt.Fprint(buf, v)
|
||||
}
|
||||
comma = ","
|
||||
}
|
||||
}
|
||||
|
||||
// init initializes b.tags to a slice of len `length` (filled with zero values).
|
||||
// The slice may have capacity capacityHint. If capacityHint is less than
|
||||
// length, it is ignored.
|
||||
func (b *Buffer) init(length, capacityHint int) {
|
||||
if length <= staticSlots {
|
||||
// Even if capacityHint is larger that staticSlots, we still want to try to
|
||||
// avoid the allocation (especially since tags frequently get deduplicated).
|
||||
b.tags = b.prealloc[:length]
|
||||
} else {
|
||||
if capacityHint < length {
|
||||
capacityHint = length
|
||||
}
|
||||
b.tags = make([]Tag, length, capacityHint)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Buffer) addOrReplace(key string, value any) {
|
||||
for i := range b.tags {
|
||||
if b.tags[i].key == key {
|
||||
b.tags[i].value = value
|
||||
return
|
||||
}
|
||||
}
|
||||
b.tags = append(b.tags, Tag{key: key, value: value})
|
||||
}
|
||||
|
||||
// find returns the position of the tag with the given key, or -1 if
|
||||
// it is not found.
|
||||
func (b *Buffer) find(key string) int {
|
||||
for i := range b.tags {
|
||||
if b.tags[i].key == key {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
87
vendor/github.com/cockroachdb/logtags/context.go
generated
vendored
Normal file
87
vendor/github.com/cockroachdb/logtags/context.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
// Copyright 2018 The Cockroach Authors.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License included
|
||||
// in the file licenses/BSL.txt and at www.mariadb.com/bsl11.
|
||||
//
|
||||
// Change Date: 2022-10-01
|
||||
//
|
||||
// On the date above, in accordance with the Business Source License, use
|
||||
// of this software will be governed by the Apache License, Version 2.0,
|
||||
// included in the file licenses/APL.txt and at
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
package logtags
|
||||
|
||||
import "context"
|
||||
|
||||
// contextLogTagsKey is an empty type for the handle associated with the log
|
||||
// tags (*Buffer) value (see context.Value).
|
||||
type contextLogTagsKey struct{}
|
||||
|
||||
// FromContext returns the tags stored in the context (by WithTags, AddTag, or
|
||||
// AddTags).
|
||||
func FromContext(ctx context.Context) *Buffer {
|
||||
if fromContextFn != nil {
|
||||
return fromContextFn(ctx)
|
||||
}
|
||||
val := ctx.Value(contextLogTagsKey{})
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
return val.(*Buffer)
|
||||
}
|
||||
|
||||
// WithTags returns a context with the given tags. Any existing tags are
|
||||
// ignored.
|
||||
func WithTags(ctx context.Context, tags *Buffer) context.Context {
|
||||
if withTagsFn != nil {
|
||||
return withTagsFn(ctx, tags)
|
||||
}
|
||||
return context.WithValue(ctx, contextLogTagsKey{}, tags)
|
||||
}
|
||||
|
||||
// AddTag returns a context that has the tags in the given context plus another
|
||||
// tag. Tags are deduplicated (see Buffer.AddTag).
|
||||
func AddTag(ctx context.Context, key string, value interface{}) context.Context {
|
||||
b := FromContext(ctx)
|
||||
return WithTags(ctx, b.Add(key, value))
|
||||
}
|
||||
|
||||
// RemoveTag returns a context that has the tags in the given context except the
|
||||
// tag with key `key`. If such a tag does not exist, the given context is
|
||||
// returned.
|
||||
func RemoveTag(ctx context.Context, key string) context.Context {
|
||||
b := FromContext(ctx)
|
||||
newB, ok := b.Remove(key)
|
||||
if !ok {
|
||||
return ctx
|
||||
}
|
||||
return WithTags(ctx, newB)
|
||||
}
|
||||
|
||||
// AddTags returns a context that has the tags in the given context plus another
|
||||
// set of tags. Tags are deduplicated (see Buffer.AddTags).
|
||||
func AddTags(ctx context.Context, tags *Buffer) context.Context {
|
||||
b := FromContext(ctx)
|
||||
newB := b.Merge(tags)
|
||||
if newB == b {
|
||||
return ctx
|
||||
}
|
||||
return WithTags(ctx, newB)
|
||||
}
|
||||
|
||||
// OverrideContextFuncs can be used to override the implementation of
|
||||
// FromContext and WithTags. This is useful if we have a more efficient
|
||||
// implementation of context-associated values.
|
||||
//
|
||||
// Must be called before WithTags or FromContext are called.
|
||||
func OverrideContextFuncs(
|
||||
fromContext func(ctx context.Context) *Buffer,
|
||||
withTags func(ctx context.Context, tags *Buffer) context.Context,
|
||||
) {
|
||||
fromContextFn = fromContext
|
||||
withTagsFn = withTags
|
||||
}
|
||||
|
||||
var fromContextFn func(ctx context.Context) *Buffer
|
||||
var withTagsFn func(ctx context.Context, tags *Buffer) context.Context
|
||||
47
vendor/github.com/cockroachdb/logtags/tag.go
generated
vendored
Normal file
47
vendor/github.com/cockroachdb/logtags/tag.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2018 The Cockroach Authors.
|
||||
//
|
||||
// Use of this software is governed by the Business Source License included
|
||||
// in the file licenses/BSL.txt and at www.mariadb.com/bsl11.
|
||||
//
|
||||
// Change Date: 2022-10-01
|
||||
//
|
||||
// On the date above, in accordance with the Business Source License, use
|
||||
// of this software will be governed by the Apache License, Version 2.0,
|
||||
// included in the file licenses/APL.txt and at
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
package logtags
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Tag is a log tag, which has a string key and an arbitrary value.
|
||||
// The value must support testing for equality. It can be nil.
|
||||
type Tag struct {
|
||||
key string
|
||||
value interface{}
|
||||
}
|
||||
|
||||
// Key returns the key.
|
||||
func (t *Tag) Key() string {
|
||||
return t.key
|
||||
}
|
||||
|
||||
// Value returns the value.
|
||||
func (t *Tag) Value() interface{} {
|
||||
return t.value
|
||||
}
|
||||
|
||||
// ValueStr returns the value as a string.
|
||||
func (t *Tag) ValueStr() string {
|
||||
if t.value == nil {
|
||||
return ""
|
||||
}
|
||||
switch v := t.value.(type) {
|
||||
case string:
|
||||
return v
|
||||
case fmt.Stringer:
|
||||
return v.String()
|
||||
default:
|
||||
return fmt.Sprint(t.value)
|
||||
}
|
||||
}
|
||||
10
vendor/github.com/cockroachdb/pebble/.editorconfig
generated
vendored
Normal file
10
vendor/github.com/cockroachdb/pebble/.editorconfig
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# See http://editorconfig.org
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
|
||||
# For non-go files, we indent with two spaces. In go files we indent
|
||||
# with tabs but still set indent_size to control the github web viewer.
|
||||
indent_size=2
|
||||
9
vendor/github.com/cockroachdb/pebble/.gitignore
generated
vendored
Normal file
9
vendor/github.com/cockroachdb/pebble/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# Github action artifacts.
|
||||
artifacts
|
||||
# Profiling artifacts.
|
||||
cpu.*.prof
|
||||
heap.prof
|
||||
mutex.prof
|
||||
coverprofile.out
|
||||
# Testing artifacts
|
||||
meta.*.test
|
||||
27
vendor/github.com/cockroachdb/pebble/LICENSE
generated
vendored
Normal file
27
vendor/github.com/cockroachdb/pebble/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2011 The LevelDB-Go Authors. 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 Google Inc. 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.
|
||||
131
vendor/github.com/cockroachdb/pebble/Makefile
generated
vendored
Normal file
131
vendor/github.com/cockroachdb/pebble/Makefile
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
GO := go
|
||||
PKG := ./...
|
||||
GOFLAGS :=
|
||||
STRESSFLAGS :=
|
||||
TAGS := invariants
|
||||
TESTS := .
|
||||
PREV_RELEASE := crl-release-23.1
|
||||
COVER_PROFILE := coverprofile.out
|
||||
|
||||
.PHONY: all
|
||||
all:
|
||||
@echo usage:
|
||||
@echo " make test"
|
||||
@echo " make testrace"
|
||||
@echo " make stress"
|
||||
@echo " make stressrace"
|
||||
@echo " make stressmeta"
|
||||
@echo " make crossversion-meta"
|
||||
@echo " make testcoverage"
|
||||
@echo " make mod-update"
|
||||
@echo " make generate"
|
||||
@echo " make generate-test-data"
|
||||
@echo " make clean"
|
||||
|
||||
override testflags :=
|
||||
.PHONY: test
|
||||
test:
|
||||
${GO} test -tags '$(TAGS)' ${testflags} -run ${TESTS} ${PKG}
|
||||
|
||||
.PHONY: testcoverage
|
||||
testcoverage:
|
||||
${GO} test -tags '$(TAGS)' ${testflags} -run ${TESTS} ${PKG} -coverprofile ${COVER_PROFILE}
|
||||
|
||||
.PHONY: testrace
|
||||
testrace: testflags += -race -timeout 20m
|
||||
testrace: test
|
||||
|
||||
testasan: testflags += -asan -timeout 20m
|
||||
testasan: test
|
||||
|
||||
testmsan: export CC=clang
|
||||
testmsan: testflags += -msan -timeout 20m
|
||||
testmsan: test
|
||||
|
||||
.PHONY: testobjiotracing
|
||||
testobjiotracing:
|
||||
${GO} test -tags '$(TAGS) pebble_obj_io_tracing' ${testflags} -run ${TESTS} ./objstorage/objstorageprovider/objiotracing
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
${GO} test -tags '$(TAGS)' ${testflags} -run ${TESTS} ./internal/lint
|
||||
|
||||
.PHONY: stress stressrace
|
||||
stressrace: testflags += -race
|
||||
stress stressrace: testflags += -exec 'stress ${STRESSFLAGS}' -timeout 0 -test.v
|
||||
stress stressrace: test
|
||||
|
||||
.PHONY: stressmeta
|
||||
stressmeta: override PKG = ./internal/metamorphic
|
||||
stressmeta: override STRESSFLAGS += -p 1
|
||||
stressmeta: override TESTS = TestMeta$$
|
||||
stressmeta: stress
|
||||
|
||||
.PHONY: crossversion-meta
|
||||
crossversion-meta:
|
||||
git checkout ${PREV_RELEASE}; \
|
||||
${GO} test -c ./internal/metamorphic -o './internal/metamorphic/crossversion/${PREV_RELEASE}.test'; \
|
||||
git checkout -; \
|
||||
${GO} test -c ./internal/metamorphic -o './internal/metamorphic/crossversion/head.test'; \
|
||||
${GO} test -tags '$(TAGS)' ${testflags} -v -run 'TestMetaCrossVersion' ./internal/metamorphic/crossversion --version '${PREV_RELEASE},${PREV_RELEASE},${PREV_RELEASE}.test' --version 'HEAD,HEAD,./head.test'
|
||||
|
||||
.PHONY: stress-crossversion
|
||||
stress-crossversion:
|
||||
STRESS=1 ./scripts/run-crossversion-meta.sh crl-release-21.2 crl-release-22.1 crl-release-22.2 crl-release-23.1 master
|
||||
|
||||
.PHONY: generate
|
||||
generate:
|
||||
${GO} generate ${PKG}
|
||||
|
||||
generate:
|
||||
|
||||
# Note that the output of generate-test-data is not deterministic. This should
|
||||
# only be run manually as needed.
|
||||
.PHONY: generate-test-data
|
||||
generate-test-data:
|
||||
${GO} run -tags make_incorrect_manifests ./tool/make_incorrect_manifests.go
|
||||
${GO} run -tags make_test_find_db ./tool/make_test_find_db.go
|
||||
${GO} run -tags make_test_sstables ./tool/make_test_sstables.go
|
||||
${GO} run -tags make_test_remotecat ./tool/make_test_remotecat.go
|
||||
|
||||
mod-update:
|
||||
${GO} get -u
|
||||
${GO} mod tidy
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(patsubst %,%.test,$(notdir $(shell go list ${PKG})))
|
||||
|
||||
git_dirty := $(shell git status -s)
|
||||
|
||||
.PHONY: git-clean-check
|
||||
git-clean-check:
|
||||
ifneq ($(git_dirty),)
|
||||
@echo "Git repository is dirty!"
|
||||
@false
|
||||
else
|
||||
@echo "Git repository is clean."
|
||||
endif
|
||||
|
||||
.PHONY: mod-tidy-check
|
||||
mod-tidy-check:
|
||||
ifneq ($(git_dirty),)
|
||||
$(error mod-tidy-check must be invoked on a clean repository)
|
||||
endif
|
||||
@${GO} mod tidy
|
||||
$(MAKE) git-clean-check
|
||||
|
||||
# TODO(radu): switch back to @latest once bogus doc changes are
|
||||
# addressed; see https://github.com/cockroachdb/crlfmt/pull/44
|
||||
.PHONY: format
|
||||
format:
|
||||
go install github.com/cockroachdb/crlfmt@44a36ec7 && crlfmt -w -tab 2 .
|
||||
|
||||
.PHONY: format-check
|
||||
format-check:
|
||||
ifneq ($(git_dirty),)
|
||||
$(error format-check must be invoked on a clean repository)
|
||||
endif
|
||||
$(MAKE) format
|
||||
git diff
|
||||
$(MAKE) git-clean-check
|
||||
225
vendor/github.com/cockroachdb/pebble/README.md
generated
vendored
Normal file
225
vendor/github.com/cockroachdb/pebble/README.md
generated
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
# Pebble [](https://github.com/cockroachdb/pebble/actions/workflows/ci.yaml) [](https://godoc.org/github.com/cockroachdb/pebble) <sup><sub><sub>[Coverage](https://storage.googleapis.com/crl-codecover-public/pebble/index.html)</sub></sub></sup>
|
||||
|
||||
#### [Nightly benchmarks](https://cockroachdb.github.io/pebble/)
|
||||
|
||||
Pebble is a LevelDB/RocksDB inspired key-value store focused on
|
||||
performance and internal usage by CockroachDB. Pebble inherits the
|
||||
RocksDB file formats and a few extensions such as range deletion
|
||||
tombstones, table-level bloom filters, and updates to the MANIFEST
|
||||
format.
|
||||
|
||||
Pebble intentionally does not aspire to include every feature in RocksDB and
|
||||
specifically targets the use case and feature set needed by CockroachDB:
|
||||
|
||||
* Block-based tables
|
||||
* Checkpoints
|
||||
* Indexed batches
|
||||
* Iterator options (lower/upper bound, table filter)
|
||||
* Level-based compaction
|
||||
* Manual compaction
|
||||
* Merge operator
|
||||
* Prefix bloom filters
|
||||
* Prefix iteration
|
||||
* Range deletion tombstones
|
||||
* Reverse iteration
|
||||
* SSTable ingestion
|
||||
* Single delete
|
||||
* Snapshots
|
||||
* Table-level bloom filters
|
||||
|
||||
RocksDB has a large number of features that are not implemented in
|
||||
Pebble:
|
||||
|
||||
* Backups
|
||||
* Column families
|
||||
* Delete files in range
|
||||
* FIFO compaction style
|
||||
* Forward iterator / tailing iterator
|
||||
* Hash table format
|
||||
* Memtable bloom filter
|
||||
* Persistent cache
|
||||
* Pin iterator key / value
|
||||
* Plain table format
|
||||
* SSTable ingest-behind
|
||||
* Sub-compactions
|
||||
* Transactions
|
||||
* Universal compaction style
|
||||
|
||||
***WARNING***: Pebble may silently corrupt data or behave incorrectly if
|
||||
used with a RocksDB database that uses a feature Pebble doesn't
|
||||
support. Caveat emptor!
|
||||
|
||||
## Production Ready
|
||||
|
||||
Pebble was introduced as an alternative storage engine to RocksDB in
|
||||
CockroachDB v20.1 (released May 2020) and was used in production
|
||||
successfully at that time. Pebble was made the default storage engine
|
||||
in CockroachDB v20.2 (released Nov 2020). Pebble is being used in
|
||||
production by users of CockroachDB at scale and is considered stable
|
||||
and production ready.
|
||||
|
||||
## Advantages
|
||||
|
||||
Pebble offers several improvements over RocksDB:
|
||||
|
||||
* Faster reverse iteration via backwards links in the memtable's
|
||||
skiplist.
|
||||
* Faster commit pipeline that achieves better concurrency.
|
||||
* Seamless merged iteration of indexed batches. The mutations in the
|
||||
batch conceptually occupy another memtable level.
|
||||
* L0 sublevels and flush splitting for concurrent compactions out of L0 and
|
||||
reduced read-amplification during heavy write load.
|
||||
* Faster LSM edits in LSMs with large numbers of sstables through use of a
|
||||
copy-on-write B-tree to hold file metadata.
|
||||
* Delete-only compactions that drop whole sstables that fall within the bounds
|
||||
of a range deletion.
|
||||
* Block-property collectors and filters that enable iterators to skip tables,
|
||||
index blocks and data blocks that are irrelevant, according to user-defined
|
||||
properties over key-value pairs.
|
||||
* Range keys API, allowing KV pairs defined over a range of keyspace with
|
||||
user-defined semantics and interleaved during iteration.
|
||||
* Smaller, more approachable code base.
|
||||
|
||||
See the [Pebble vs RocksDB: Implementation
|
||||
Differences](docs/rocksdb.md) doc for more details on implementation
|
||||
differences.
|
||||
|
||||
## RocksDB Compatibility
|
||||
|
||||
Pebble strives for forward compatibility with RocksDB 6.2.1 (the latest
|
||||
version of RocksDB used by CockroachDB). Forward compatibility means
|
||||
that a DB generated by RocksDB can be used by Pebble. Currently, Pebble
|
||||
provides bidirectional compatibility with RocksDB (a Pebble generated DB
|
||||
can be used by RocksDB) when using its FormatMostCompatible format. New
|
||||
functionality that is backwards incompatible is gated behind new format
|
||||
major versions. In general, Pebble only provides compatibility with the
|
||||
subset of functionality and configuration used by CockroachDB. The scope
|
||||
of RocksDB functionality and configuration is too large to adequately
|
||||
test and document all the incompatibilities. The list below contains
|
||||
known incompatibilities.
|
||||
|
||||
* Pebble's use of WAL recycling is only compatible with RocksDB's
|
||||
`kTolerateCorruptedTailRecords` WAL recovery mode. Older versions of
|
||||
RocksDB would automatically map incompatible WAL recovery modes to
|
||||
`kTolerateCorruptedTailRecords`. New versions of RocksDB will
|
||||
disable WAL recycling.
|
||||
* Column families. Pebble does not support column families, nor does
|
||||
it attempt to detect their usage when opening a DB that may contain
|
||||
them.
|
||||
* Hash table format. Pebble does not support the hash table sstable
|
||||
format.
|
||||
* Plain table format. Pebble does not support the plain table sstable
|
||||
format.
|
||||
* SSTable format version 3 and 4. Pebble does not support version 3
|
||||
and version 4 format sstables. The sstable format version is
|
||||
controlled by the `BlockBasedTableOptions::format_version` option.
|
||||
See [#97](https://github.com/cockroachdb/pebble/issues/97).
|
||||
|
||||
## Format major versions
|
||||
|
||||
Over time Pebble has introduced new physical file formats. Backwards
|
||||
incompatible changes are made through the introduction of 'format major
|
||||
versions'. By default, when Pebble opens a database, it defaults to
|
||||
`FormatMostCompatible`. This version is bi-directionally compatible with RocksDB
|
||||
6.2.1 (with the caveats described above).
|
||||
|
||||
To opt into new formats, a user may set `FormatMajorVersion` on the
|
||||
[`Options`](https://pkg.go.dev/github.com/cockroachdb/pebble#Options)
|
||||
supplied to
|
||||
[`Open`](https://pkg.go.dev/github.com/cockroachdb/pebble#Open), or
|
||||
upgrade the format major version at runtime using
|
||||
[`DB.RatchetFormatMajorVersion`](https://pkg.go.dev/github.com/cockroachdb/pebble#DB.RatchetFormatMajorVersion).
|
||||
Format major version upgrades are permanent; There is no option to
|
||||
return to an earlier format.
|
||||
|
||||
The table below outlines the history of format major versions:
|
||||
|
||||
| Name | Value | Migration |
|
||||
|------------------------------------|-------|------------|
|
||||
| FormatMostCompatible | 1 | No |
|
||||
| FormatVersioned | 3 | No |
|
||||
| FormatSetWithDelete | 4 | No |
|
||||
| FormatBlockPropertyCollector | 5 | No |
|
||||
| FormatSplitUserKeysMarked | 6 | Background |
|
||||
| FormatSplitUserKeysMarkedCompacted | 7 | Blocking |
|
||||
| FormatRangeKeys | 8 | No |
|
||||
| FormatMinTableFormatPebblev1 | 9 | No |
|
||||
| FormatPrePebblev1Marked | 10 | Background |
|
||||
| FormatSSTableValueBlocks | 12 | No |
|
||||
| FormatFlushableIngest | 13 | No |
|
||||
| FormatPrePebblev1MarkedCompacted | 14 | Blocking |
|
||||
| FormatDeleteSizedAndObsolete | 15 | No |
|
||||
| FormatVirtualSSTables | 16 | No |
|
||||
|
||||
Upgrading to a format major version with 'Background' in the migration
|
||||
column may trigger background activity to rewrite physical file
|
||||
formats, typically through compactions. Upgrading to a format major
|
||||
version with 'Blocking' in the migration column will block until a
|
||||
migration is complete. The database may continue to serve reads and
|
||||
writes if upgrading a live database through
|
||||
`RatchetFormatMajorVersion`, but the method call will not return until
|
||||
the migration is complete.
|
||||
|
||||
For reference, the table below lists the range of supported Pebble format major
|
||||
versions for CockroachDB releases.
|
||||
|
||||
| CockroachDB release | Earliest supported | Latest supported |
|
||||
|---------------------|------------------------------------|---------------------------|
|
||||
| 20.1 through 21.1 | FormatMostCompatible | FormatMostCompatible |
|
||||
| 21.2 | FormatMostCompatible | FormatSetWithDelete |
|
||||
| 21.2 | FormatMostCompatible | FormatSetWithDelete |
|
||||
| 22.1 | FormatMostCompatible | FormatSplitUserKeysMarked |
|
||||
| 22.2 | FormatMostCompatible | FormatPrePebblev1Marked |
|
||||
| 23.1 | FormatSplitUserKeysMarkedCompacted | FormatFlushableIngest |
|
||||
| 23.2 | FormatSplitUserKeysMarkedCompacted | FormatVirtualSSTables |
|
||||
|
||||
## Pedigree
|
||||
|
||||
Pebble is based on the incomplete Go version of LevelDB:
|
||||
|
||||
https://github.com/golang/leveldb
|
||||
|
||||
The Go version of LevelDB is based on the C++ original:
|
||||
|
||||
https://github.com/google/leveldb
|
||||
|
||||
Optimizations and inspiration were drawn from RocksDB:
|
||||
|
||||
https://github.com/facebook/rocksdb
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Example Code
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/cockroachdb/pebble"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db, err := pebble.Open("demo", &pebble.Options{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
key := []byte("hello")
|
||||
if err := db.Set(key, []byte("world"), pebble.Sync); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
value, closer, err := db.Get(key)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("%s %s\n", key, value)
|
||||
if err := closer.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := db.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
2293
vendor/github.com/cockroachdb/pebble/batch.go
generated
vendored
Normal file
2293
vendor/github.com/cockroachdb/pebble/batch.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
23
vendor/github.com/cockroachdb/pebble/cache.go
generated
vendored
Normal file
23
vendor/github.com/cockroachdb/pebble/cache.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use
|
||||
// of this source code is governed by a BSD-style license that can be found in
|
||||
// the LICENSE file.
|
||||
|
||||
package pebble
|
||||
|
||||
import "github.com/cockroachdb/pebble/internal/cache"
|
||||
|
||||
// Cache exports the cache.Cache type.
|
||||
type Cache = cache.Cache
|
||||
|
||||
// NewCache creates a new cache of the specified size. Memory for the cache is
|
||||
// allocated on demand, not during initialization. The cache is created with a
|
||||
// reference count of 1. Each DB it is associated with adds a reference, so the
|
||||
// creator of the cache should usually release their reference after the DB is
|
||||
// created.
|
||||
//
|
||||
// c := pebble.NewCache(...)
|
||||
// defer c.Unref()
|
||||
// d, err := pebble.Open(pebble.Options{Cache: c})
|
||||
func NewCache(size int64) *cache.Cache {
|
||||
return cache.New(size)
|
||||
}
|
||||
425
vendor/github.com/cockroachdb/pebble/checkpoint.go
generated
vendored
Normal file
425
vendor/github.com/cockroachdb/pebble/checkpoint.go
generated
vendored
Normal file
@@ -0,0 +1,425 @@
|
||||
// Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use
|
||||
// of this source code is governed by a BSD-style license that can be found in
|
||||
// the LICENSE file.
|
||||
|
||||
package pebble
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/cockroachdb/errors/oserror"
|
||||
"github.com/cockroachdb/pebble/internal/base"
|
||||
"github.com/cockroachdb/pebble/record"
|
||||
"github.com/cockroachdb/pebble/vfs"
|
||||
"github.com/cockroachdb/pebble/vfs/atomicfs"
|
||||
)
|
||||
|
||||
// checkpointOptions hold the optional parameters to construct checkpoint
|
||||
// snapshots.
|
||||
type checkpointOptions struct {
|
||||
// flushWAL set to true will force a flush and sync of the WAL prior to
|
||||
// checkpointing.
|
||||
flushWAL bool
|
||||
|
||||
// If set, any SSTs that don't overlap with these spans are excluded from a checkpoint.
|
||||
restrictToSpans []CheckpointSpan
|
||||
}
|
||||
|
||||
// CheckpointOption set optional parameters used by `DB.Checkpoint`.
|
||||
type CheckpointOption func(*checkpointOptions)
|
||||
|
||||
// WithFlushedWAL enables flushing and syncing the WAL prior to constructing a
|
||||
// checkpoint. This guarantees that any writes committed before calling
|
||||
// DB.Checkpoint will be part of that checkpoint.
|
||||
//
|
||||
// Note that this setting can only be useful in cases when some writes are
|
||||
// performed with Sync = false. Otherwise, the guarantee will already be met.
|
||||
//
|
||||
// Passing this option is functionally equivalent to calling
|
||||
// DB.LogData(nil, Sync) right before DB.Checkpoint.
|
||||
func WithFlushedWAL() CheckpointOption {
|
||||
return func(opt *checkpointOptions) {
|
||||
opt.flushWAL = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithRestrictToSpans specifies spans of interest for the checkpoint. Any SSTs
|
||||
// that don't overlap with any of these spans are excluded from the checkpoint.
|
||||
//
|
||||
// Note that the checkpoint can still surface keys outside of these spans (from
|
||||
// the WAL and from SSTs that partially overlap with these spans). Moreover,
|
||||
// these surface keys aren't necessarily "valid" in that they could have been
|
||||
// modified but the SST containing the modification is excluded.
|
||||
func WithRestrictToSpans(spans []CheckpointSpan) CheckpointOption {
|
||||
return func(opt *checkpointOptions) {
|
||||
opt.restrictToSpans = spans
|
||||
}
|
||||
}
|
||||
|
||||
// CheckpointSpan is a key range [Start, End) (inclusive on Start, exclusive on
|
||||
// End) of interest for a checkpoint.
|
||||
type CheckpointSpan struct {
|
||||
Start []byte
|
||||
End []byte
|
||||
}
|
||||
|
||||
// excludeFromCheckpoint returns true if an SST file should be excluded from the
|
||||
// checkpoint because it does not overlap with the spans of interest
|
||||
// (opt.restrictToSpans).
|
||||
func excludeFromCheckpoint(f *fileMetadata, opt *checkpointOptions, cmp Compare) bool {
|
||||
if len(opt.restrictToSpans) == 0 {
|
||||
// Option not set; don't exclude anything.
|
||||
return false
|
||||
}
|
||||
for _, s := range opt.restrictToSpans {
|
||||
if f.Overlaps(cmp, s.Start, s.End, true /* exclusiveEnd */) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// None of the restrictToSpans overlapped; we can exclude this file.
|
||||
return true
|
||||
}
|
||||
|
||||
// mkdirAllAndSyncParents creates destDir and any of its missing parents.
|
||||
// Those missing parents, as well as the closest existing ancestor, are synced.
|
||||
// Returns a handle to the directory created at destDir.
|
||||
func mkdirAllAndSyncParents(fs vfs.FS, destDir string) (vfs.File, error) {
|
||||
// Collect paths for all directories between destDir (excluded) and its
|
||||
// closest existing ancestor (included).
|
||||
var parentPaths []string
|
||||
for parentPath := fs.PathDir(destDir); ; parentPath = fs.PathDir(parentPath) {
|
||||
parentPaths = append(parentPaths, parentPath)
|
||||
if fs.PathDir(parentPath) == parentPath {
|
||||
break
|
||||
}
|
||||
_, err := fs.Stat(parentPath)
|
||||
if err == nil {
|
||||
// Exit loop at the closest existing ancestor.
|
||||
break
|
||||
}
|
||||
if !oserror.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Create destDir and any of its missing parents.
|
||||
if err := fs.MkdirAll(destDir, 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Sync all the parent directories up to the closest existing ancestor,
|
||||
// included.
|
||||
for _, parentPath := range parentPaths {
|
||||
parentDir, err := fs.OpenDir(parentPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = parentDir.Sync()
|
||||
if err != nil {
|
||||
_ = parentDir.Close()
|
||||
return nil, err
|
||||
}
|
||||
err = parentDir.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return fs.OpenDir(destDir)
|
||||
}
|
||||
|
||||
// Checkpoint constructs a snapshot of the DB instance in the specified
|
||||
// directory. The WAL, MANIFEST, OPTIONS, and sstables will be copied into the
|
||||
// snapshot. Hard links will be used when possible. Beware of the significant
|
||||
// space overhead for a checkpoint if hard links are disabled. Also beware that
|
||||
// even if hard links are used, the space overhead for the checkpoint will
|
||||
// increase over time as the DB performs compactions.
|
||||
func (d *DB) Checkpoint(
|
||||
destDir string, opts ...CheckpointOption,
|
||||
) (
|
||||
ckErr error, /* used in deferred cleanup */
|
||||
) {
|
||||
opt := &checkpointOptions{}
|
||||
for _, fn := range opts {
|
||||
fn(opt)
|
||||
}
|
||||
|
||||
if _, err := d.opts.FS.Stat(destDir); !oserror.IsNotExist(err) {
|
||||
if err == nil {
|
||||
return &os.PathError{
|
||||
Op: "checkpoint",
|
||||
Path: destDir,
|
||||
Err: oserror.ErrExist,
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if opt.flushWAL && !d.opts.DisableWAL {
|
||||
// Write an empty log-data record to flush and sync the WAL.
|
||||
if err := d.LogData(nil /* data */, Sync); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Disable file deletions.
|
||||
d.mu.Lock()
|
||||
d.disableFileDeletions()
|
||||
defer func() {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
d.enableFileDeletions()
|
||||
}()
|
||||
|
||||
// TODO(peter): RocksDB provides the option to roll the manifest if the
|
||||
// MANIFEST size is too large. Should we do this too?
|
||||
|
||||
// Lock the manifest before getting the current version. We need the
|
||||
// length of the manifest that we read to match the current version that
|
||||
// we read, otherwise we might copy a versionEdit not reflected in the
|
||||
// sstables we copy/link.
|
||||
d.mu.versions.logLock()
|
||||
// Get the unflushed log files, the current version, and the current manifest
|
||||
// file number.
|
||||
memQueue := d.mu.mem.queue
|
||||
current := d.mu.versions.currentVersion()
|
||||
formatVers := d.FormatMajorVersion()
|
||||
manifestFileNum := d.mu.versions.manifestFileNum
|
||||
manifestSize := d.mu.versions.manifest.Size()
|
||||
optionsFileNum := d.optionsFileNum
|
||||
virtualBackingFiles := make(map[base.DiskFileNum]struct{})
|
||||
for diskFileNum := range d.mu.versions.backingState.fileBackingMap {
|
||||
virtualBackingFiles[diskFileNum] = struct{}{}
|
||||
}
|
||||
// Release the manifest and DB.mu so we don't block other operations on
|
||||
// the database.
|
||||
d.mu.versions.logUnlock()
|
||||
d.mu.Unlock()
|
||||
|
||||
// Wrap the normal filesystem with one which wraps newly created files with
|
||||
// vfs.NewSyncingFile.
|
||||
fs := vfs.NewSyncingFS(d.opts.FS, vfs.SyncingFileOptions{
|
||||
NoSyncOnClose: d.opts.NoSyncOnClose,
|
||||
BytesPerSync: d.opts.BytesPerSync,
|
||||
})
|
||||
|
||||
// Create the dir and its parents (if necessary), and sync them.
|
||||
var dir vfs.File
|
||||
defer func() {
|
||||
if dir != nil {
|
||||
_ = dir.Close()
|
||||
}
|
||||
if ckErr != nil {
|
||||
// Attempt to cleanup on error.
|
||||
_ = fs.RemoveAll(destDir)
|
||||
}
|
||||
}()
|
||||
dir, ckErr = mkdirAllAndSyncParents(fs, destDir)
|
||||
if ckErr != nil {
|
||||
return ckErr
|
||||
}
|
||||
|
||||
{
|
||||
// Link or copy the OPTIONS.
|
||||
srcPath := base.MakeFilepath(fs, d.dirname, fileTypeOptions, optionsFileNum)
|
||||
destPath := fs.PathJoin(destDir, fs.PathBase(srcPath))
|
||||
ckErr = vfs.LinkOrCopy(fs, srcPath, destPath)
|
||||
if ckErr != nil {
|
||||
return ckErr
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Set the format major version in the destination directory.
|
||||
var versionMarker *atomicfs.Marker
|
||||
versionMarker, _, ckErr = atomicfs.LocateMarker(fs, destDir, formatVersionMarkerName)
|
||||
if ckErr != nil {
|
||||
return ckErr
|
||||
}
|
||||
|
||||
// We use the marker to encode the active format version in the
|
||||
// marker filename. Unlike other uses of the atomic marker,
|
||||
// there is no file with the filename `formatVers.String()` on
|
||||
// the filesystem.
|
||||
ckErr = versionMarker.Move(formatVers.String())
|
||||
if ckErr != nil {
|
||||
return ckErr
|
||||
}
|
||||
ckErr = versionMarker.Close()
|
||||
if ckErr != nil {
|
||||
return ckErr
|
||||
}
|
||||
}
|
||||
|
||||
var excludedFiles map[deletedFileEntry]*fileMetadata
|
||||
// Set of FileBacking.DiskFileNum which will be required by virtual sstables
|
||||
// in the checkpoint.
|
||||
requiredVirtualBackingFiles := make(map[base.DiskFileNum]struct{})
|
||||
// Link or copy the sstables.
|
||||
for l := range current.Levels {
|
||||
iter := current.Levels[l].Iter()
|
||||
for f := iter.First(); f != nil; f = iter.Next() {
|
||||
if excludeFromCheckpoint(f, opt, d.cmp) {
|
||||
if excludedFiles == nil {
|
||||
excludedFiles = make(map[deletedFileEntry]*fileMetadata)
|
||||
}
|
||||
excludedFiles[deletedFileEntry{
|
||||
Level: l,
|
||||
FileNum: f.FileNum,
|
||||
}] = f
|
||||
continue
|
||||
}
|
||||
|
||||
fileBacking := f.FileBacking
|
||||
if f.Virtual {
|
||||
if _, ok := requiredVirtualBackingFiles[fileBacking.DiskFileNum]; ok {
|
||||
continue
|
||||
}
|
||||
requiredVirtualBackingFiles[fileBacking.DiskFileNum] = struct{}{}
|
||||
}
|
||||
|
||||
srcPath := base.MakeFilepath(fs, d.dirname, fileTypeTable, fileBacking.DiskFileNum)
|
||||
destPath := fs.PathJoin(destDir, fs.PathBase(srcPath))
|
||||
ckErr = vfs.LinkOrCopy(fs, srcPath, destPath)
|
||||
if ckErr != nil {
|
||||
return ckErr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var removeBackingTables []base.DiskFileNum
|
||||
for diskFileNum := range virtualBackingFiles {
|
||||
if _, ok := requiredVirtualBackingFiles[diskFileNum]; !ok {
|
||||
// The backing sstable associated with fileNum is no longer
|
||||
// required.
|
||||
removeBackingTables = append(removeBackingTables, diskFileNum)
|
||||
}
|
||||
}
|
||||
|
||||
ckErr = d.writeCheckpointManifest(
|
||||
fs, formatVers, destDir, dir, manifestFileNum.DiskFileNum(), manifestSize,
|
||||
excludedFiles, removeBackingTables,
|
||||
)
|
||||
if ckErr != nil {
|
||||
return ckErr
|
||||
}
|
||||
|
||||
// Copy the WAL files. We copy rather than link because WAL file recycling
|
||||
// will cause the WAL files to be reused which would invalidate the
|
||||
// checkpoint.
|
||||
for i := range memQueue {
|
||||
logNum := memQueue[i].logNum
|
||||
if logNum == 0 {
|
||||
continue
|
||||
}
|
||||
srcPath := base.MakeFilepath(fs, d.walDirname, fileTypeLog, logNum.DiskFileNum())
|
||||
destPath := fs.PathJoin(destDir, fs.PathBase(srcPath))
|
||||
ckErr = vfs.Copy(fs, srcPath, destPath)
|
||||
if ckErr != nil {
|
||||
return ckErr
|
||||
}
|
||||
}
|
||||
|
||||
// Sync and close the checkpoint directory.
|
||||
ckErr = dir.Sync()
|
||||
if ckErr != nil {
|
||||
return ckErr
|
||||
}
|
||||
ckErr = dir.Close()
|
||||
dir = nil
|
||||
return ckErr
|
||||
}
|
||||
|
||||
func (d *DB) writeCheckpointManifest(
|
||||
fs vfs.FS,
|
||||
formatVers FormatMajorVersion,
|
||||
destDirPath string,
|
||||
destDir vfs.File,
|
||||
manifestFileNum base.DiskFileNum,
|
||||
manifestSize int64,
|
||||
excludedFiles map[deletedFileEntry]*fileMetadata,
|
||||
removeBackingTables []base.DiskFileNum,
|
||||
) error {
|
||||
// Copy the MANIFEST, and create a pointer to it. We copy rather
|
||||
// than link because additional version edits added to the
|
||||
// MANIFEST after we took our snapshot of the sstables will
|
||||
// reference sstables that aren't in our checkpoint. For a
|
||||
// similar reason, we need to limit how much of the MANIFEST we
|
||||
// copy.
|
||||
// If some files are excluded from the checkpoint, also append a block that
|
||||
// records those files as deleted.
|
||||
if err := func() error {
|
||||
srcPath := base.MakeFilepath(fs, d.dirname, fileTypeManifest, manifestFileNum)
|
||||
destPath := fs.PathJoin(destDirPath, fs.PathBase(srcPath))
|
||||
src, err := fs.Open(srcPath, vfs.SequentialReadsOption)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
dst, err := fs.Create(destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dst.Close()
|
||||
|
||||
// Copy all existing records. We need to copy at the record level in case we
|
||||
// need to append another record with the excluded files (we cannot simply
|
||||
// append a record after a raw data copy; see
|
||||
// https://github.com/cockroachdb/cockroach/issues/100935).
|
||||
r := record.NewReader(&io.LimitedReader{R: src, N: manifestSize}, manifestFileNum.FileNum())
|
||||
w := record.NewWriter(dst)
|
||||
for {
|
||||
rr, err := r.Next()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
rw, err := w.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(rw, rr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(excludedFiles) > 0 {
|
||||
// Write out an additional VersionEdit that deletes the excluded SST files.
|
||||
ve := versionEdit{
|
||||
DeletedFiles: excludedFiles,
|
||||
RemovedBackingTables: removeBackingTables,
|
||||
}
|
||||
|
||||
rw, err := w.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ve.Encode(rw); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return dst.Sync()
|
||||
}(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Recent format versions use an atomic marker for setting the
|
||||
// active manifest. Older versions use the CURRENT file. The
|
||||
// setCurrentFunc function will return a closure that will
|
||||
// take the appropriate action for the database's format
|
||||
// version.
|
||||
var manifestMarker *atomicfs.Marker
|
||||
manifestMarker, _, err := atomicfs.LocateMarker(fs, destDirPath, manifestMarkerName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setCurrentFunc(formatVers, manifestMarker, fs, destDirPath, destDir)(manifestFileNum.FileNum()); err != nil {
|
||||
return err
|
||||
}
|
||||
return manifestMarker.Close()
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user