mirror of
https://github.com/ipfs/kubo.git
synced 2025-05-21 00:47:22 +08:00
feat: add basic gateway tracing (#8595)
* add deprecation warning when tracer plugins are loaded * add response format attribute to span in gateway handler * add note about tracing's experimental status in godoc * add nil check for TTL when adding name span attrs * add basic sharness test for integration with otel collector * add nil check in UnixFSAPI.processLink * test: sharness check all json objs for swarm span * add env var docs to docs/environment-variables.md * chore: pin the otel collector version * add tracing spans per response type (#8841) * docs: tracing with jaeger-ui Co-authored-by: Marcin Rataj <lidel@lidel.org>
This commit is contained in:
@ -20,6 +20,8 @@ import (
|
|||||||
loader "github.com/ipfs/go-ipfs/plugin/loader"
|
loader "github.com/ipfs/go-ipfs/plugin/loader"
|
||||||
repo "github.com/ipfs/go-ipfs/repo"
|
repo "github.com/ipfs/go-ipfs/repo"
|
||||||
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
|
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
|
||||||
cmds "github.com/ipfs/go-ipfs-cmds"
|
cmds "github.com/ipfs/go-ipfs-cmds"
|
||||||
"github.com/ipfs/go-ipfs-cmds/cli"
|
"github.com/ipfs/go-ipfs-cmds/cli"
|
||||||
@ -70,21 +72,30 @@ func main() {
|
|||||||
os.Exit(mainRet())
|
os.Exit(mainRet())
|
||||||
}
|
}
|
||||||
|
|
||||||
func mainRet() int {
|
func printErr(err error) int {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func mainRet() (exitCode int) {
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
ctx := logging.ContextWithLoggable(context.Background(), loggables.Uuid("session"))
|
ctx := logging.ContextWithLoggable(context.Background(), loggables.Uuid("session"))
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// we'll call this local helper to output errors.
|
tp, err := tracing.NewTracerProvider(ctx)
|
||||||
// this is so we control how to print errors in one place.
|
if err != nil {
|
||||||
printErr := func(err error) {
|
return printErr(err)
|
||||||
fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
|
|
||||||
}
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := tp.Shutdown(ctx); err != nil {
|
||||||
|
exitCode = printErr(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
otel.SetTracerProvider(tp)
|
||||||
|
|
||||||
stopFunc, err := profileIfEnabled()
|
stopFunc, err := profileIfEnabled()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
printErr(err)
|
return printErr(err)
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
defer stopFunc() // to be executed as late as possible
|
defer stopFunc() // to be executed as late as possible
|
||||||
|
|
||||||
|
@ -13,8 +13,11 @@ import (
|
|||||||
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
||||||
caopts "github.com/ipfs/interface-go-ipfs-core/options"
|
caopts "github.com/ipfs/interface-go-ipfs-core/options"
|
||||||
path "github.com/ipfs/interface-go-ipfs-core/path"
|
path "github.com/ipfs/interface-go-ipfs-core/path"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
|
||||||
util "github.com/ipfs/go-ipfs/blocks/blockstoreutil"
|
util "github.com/ipfs/go-ipfs/blocks/blockstoreutil"
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BlockAPI CoreAPI
|
type BlockAPI CoreAPI
|
||||||
@ -25,6 +28,9 @@ type BlockStat struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.BlockPutOption) (coreiface.BlockStat, error) {
|
func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.BlockPutOption) (coreiface.BlockStat, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Put")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
settings, pref, err := caopts.BlockPutOptions(opts...)
|
settings, pref, err := caopts.BlockPutOptions(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -65,6 +71,8 @@ func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Bloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *BlockAPI) Get(ctx context.Context, p path.Path) (io.Reader, error) {
|
func (api *BlockAPI) Get(ctx context.Context, p path.Path) (io.Reader, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Get", trace.WithAttributes(attribute.String("path", p.String())))
|
||||||
|
defer span.End()
|
||||||
rp, err := api.core().ResolvePath(ctx, p)
|
rp, err := api.core().ResolvePath(ctx, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -79,6 +87,9 @@ func (api *BlockAPI) Get(ctx context.Context, p path.Path) (io.Reader, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *BlockAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.BlockRmOption) error {
|
func (api *BlockAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.BlockRmOption) error {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Rm", trace.WithAttributes(attribute.String("path", p.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
rp, err := api.core().ResolvePath(ctx, p)
|
rp, err := api.core().ResolvePath(ctx, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -119,6 +130,9 @@ func (api *BlockAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.BlockRm
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *BlockAPI) Stat(ctx context.Context, p path.Path) (coreiface.BlockStat, error) {
|
func (api *BlockAPI) Stat(ctx context.Context, p path.Path) (coreiface.BlockStat, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Stat", trace.WithAttributes(attribute.String("path", p.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
rp, err := api.core().ResolvePath(ctx, p)
|
rp, err := api.core().ResolvePath(ctx, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -5,8 +5,11 @@ import (
|
|||||||
|
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
pin "github.com/ipfs/go-ipfs-pinner"
|
pin "github.com/ipfs/go-ipfs-pinner"
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
ipld "github.com/ipfs/go-ipld-format"
|
ipld "github.com/ipfs/go-ipld-format"
|
||||||
dag "github.com/ipfs/go-merkledag"
|
dag "github.com/ipfs/go-merkledag"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
type dagAPI struct {
|
type dagAPI struct {
|
||||||
@ -18,6 +21,8 @@ type dagAPI struct {
|
|||||||
type pinningAdder CoreAPI
|
type pinningAdder CoreAPI
|
||||||
|
|
||||||
func (adder *pinningAdder) Add(ctx context.Context, nd ipld.Node) error {
|
func (adder *pinningAdder) Add(ctx context.Context, nd ipld.Node) error {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.PinningAdder", "Add", trace.WithAttributes(attribute.String("node", nd.String())))
|
||||||
|
defer span.End()
|
||||||
defer adder.blockstore.PinLock(ctx).Unlock(ctx)
|
defer adder.blockstore.PinLock(ctx).Unlock(ctx)
|
||||||
|
|
||||||
if err := adder.dag.Add(ctx, nd); err != nil {
|
if err := adder.dag.Add(ctx, nd); err != nil {
|
||||||
@ -30,6 +35,8 @@ func (adder *pinningAdder) Add(ctx context.Context, nd ipld.Node) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (adder *pinningAdder) AddMany(ctx context.Context, nds []ipld.Node) error {
|
func (adder *pinningAdder) AddMany(ctx context.Context, nds []ipld.Node) error {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.PinningAdder", "AddMany", trace.WithAttributes(attribute.Int("nodes.count", len(nds))))
|
||||||
|
defer span.End()
|
||||||
defer adder.blockstore.PinLock(ctx).Unlock(ctx)
|
defer adder.blockstore.PinLock(ctx).Unlock(ctx)
|
||||||
|
|
||||||
if err := adder.dag.AddMany(ctx, nds); err != nil {
|
if err := adder.dag.AddMany(ctx, nds); err != nil {
|
||||||
|
@ -9,17 +9,22 @@ import (
|
|||||||
cidutil "github.com/ipfs/go-cidutil"
|
cidutil "github.com/ipfs/go-cidutil"
|
||||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||||
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
dag "github.com/ipfs/go-merkledag"
|
dag "github.com/ipfs/go-merkledag"
|
||||||
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
||||||
caopts "github.com/ipfs/interface-go-ipfs-core/options"
|
caopts "github.com/ipfs/interface-go-ipfs-core/options"
|
||||||
path "github.com/ipfs/interface-go-ipfs-core/path"
|
path "github.com/ipfs/interface-go-ipfs-core/path"
|
||||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||||
routing "github.com/libp2p/go-libp2p-core/routing"
|
routing "github.com/libp2p/go-libp2p-core/routing"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DhtAPI CoreAPI
|
type DhtAPI CoreAPI
|
||||||
|
|
||||||
func (api *DhtAPI) FindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, error) {
|
func (api *DhtAPI) FindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.DhtAPI", "FindPeer", trace.WithAttributes(attribute.String("peer", p.String())))
|
||||||
|
defer span.End()
|
||||||
err := api.checkOnline(false)
|
err := api.checkOnline(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return peer.AddrInfo{}, err
|
return peer.AddrInfo{}, err
|
||||||
@ -34,10 +39,14 @@ func (api *DhtAPI) FindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *DhtAPI) FindProviders(ctx context.Context, p path.Path, opts ...caopts.DhtFindProvidersOption) (<-chan peer.AddrInfo, error) {
|
func (api *DhtAPI) FindProviders(ctx context.Context, p path.Path, opts ...caopts.DhtFindProvidersOption) (<-chan peer.AddrInfo, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.DhtAPI", "FindProviders", trace.WithAttributes(attribute.String("path", p.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
settings, err := caopts.DhtFindProvidersOptions(opts...)
|
settings, err := caopts.DhtFindProvidersOptions(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
span.SetAttributes(attribute.Int("numproviders", settings.NumProviders))
|
||||||
|
|
||||||
err = api.checkOnline(false)
|
err = api.checkOnline(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -59,10 +68,14 @@ func (api *DhtAPI) FindProviders(ctx context.Context, p path.Path, opts ...caopt
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *DhtAPI) Provide(ctx context.Context, path path.Path, opts ...caopts.DhtProvideOption) error {
|
func (api *DhtAPI) Provide(ctx context.Context, path path.Path, opts ...caopts.DhtProvideOption) error {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.DhtAPI", "Provide", trace.WithAttributes(attribute.String("path", path.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
settings, err := caopts.DhtProvideOptions(opts...)
|
settings, err := caopts.DhtProvideOptions(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
span.SetAttributes(attribute.Bool("recursive", settings.Recursive))
|
||||||
|
|
||||||
err = api.checkOnline(false)
|
err = api.checkOnline(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -7,12 +7,15 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
ipfspath "github.com/ipfs/go-path"
|
ipfspath "github.com/ipfs/go-path"
|
||||||
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
||||||
caopts "github.com/ipfs/interface-go-ipfs-core/options"
|
caopts "github.com/ipfs/interface-go-ipfs-core/options"
|
||||||
path "github.com/ipfs/interface-go-ipfs-core/path"
|
path "github.com/ipfs/interface-go-ipfs-core/path"
|
||||||
crypto "github.com/libp2p/go-libp2p-core/crypto"
|
crypto "github.com/libp2p/go-libp2p-core/crypto"
|
||||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
type KeyAPI CoreAPI
|
type KeyAPI CoreAPI
|
||||||
@ -40,6 +43,9 @@ func (k *key) ID() peer.ID {
|
|||||||
// Generate generates new key, stores it in the keystore under the specified
|
// Generate generates new key, stores it in the keystore under the specified
|
||||||
// name and returns a base58 encoded multihash of its public key.
|
// name and returns a base58 encoded multihash of its public key.
|
||||||
func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.KeyGenerateOption) (coreiface.Key, error) {
|
func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.KeyGenerateOption) (coreiface.Key, error) {
|
||||||
|
_, span := tracing.Span(ctx, "CoreAPI.KeyAPI", "Generate", trace.WithAttributes(attribute.String("name", name)))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
options, err := caopts.KeyGenerateOptions(opts...)
|
options, err := caopts.KeyGenerateOptions(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -97,6 +103,9 @@ func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.Key
|
|||||||
|
|
||||||
// List returns a list keys stored in keystore.
|
// List returns a list keys stored in keystore.
|
||||||
func (api *KeyAPI) List(ctx context.Context) ([]coreiface.Key, error) {
|
func (api *KeyAPI) List(ctx context.Context) ([]coreiface.Key, error) {
|
||||||
|
_, span := tracing.Span(ctx, "CoreAPI.KeyAPI", "List")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
keys, err := api.repo.Keystore().List()
|
keys, err := api.repo.Keystore().List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -128,10 +137,14 @@ func (api *KeyAPI) List(ctx context.Context) ([]coreiface.Key, error) {
|
|||||||
// Rename renames `oldName` to `newName`. Returns the key and whether another
|
// Rename renames `oldName` to `newName`. Returns the key and whether another
|
||||||
// key was overwritten, or an error.
|
// key was overwritten, or an error.
|
||||||
func (api *KeyAPI) Rename(ctx context.Context, oldName string, newName string, opts ...caopts.KeyRenameOption) (coreiface.Key, bool, error) {
|
func (api *KeyAPI) Rename(ctx context.Context, oldName string, newName string, opts ...caopts.KeyRenameOption) (coreiface.Key, bool, error) {
|
||||||
|
_, span := tracing.Span(ctx, "CoreAPI.KeyAPI", "Rename", trace.WithAttributes(attribute.String("oldname", oldName), attribute.String("newname", newName)))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
options, err := caopts.KeyRenameOptions(opts...)
|
options, err := caopts.KeyRenameOptions(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
span.SetAttributes(attribute.Bool("force", options.Force))
|
||||||
|
|
||||||
ks := api.repo.Keystore()
|
ks := api.repo.Keystore()
|
||||||
|
|
||||||
@ -187,6 +200,9 @@ func (api *KeyAPI) Rename(ctx context.Context, oldName string, newName string, o
|
|||||||
|
|
||||||
// Remove removes keys from keystore. Returns ipns path of the removed key.
|
// Remove removes keys from keystore. Returns ipns path of the removed key.
|
||||||
func (api *KeyAPI) Remove(ctx context.Context, name string) (coreiface.Key, error) {
|
func (api *KeyAPI) Remove(ctx context.Context, name string) (coreiface.Key, error) {
|
||||||
|
_, span := tracing.Span(ctx, "CoreAPI.KeyAPI", "Remove", trace.WithAttributes(attribute.String("name", name)))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
ks := api.repo.Keystore()
|
ks := api.repo.Keystore()
|
||||||
|
|
||||||
if name == "self" {
|
if name == "self" {
|
||||||
|
@ -6,8 +6,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ipfs/go-ipfs-keystore"
|
keystore "github.com/ipfs/go-ipfs-keystore"
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
"github.com/ipfs/go-namesys"
|
"github.com/ipfs/go-namesys"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
|
||||||
ipath "github.com/ipfs/go-path"
|
ipath "github.com/ipfs/go-path"
|
||||||
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
||||||
@ -36,6 +39,9 @@ func (e *ipnsEntry) Value() path.Path {
|
|||||||
|
|
||||||
// Publish announces new IPNS name and returns the new IPNS entry.
|
// Publish announces new IPNS name and returns the new IPNS entry.
|
||||||
func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.NamePublishOption) (coreiface.IpnsEntry, error) {
|
func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.NamePublishOption) (coreiface.IpnsEntry, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.NameAPI", "Publish", trace.WithAttributes(attribute.String("path", p.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
if err := api.checkPublishAllowed(); err != nil {
|
if err := api.checkPublishAllowed(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -44,6 +50,14 @@ func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.Nam
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
span.SetAttributes(
|
||||||
|
attribute.Bool("allowoffline", options.AllowOffline),
|
||||||
|
attribute.String("key", options.Key),
|
||||||
|
attribute.Float64("validtime", options.ValidTime.Seconds()),
|
||||||
|
)
|
||||||
|
if options.TTL != nil {
|
||||||
|
span.SetAttributes(attribute.Float64("ttl", options.TTL.Seconds()))
|
||||||
|
}
|
||||||
|
|
||||||
err = api.checkOnline(options.AllowOffline)
|
err = api.checkOnline(options.AllowOffline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -82,11 +96,16 @@ func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.Nam
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *NameAPI) Search(ctx context.Context, name string, opts ...caopts.NameResolveOption) (<-chan coreiface.IpnsResult, error) {
|
func (api *NameAPI) Search(ctx context.Context, name string, opts ...caopts.NameResolveOption) (<-chan coreiface.IpnsResult, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.NameAPI", "Search", trace.WithAttributes(attribute.String("name", name)))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
options, err := caopts.NameResolveOptions(opts...)
|
options, err := caopts.NameResolveOptions(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.SetAttributes(attribute.Bool("cache", options.Cache))
|
||||||
|
|
||||||
err = api.checkOnline(true)
|
err = api.checkOnline(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -124,6 +143,9 @@ func (api *NameAPI) Search(ctx context.Context, name string, opts ...caopts.Name
|
|||||||
// Resolve attempts to resolve the newest version of the specified name and
|
// Resolve attempts to resolve the newest version of the specified name and
|
||||||
// returns its path.
|
// returns its path.
|
||||||
func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.NameResolveOption) (path.Path, error) {
|
func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.NameResolveOption) (path.Path, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.NameAPI", "Resolve", trace.WithAttributes(attribute.String("name", name)))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
pin "github.com/ipfs/go-ipfs-pinner"
|
pin "github.com/ipfs/go-ipfs-pinner"
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
ipld "github.com/ipfs/go-ipld-format"
|
ipld "github.com/ipfs/go-ipld-format"
|
||||||
dag "github.com/ipfs/go-merkledag"
|
dag "github.com/ipfs/go-merkledag"
|
||||||
"github.com/ipfs/go-merkledag/dagutils"
|
"github.com/ipfs/go-merkledag/dagutils"
|
||||||
@ -20,6 +21,8 @@ import (
|
|||||||
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
||||||
caopts "github.com/ipfs/interface-go-ipfs-core/options"
|
caopts "github.com/ipfs/interface-go-ipfs-core/options"
|
||||||
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
const inputLimit = 2 << 20
|
const inputLimit = 2 << 20
|
||||||
@ -37,6 +40,9 @@ type Node struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *ObjectAPI) New(ctx context.Context, opts ...caopts.ObjectNewOption) (ipld.Node, error) {
|
func (api *ObjectAPI) New(ctx context.Context, opts ...caopts.ObjectNewOption) (ipld.Node, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "New")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
options, err := caopts.ObjectNewOptions(opts...)
|
options, err := caopts.ObjectNewOptions(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -60,10 +66,18 @@ func (api *ObjectAPI) New(ctx context.Context, opts ...caopts.ObjectNewOption) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.ObjectPutOption) (ipath.Resolved, error) {
|
func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.ObjectPutOption) (ipath.Resolved, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Put")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
options, err := caopts.ObjectPutOptions(opts...)
|
options, err := caopts.ObjectPutOptions(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
span.SetAttributes(
|
||||||
|
attribute.Bool("pin", options.Pin),
|
||||||
|
attribute.String("datatype", options.DataType),
|
||||||
|
attribute.String("inputenc", options.InputEnc),
|
||||||
|
)
|
||||||
|
|
||||||
data, err := ioutil.ReadAll(io.LimitReader(src, inputLimit+10))
|
data, err := ioutil.ReadAll(io.LimitReader(src, inputLimit+10))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -130,10 +144,15 @@ func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Obj
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *ObjectAPI) Get(ctx context.Context, path ipath.Path) (ipld.Node, error) {
|
func (api *ObjectAPI) Get(ctx context.Context, path ipath.Path) (ipld.Node, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Get", trace.WithAttributes(attribute.String("path", path.String())))
|
||||||
|
defer span.End()
|
||||||
return api.core().ResolveNode(ctx, path)
|
return api.core().ResolveNode(ctx, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ObjectAPI) Data(ctx context.Context, path ipath.Path) (io.Reader, error) {
|
func (api *ObjectAPI) Data(ctx context.Context, path ipath.Path) (io.Reader, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Data", trace.WithAttributes(attribute.String("path", path.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
nd, err := api.core().ResolveNode(ctx, path)
|
nd, err := api.core().ResolveNode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -148,6 +167,9 @@ func (api *ObjectAPI) Data(ctx context.Context, path ipath.Path) (io.Reader, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *ObjectAPI) Links(ctx context.Context, path ipath.Path) ([]*ipld.Link, error) {
|
func (api *ObjectAPI) Links(ctx context.Context, path ipath.Path) ([]*ipld.Link, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Links", trace.WithAttributes(attribute.String("path", path.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
nd, err := api.core().ResolveNode(ctx, path)
|
nd, err := api.core().ResolveNode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -163,6 +185,9 @@ func (api *ObjectAPI) Links(ctx context.Context, path ipath.Path) ([]*ipld.Link,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *ObjectAPI) Stat(ctx context.Context, path ipath.Path) (*coreiface.ObjectStat, error) {
|
func (api *ObjectAPI) Stat(ctx context.Context, path ipath.Path) (*coreiface.ObjectStat, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Stat", trace.WithAttributes(attribute.String("path", path.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
nd, err := api.core().ResolveNode(ctx, path)
|
nd, err := api.core().ResolveNode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -186,10 +211,18 @@ func (api *ObjectAPI) Stat(ctx context.Context, path ipath.Path) (*coreiface.Obj
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *ObjectAPI) AddLink(ctx context.Context, base ipath.Path, name string, child ipath.Path, opts ...caopts.ObjectAddLinkOption) (ipath.Resolved, error) {
|
func (api *ObjectAPI) AddLink(ctx context.Context, base ipath.Path, name string, child ipath.Path, opts ...caopts.ObjectAddLinkOption) (ipath.Resolved, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "AddLink", trace.WithAttributes(
|
||||||
|
attribute.String("base", base.String()),
|
||||||
|
attribute.String("name", name),
|
||||||
|
attribute.String("child", child.String()),
|
||||||
|
))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
options, err := caopts.ObjectAddLinkOptions(opts...)
|
options, err := caopts.ObjectAddLinkOptions(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
span.SetAttributes(attribute.Bool("create", options.Create))
|
||||||
|
|
||||||
baseNd, err := api.core().ResolveNode(ctx, base)
|
baseNd, err := api.core().ResolveNode(ctx, base)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -227,6 +260,12 @@ func (api *ObjectAPI) AddLink(ctx context.Context, base ipath.Path, name string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *ObjectAPI) RmLink(ctx context.Context, base ipath.Path, link string) (ipath.Resolved, error) {
|
func (api *ObjectAPI) RmLink(ctx context.Context, base ipath.Path, link string) (ipath.Resolved, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "RmLink", trace.WithAttributes(
|
||||||
|
attribute.String("base", base.String()),
|
||||||
|
attribute.String("link", link)),
|
||||||
|
)
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
baseNd, err := api.core().ResolveNode(ctx, base)
|
baseNd, err := api.core().ResolveNode(ctx, base)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -253,10 +292,16 @@ func (api *ObjectAPI) RmLink(ctx context.Context, base ipath.Path, link string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *ObjectAPI) AppendData(ctx context.Context, path ipath.Path, r io.Reader) (ipath.Resolved, error) {
|
func (api *ObjectAPI) AppendData(ctx context.Context, path ipath.Path, r io.Reader) (ipath.Resolved, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "AppendData", trace.WithAttributes(attribute.String("path", path.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
return api.patchData(ctx, path, r, true)
|
return api.patchData(ctx, path, r, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ObjectAPI) SetData(ctx context.Context, path ipath.Path, r io.Reader) (ipath.Resolved, error) {
|
func (api *ObjectAPI) SetData(ctx context.Context, path ipath.Path, r io.Reader) (ipath.Resolved, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "SetData", trace.WithAttributes(attribute.String("path", path.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
return api.patchData(ctx, path, r, false)
|
return api.patchData(ctx, path, r, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,6 +335,12 @@ func (api *ObjectAPI) patchData(ctx context.Context, path ipath.Path, r io.Reade
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *ObjectAPI) Diff(ctx context.Context, before ipath.Path, after ipath.Path) ([]coreiface.ObjectChange, error) {
|
func (api *ObjectAPI) Diff(ctx context.Context, before ipath.Path, after ipath.Path) ([]coreiface.ObjectChange, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Diff", trace.WithAttributes(
|
||||||
|
attribute.String("before", before.String()),
|
||||||
|
attribute.String("after", after.String()),
|
||||||
|
))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
beforeNd, err := api.core().ResolveNode(ctx, before)
|
beforeNd, err := api.core().ResolveNode(ctx, before)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -5,8 +5,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
gopath "path"
|
gopath "path"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
"github.com/ipfs/go-namesys/resolve"
|
"github.com/ipfs/go-namesys/resolve"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/ipfs/go-fetcher"
|
"github.com/ipfs/go-fetcher"
|
||||||
ipld "github.com/ipfs/go-ipld-format"
|
ipld "github.com/ipfs/go-ipld-format"
|
||||||
@ -19,6 +23,9 @@ import (
|
|||||||
// ResolveNode resolves the path `p` using Unixfs resolver, gets and returns the
|
// ResolveNode resolves the path `p` using Unixfs resolver, gets and returns the
|
||||||
// resolved Node.
|
// resolved Node.
|
||||||
func (api *CoreAPI) ResolveNode(ctx context.Context, p path.Path) (ipld.Node, error) {
|
func (api *CoreAPI) ResolveNode(ctx context.Context, p path.Path) (ipld.Node, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI", "ResolveNode", trace.WithAttributes(attribute.String("path", p.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
rp, err := api.ResolvePath(ctx, p)
|
rp, err := api.ResolvePath(ctx, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -34,6 +41,9 @@ func (api *CoreAPI) ResolveNode(ctx context.Context, p path.Path) (ipld.Node, er
|
|||||||
// ResolvePath resolves the path `p` using Unixfs resolver, returns the
|
// ResolvePath resolves the path `p` using Unixfs resolver, returns the
|
||||||
// resolved path.
|
// resolved path.
|
||||||
func (api *CoreAPI) ResolvePath(ctx context.Context, p path.Path) (path.Resolved, error) {
|
func (api *CoreAPI) ResolvePath(ctx context.Context, p path.Path) (path.Resolved, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI", "ResolvePath", trace.WithAttributes(attribute.String("path", p.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
if _, ok := p.(path.Resolved); ok {
|
if _, ok := p.(path.Resolved); ok {
|
||||||
return p.(path.Resolved), nil
|
return p.(path.Resolved), nil
|
||||||
}
|
}
|
||||||
|
@ -8,15 +8,21 @@ import (
|
|||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
||||||
pin "github.com/ipfs/go-ipfs-pinner"
|
pin "github.com/ipfs/go-ipfs-pinner"
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
"github.com/ipfs/go-merkledag"
|
"github.com/ipfs/go-merkledag"
|
||||||
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
||||||
caopts "github.com/ipfs/interface-go-ipfs-core/options"
|
caopts "github.com/ipfs/interface-go-ipfs-core/options"
|
||||||
"github.com/ipfs/interface-go-ipfs-core/path"
|
"github.com/ipfs/interface-go-ipfs-core/path"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PinAPI CoreAPI
|
type PinAPI CoreAPI
|
||||||
|
|
||||||
func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOption) error {
|
func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOption) error {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "Add", trace.WithAttributes(attribute.String("path", p.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
dagNode, err := api.core().ResolveNode(ctx, p)
|
dagNode, err := api.core().ResolveNode(ctx, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("pin: %s", err)
|
return fmt.Errorf("pin: %s", err)
|
||||||
@ -27,6 +33,8 @@ func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOp
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.SetAttributes(attribute.Bool("recursive", settings.Recursive))
|
||||||
|
|
||||||
defer api.blockstore.PinLock(ctx).Unlock(ctx)
|
defer api.blockstore.PinLock(ctx).Unlock(ctx)
|
||||||
|
|
||||||
err = api.pinning.Pin(ctx, dagNode, settings.Recursive)
|
err = api.pinning.Pin(ctx, dagNode, settings.Recursive)
|
||||||
@ -42,11 +50,16 @@ func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOp
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan coreiface.Pin, error) {
|
func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan coreiface.Pin, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "Ls")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
settings, err := caopts.PinLsOptions(opts...)
|
settings, err := caopts.PinLsOptions(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.SetAttributes(attribute.String("type", settings.Type))
|
||||||
|
|
||||||
switch settings.Type {
|
switch settings.Type {
|
||||||
case "all", "direct", "indirect", "recursive":
|
case "all", "direct", "indirect", "recursive":
|
||||||
default:
|
default:
|
||||||
@ -57,6 +70,9 @@ func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan c
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *PinAPI) IsPinned(ctx context.Context, p path.Path, opts ...caopts.PinIsPinnedOption) (string, bool, error) {
|
func (api *PinAPI) IsPinned(ctx context.Context, p path.Path, opts ...caopts.PinIsPinnedOption) (string, bool, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "IsPinned", trace.WithAttributes(attribute.String("path", p.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
resolved, err := api.core().ResolvePath(ctx, p)
|
resolved, err := api.core().ResolvePath(ctx, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", false, fmt.Errorf("error resolving path: %s", err)
|
return "", false, fmt.Errorf("error resolving path: %s", err)
|
||||||
@ -67,6 +83,8 @@ func (api *PinAPI) IsPinned(ctx context.Context, p path.Path, opts ...caopts.Pin
|
|||||||
return "", false, err
|
return "", false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.SetAttributes(attribute.String("withtype", settings.WithType))
|
||||||
|
|
||||||
mode, ok := pin.StringToMode(settings.WithType)
|
mode, ok := pin.StringToMode(settings.WithType)
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", false, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", settings.WithType)
|
return "", false, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", settings.WithType)
|
||||||
@ -77,6 +95,9 @@ func (api *PinAPI) IsPinned(ctx context.Context, p path.Path, opts ...caopts.Pin
|
|||||||
|
|
||||||
// Rm pin rm api
|
// Rm pin rm api
|
||||||
func (api *PinAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.PinRmOption) error {
|
func (api *PinAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.PinRmOption) error {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "Rm", trace.WithAttributes(attribute.String("path", p.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
rp, err := api.core().ResolvePath(ctx, p)
|
rp, err := api.core().ResolvePath(ctx, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -87,6 +108,8 @@ func (api *PinAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.PinRmOpti
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.SetAttributes(attribute.Bool("recursive", settings.Recursive))
|
||||||
|
|
||||||
// Note: after unpin the pin sets are flushed to the blockstore, so we need
|
// Note: after unpin the pin sets are flushed to the blockstore, so we need
|
||||||
// to take a lock to prevent a concurrent garbage collection
|
// to take a lock to prevent a concurrent garbage collection
|
||||||
defer api.blockstore.PinLock(ctx).Unlock(ctx)
|
defer api.blockstore.PinLock(ctx).Unlock(ctx)
|
||||||
@ -99,11 +122,19 @@ func (api *PinAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.PinRmOpti
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *PinAPI) Update(ctx context.Context, from path.Path, to path.Path, opts ...caopts.PinUpdateOption) error {
|
func (api *PinAPI) Update(ctx context.Context, from path.Path, to path.Path, opts ...caopts.PinUpdateOption) error {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "Update", trace.WithAttributes(
|
||||||
|
attribute.String("from", from.String()),
|
||||||
|
attribute.String("to", to.String()),
|
||||||
|
))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
settings, err := caopts.PinUpdateOptions(opts...)
|
settings, err := caopts.PinUpdateOptions(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.SetAttributes(attribute.Bool("unpin", settings.Unpin))
|
||||||
|
|
||||||
fp, err := api.core().ResolvePath(ctx, from)
|
fp, err := api.core().ResolvePath(ctx, from)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -153,6 +184,9 @@ func (n *badNode) Err() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, error) {
|
func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "Verify")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
visited := make(map[cid.Cid]*pinStatus)
|
visited := make(map[cid.Cid]*pinStatus)
|
||||||
bs := api.blockstore
|
bs := api.blockstore
|
||||||
DAG := merkledag.NewDAGService(bserv.New(bs, offline.Exchange(bs)))
|
DAG := merkledag.NewDAGService(bserv.New(bs, offline.Exchange(bs)))
|
||||||
@ -164,6 +198,9 @@ func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, erro
|
|||||||
|
|
||||||
var checkPin func(root cid.Cid) *pinStatus
|
var checkPin func(root cid.Cid) *pinStatus
|
||||||
checkPin = func(root cid.Cid) *pinStatus {
|
checkPin = func(root cid.Cid) *pinStatus {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "Verify.CheckPin", trace.WithAttributes(attribute.String("cid", root.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
if status, ok := visited[root]; ok {
|
if status, ok := visited[root]; ok {
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package coreapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
cid "github.com/ipfs/go-cid"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ProviderAPI brings Provider behavior to CoreAPI
|
|
||||||
type ProviderAPI CoreAPI
|
|
||||||
|
|
||||||
// Provide the given cid using the current provider
|
|
||||||
func (api *ProviderAPI) Provide(cid cid.Cid) error {
|
|
||||||
return api.provider.Provide(cid)
|
|
||||||
}
|
|
@ -4,11 +4,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
||||||
caopts "github.com/ipfs/interface-go-ipfs-core/options"
|
caopts "github.com/ipfs/interface-go-ipfs-core/options"
|
||||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||||
routing "github.com/libp2p/go-libp2p-core/routing"
|
routing "github.com/libp2p/go-libp2p-core/routing"
|
||||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PubSubAPI CoreAPI
|
type PubSubAPI CoreAPI
|
||||||
@ -22,6 +25,9 @@ type pubSubMessage struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *PubSubAPI) Ls(ctx context.Context) ([]string, error) {
|
func (api *PubSubAPI) Ls(ctx context.Context) ([]string, error) {
|
||||||
|
_, span := tracing.Span(ctx, "CoreAPI.PubSubAPI", "Ls")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
_, err := api.checkNode()
|
_, err := api.checkNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -31,6 +37,9 @@ func (api *PubSubAPI) Ls(ctx context.Context) ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *PubSubAPI) Peers(ctx context.Context, opts ...caopts.PubSubPeersOption) ([]peer.ID, error) {
|
func (api *PubSubAPI) Peers(ctx context.Context, opts ...caopts.PubSubPeersOption) ([]peer.ID, error) {
|
||||||
|
_, span := tracing.Span(ctx, "CoreAPI.PubSubAPI", "Peers")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
_, err := api.checkNode()
|
_, err := api.checkNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -41,10 +50,15 @@ func (api *PubSubAPI) Peers(ctx context.Context, opts ...caopts.PubSubPeersOptio
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.SetAttributes(attribute.String("topic", settings.Topic))
|
||||||
|
|
||||||
return api.pubSub.ListPeers(settings.Topic), nil
|
return api.pubSub.ListPeers(settings.Topic), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *PubSubAPI) Publish(ctx context.Context, topic string, data []byte) error {
|
func (api *PubSubAPI) Publish(ctx context.Context, topic string, data []byte) error {
|
||||||
|
_, span := tracing.Span(ctx, "CoreAPI.PubSubAPI", "Publish", trace.WithAttributes(attribute.String("topic", topic)))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
_, err := api.checkNode()
|
_, err := api.checkNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -55,6 +69,9 @@ func (api *PubSubAPI) Publish(ctx context.Context, topic string, data []byte) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *PubSubAPI) Subscribe(ctx context.Context, topic string, opts ...caopts.PubSubSubscribeOption) (coreiface.PubSubSubscription, error) {
|
func (api *PubSubAPI) Subscribe(ctx context.Context, topic string, opts ...caopts.PubSubSubscribeOption) (coreiface.PubSubSubscription, error) {
|
||||||
|
_, span := tracing.Span(ctx, "CoreAPI.PubSubAPI", "Subscribe", trace.WithAttributes(attribute.String("topic", topic)))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
// Parse the options to avoid introducing silent failures for invalid
|
// Parse the options to avoid introducing silent failures for invalid
|
||||||
// options. However, we don't currently have any use for them. The only
|
// options. However, we don't currently have any use for them. The only
|
||||||
// subscription option, discovery, is now a no-op as it's handled by
|
// subscription option, discovery, is now a no-op as it's handled by
|
||||||
@ -97,6 +114,9 @@ func (sub *pubSubSubscription) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sub *pubSubSubscription) Next(ctx context.Context) (coreiface.PubSubMessage, error) {
|
func (sub *pubSubSubscription) Next(ctx context.Context) (coreiface.PubSubMessage, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.PubSubSubscription", "Next")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
msg, err := sub.subscription.Next(ctx)
|
msg, err := sub.subscription.Next(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
||||||
inet "github.com/libp2p/go-libp2p-core/network"
|
inet "github.com/libp2p/go-libp2p-core/network"
|
||||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||||
@ -12,6 +13,8 @@ import (
|
|||||||
protocol "github.com/libp2p/go-libp2p-core/protocol"
|
protocol "github.com/libp2p/go-libp2p-core/protocol"
|
||||||
swarm "github.com/libp2p/go-libp2p-swarm"
|
swarm "github.com/libp2p/go-libp2p-swarm"
|
||||||
ma "github.com/multiformats/go-multiaddr"
|
ma "github.com/multiformats/go-multiaddr"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SwarmAPI CoreAPI
|
type SwarmAPI CoreAPI
|
||||||
@ -30,6 +33,9 @@ const connectionManagerTag = "user-connect"
|
|||||||
const connectionManagerWeight = 100
|
const connectionManagerWeight = 100
|
||||||
|
|
||||||
func (api *SwarmAPI) Connect(ctx context.Context, pi peer.AddrInfo) error {
|
func (api *SwarmAPI) Connect(ctx context.Context, pi peer.AddrInfo) error {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.SwarmAPI", "Connect", trace.WithAttributes(attribute.String("peerid", pi.ID.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
if api.peerHost == nil {
|
if api.peerHost == nil {
|
||||||
return coreiface.ErrOffline
|
return coreiface.ErrOffline
|
||||||
}
|
}
|
||||||
@ -47,6 +53,9 @@ func (api *SwarmAPI) Connect(ctx context.Context, pi peer.AddrInfo) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *SwarmAPI) Disconnect(ctx context.Context, addr ma.Multiaddr) error {
|
func (api *SwarmAPI) Disconnect(ctx context.Context, addr ma.Multiaddr) error {
|
||||||
|
_, span := tracing.Span(ctx, "CoreAPI.SwarmAPI", "Disconnect", trace.WithAttributes(attribute.String("addr", addr.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
if api.peerHost == nil {
|
if api.peerHost == nil {
|
||||||
return coreiface.ErrOffline
|
return coreiface.ErrOffline
|
||||||
}
|
}
|
||||||
@ -56,6 +65,8 @@ func (api *SwarmAPI) Disconnect(ctx context.Context, addr ma.Multiaddr) error {
|
|||||||
return peer.ErrInvalidAddr
|
return peer.ErrInvalidAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.SetAttributes(attribute.String("peerid", id.String()))
|
||||||
|
|
||||||
net := api.peerHost.Network()
|
net := api.peerHost.Network()
|
||||||
if taddr == nil {
|
if taddr == nil {
|
||||||
if net.Connectedness(id) != inet.Connected {
|
if net.Connectedness(id) != inet.Connected {
|
||||||
@ -76,7 +87,10 @@ func (api *SwarmAPI) Disconnect(ctx context.Context, addr ma.Multiaddr) error {
|
|||||||
return coreiface.ErrConnNotFound
|
return coreiface.ErrConnNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *SwarmAPI) KnownAddrs(context.Context) (map[peer.ID][]ma.Multiaddr, error) {
|
func (api *SwarmAPI) KnownAddrs(ctx context.Context) (map[peer.ID][]ma.Multiaddr, error) {
|
||||||
|
_, span := tracing.Span(ctx, "CoreAPI.SwarmAPI", "KnownAddrs")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
if api.peerHost == nil {
|
if api.peerHost == nil {
|
||||||
return nil, coreiface.ErrOffline
|
return nil, coreiface.ErrOffline
|
||||||
}
|
}
|
||||||
@ -93,7 +107,10 @@ func (api *SwarmAPI) KnownAddrs(context.Context) (map[peer.ID][]ma.Multiaddr, er
|
|||||||
return addrs, nil
|
return addrs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *SwarmAPI) LocalAddrs(context.Context) ([]ma.Multiaddr, error) {
|
func (api *SwarmAPI) LocalAddrs(ctx context.Context) ([]ma.Multiaddr, error) {
|
||||||
|
_, span := tracing.Span(ctx, "CoreAPI.SwarmAPI", "LocalAddrs")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
if api.peerHost == nil {
|
if api.peerHost == nil {
|
||||||
return nil, coreiface.ErrOffline
|
return nil, coreiface.ErrOffline
|
||||||
}
|
}
|
||||||
@ -101,7 +118,10 @@ func (api *SwarmAPI) LocalAddrs(context.Context) ([]ma.Multiaddr, error) {
|
|||||||
return api.peerHost.Addrs(), nil
|
return api.peerHost.Addrs(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *SwarmAPI) ListenAddrs(context.Context) ([]ma.Multiaddr, error) {
|
func (api *SwarmAPI) ListenAddrs(ctx context.Context) ([]ma.Multiaddr, error) {
|
||||||
|
_, span := tracing.Span(ctx, "CoreAPI.SwarmAPI", "ListenAddrs")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
if api.peerHost == nil {
|
if api.peerHost == nil {
|
||||||
return nil, coreiface.ErrOffline
|
return nil, coreiface.ErrOffline
|
||||||
}
|
}
|
||||||
@ -109,7 +129,10 @@ func (api *SwarmAPI) ListenAddrs(context.Context) ([]ma.Multiaddr, error) {
|
|||||||
return api.peerHost.Network().InterfaceListenAddresses()
|
return api.peerHost.Network().InterfaceListenAddresses()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *SwarmAPI) Peers(context.Context) ([]coreiface.ConnectionInfo, error) {
|
func (api *SwarmAPI) Peers(ctx context.Context) ([]coreiface.ConnectionInfo, error) {
|
||||||
|
_, span := tracing.Span(ctx, "CoreAPI.SwarmAPI", "Peers")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
if api.peerHost == nil {
|
if api.peerHost == nil {
|
||||||
return nil, coreiface.ErrOffline
|
return nil, coreiface.ErrOffline
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ipfs/go-ipfs/core"
|
"github.com/ipfs/go-ipfs/core"
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
|
||||||
"github.com/ipfs/go-ipfs/core/coreunix"
|
"github.com/ipfs/go-ipfs/core/coreunix"
|
||||||
|
|
||||||
@ -55,11 +58,30 @@ func getOrCreateNilNode() (*core.IpfsNode, error) {
|
|||||||
// Add builds a merkledag node from a reader, adds it to the blockstore,
|
// Add builds a merkledag node from a reader, adds it to the blockstore,
|
||||||
// and returns the key representing that node.
|
// and returns the key representing that node.
|
||||||
func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options.UnixfsAddOption) (path.Resolved, error) {
|
func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options.UnixfsAddOption) (path.Resolved, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.UnixfsAPI", "Add")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
settings, prefix, err := options.UnixfsAddOptions(opts...)
|
settings, prefix, err := options.UnixfsAddOptions(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.SetAttributes(
|
||||||
|
attribute.String("chunker", settings.Chunker),
|
||||||
|
attribute.Int("cidversion", settings.CidVersion),
|
||||||
|
attribute.Bool("inline", settings.Inline),
|
||||||
|
attribute.Int("inlinelimit", settings.InlineLimit),
|
||||||
|
attribute.Bool("rawleaves", settings.RawLeaves),
|
||||||
|
attribute.Bool("rawleavesset", settings.RawLeavesSet),
|
||||||
|
attribute.Int("layout", int(settings.Layout)),
|
||||||
|
attribute.Bool("pin", settings.Pin),
|
||||||
|
attribute.Bool("onlyhash", settings.OnlyHash),
|
||||||
|
attribute.Bool("fscache", settings.FsCache),
|
||||||
|
attribute.Bool("nocopy", settings.NoCopy),
|
||||||
|
attribute.Bool("silent", settings.Silent),
|
||||||
|
attribute.Bool("progress", settings.Progress),
|
||||||
|
)
|
||||||
|
|
||||||
cfg, err := api.repo.Config()
|
cfg, err := api.repo.Config()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -179,6 +201,9 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *UnixfsAPI) Get(ctx context.Context, p path.Path) (files.Node, error) {
|
func (api *UnixfsAPI) Get(ctx context.Context, p path.Path) (files.Node, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.UnixfsAPI", "Get", trace.WithAttributes(attribute.String("path", p.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
ses := api.core().getSession(ctx)
|
ses := api.core().getSession(ctx)
|
||||||
|
|
||||||
nd, err := ses.ResolveNode(ctx, p)
|
nd, err := ses.ResolveNode(ctx, p)
|
||||||
@ -192,11 +217,16 @@ func (api *UnixfsAPI) Get(ctx context.Context, p path.Path) (files.Node, error)
|
|||||||
// Ls returns the contents of an IPFS or IPNS object(s) at path p, with the format:
|
// Ls returns the contents of an IPFS or IPNS object(s) at path p, with the format:
|
||||||
// `<link base58 hash> <link size in bytes> <link name>`
|
// `<link base58 hash> <link size in bytes> <link name>`
|
||||||
func (api *UnixfsAPI) Ls(ctx context.Context, p path.Path, opts ...options.UnixfsLsOption) (<-chan coreiface.DirEntry, error) {
|
func (api *UnixfsAPI) Ls(ctx context.Context, p path.Path, opts ...options.UnixfsLsOption) (<-chan coreiface.DirEntry, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.UnixfsAPI", "Ls", trace.WithAttributes(attribute.String("path", p.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
settings, err := options.UnixfsLsOptions(opts...)
|
settings, err := options.UnixfsLsOptions(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.SetAttributes(attribute.Bool("resolvechildren", settings.ResolveChildren))
|
||||||
|
|
||||||
ses := api.core().getSession(ctx)
|
ses := api.core().getSession(ctx)
|
||||||
uses := (*UnixfsAPI)(ses)
|
uses := (*UnixfsAPI)(ses)
|
||||||
|
|
||||||
@ -217,6 +247,13 @@ func (api *UnixfsAPI) Ls(ctx context.Context, p path.Path, opts ...options.Unixf
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *UnixfsAPI) processLink(ctx context.Context, linkres ft.LinkResult, settings *options.UnixfsLsSettings) coreiface.DirEntry {
|
func (api *UnixfsAPI) processLink(ctx context.Context, linkres ft.LinkResult, settings *options.UnixfsLsSettings) coreiface.DirEntry {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreAPI.UnixfsAPI", "ProcessLink")
|
||||||
|
defer span.End()
|
||||||
|
if linkres.Link != nil {
|
||||||
|
span.SetAttributes(attribute.String("linkname", linkres.Link.Name), attribute.String("cid", linkres.Link.Cid.String()))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if linkres.Err != nil {
|
if linkres.Err != nil {
|
||||||
return coreiface.DirEntry{Err: linkres.Err}
|
return coreiface.DirEntry{Err: linkres.Err}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
version "github.com/ipfs/go-ipfs"
|
version "github.com/ipfs/go-ipfs"
|
||||||
core "github.com/ipfs/go-ipfs/core"
|
core "github.com/ipfs/go-ipfs/core"
|
||||||
coreapi "github.com/ipfs/go-ipfs/core/coreapi"
|
coreapi "github.com/ipfs/go-ipfs/core/coreapi"
|
||||||
|
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||||
|
|
||||||
options "github.com/ipfs/interface-go-ipfs-core/options"
|
options "github.com/ipfs/interface-go-ipfs-core/options"
|
||||||
id "github.com/libp2p/go-libp2p/p2p/protocol/identify"
|
id "github.com/libp2p/go-libp2p/p2p/protocol/identify"
|
||||||
@ -87,12 +88,14 @@ func GatewayOption(writable bool, paths ...string) ServeOption {
|
|||||||
"X-Stream-Output",
|
"X-Stream-Output",
|
||||||
}, headers[ACEHeadersName]...))
|
}, headers[ACEHeadersName]...))
|
||||||
|
|
||||||
gateway := newGatewayHandler(GatewayConfig{
|
var gateway http.Handler = newGatewayHandler(GatewayConfig{
|
||||||
Headers: headers,
|
Headers: headers,
|
||||||
Writable: writable,
|
Writable: writable,
|
||||||
PathPrefixes: cfg.Gateway.PathPrefixes,
|
PathPrefixes: cfg.Gateway.PathPrefixes,
|
||||||
}, api)
|
}, api)
|
||||||
|
|
||||||
|
gateway = otelhttp.NewHandler(gateway, "Gateway.Request")
|
||||||
|
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
mux.Handle(p+"/", gateway)
|
mux.Handle(p+"/", gateway)
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ import (
|
|||||||
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
||||||
routing "github.com/libp2p/go-libp2p-core/routing"
|
routing "github.com/libp2p/go-libp2p-core/routing"
|
||||||
prometheus "github.com/prometheus/client_golang/prometheus"
|
prometheus "github.com/prometheus/client_golang/prometheus"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -354,6 +356,8 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
|
|||||||
webError(w, "error while processing the Accept header", err, http.StatusBadRequest)
|
webError(w, "error while processing the Accept header", err, http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
trace.SpanFromContext(r.Context()).SetAttributes(attribute.String("ResponseFormat", responseFormat))
|
||||||
|
trace.SpanFromContext(r.Context()).SetAttributes(attribute.String("ResolvedPath", resolvedPath.String()))
|
||||||
|
|
||||||
// Finish early if client already has matching Etag
|
// Finish early if client already has matching Etag
|
||||||
if r.Header.Get("If-None-Match") == getEtag(r, resolvedPath.Cid()) {
|
if r.Header.Get("If-None-Match") == getEtag(r, resolvedPath.Cid()) {
|
||||||
@ -392,12 +396,12 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
|
|||||||
return
|
return
|
||||||
case "application/vnd.ipld.raw":
|
case "application/vnd.ipld.raw":
|
||||||
logger.Debugw("serving raw block", "path", contentPath)
|
logger.Debugw("serving raw block", "path", contentPath)
|
||||||
i.serveRawBlock(w, r, resolvedPath.Cid(), contentPath, begin)
|
i.serveRawBlock(w, r, resolvedPath, contentPath, begin)
|
||||||
return
|
return
|
||||||
case "application/vnd.ipld.car":
|
case "application/vnd.ipld.car":
|
||||||
logger.Debugw("serving car stream", "path", contentPath)
|
logger.Debugw("serving car stream", "path", contentPath)
|
||||||
carVersion := formatParams["version"]
|
carVersion := formatParams["version"]
|
||||||
i.serveCar(w, r, resolvedPath.Cid(), contentPath, carVersion, begin)
|
i.serveCar(w, r, resolvedPath, contentPath, carVersion, begin)
|
||||||
return
|
return
|
||||||
default: // catch-all for unsuported application/vnd.*
|
default: // catch-all for unsuported application/vnd.*
|
||||||
err := fmt.Errorf("unsupported format %q", responseFormat)
|
err := fmt.Errorf("unsupported format %q", responseFormat)
|
||||||
|
@ -6,13 +6,18 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
cid "github.com/ipfs/go-cid"
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
// serveRawBlock returns bytes behind a raw block
|
// serveRawBlock returns bytes behind a raw block
|
||||||
func (i *gatewayHandler) serveRawBlock(w http.ResponseWriter, r *http.Request, blockCid cid.Cid, contentPath ipath.Path, begin time.Time) {
|
func (i *gatewayHandler) serveRawBlock(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time) {
|
||||||
blockReader, err := i.api.Block().Get(r.Context(), contentPath)
|
ctx, span := tracing.Span(r.Context(), "Gateway", "ServeRawBlock", trace.WithAttributes(attribute.String("path", resolvedPath.String())))
|
||||||
|
defer span.End()
|
||||||
|
blockCid := resolvedPath.Cid()
|
||||||
|
blockReader, err := i.api.Block().Get(ctx, resolvedPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
webError(w, "ipfs block get "+blockCid.String(), err, http.StatusInternalServerError)
|
webError(w, "ipfs block get "+blockCid.String(), err, http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
@ -8,15 +8,20 @@ import (
|
|||||||
|
|
||||||
blocks "github.com/ipfs/go-block-format"
|
blocks "github.com/ipfs/go-block-format"
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
||||||
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
||||||
gocar "github.com/ipld/go-car"
|
gocar "github.com/ipld/go-car"
|
||||||
selectorparse "github.com/ipld/go-ipld-prime/traversal/selector/parse"
|
selectorparse "github.com/ipld/go-ipld-prime/traversal/selector/parse"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
// serveCar returns a CAR stream for specific DAG+selector
|
// serveCar returns a CAR stream for specific DAG+selector
|
||||||
func (i *gatewayHandler) serveCar(w http.ResponseWriter, r *http.Request, rootCid cid.Cid, contentPath ipath.Path, carVersion string, begin time.Time) {
|
func (i *gatewayHandler) serveCar(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, carVersion string, begin time.Time) {
|
||||||
ctx, cancel := context.WithCancel(r.Context())
|
ctx, span := tracing.Span(r.Context(), "Gateway", "ServeCar", trace.WithAttributes(attribute.String("path", resolvedPath.String())))
|
||||||
|
defer span.End()
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
switch carVersion {
|
switch carVersion {
|
||||||
@ -27,6 +32,7 @@ func (i *gatewayHandler) serveCar(w http.ResponseWriter, r *http.Request, rootCi
|
|||||||
webError(w, "unsupported CAR version", err, http.StatusBadRequest)
|
webError(w, "unsupported CAR version", err, http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
rootCid := resolvedPath.Cid()
|
||||||
|
|
||||||
// Set Content-Disposition
|
// Set Content-Disposition
|
||||||
name := rootCid.String() + ".car"
|
name := rootCid.String() + ".car"
|
||||||
|
@ -7,13 +7,18 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
files "github.com/ipfs/go-ipfs-files"
|
files "github.com/ipfs/go-ipfs-files"
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (i *gatewayHandler) serveUnixFs(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time, logger *zap.SugaredLogger) {
|
func (i *gatewayHandler) serveUnixFs(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time, logger *zap.SugaredLogger) {
|
||||||
|
ctx, span := tracing.Span(r.Context(), "Gateway", "ServeUnixFs", trace.WithAttributes(attribute.String("path", resolvedPath.String())))
|
||||||
|
defer span.End()
|
||||||
// Handling UnixFS
|
// Handling UnixFS
|
||||||
dr, err := i.api.Unixfs().Get(r.Context(), resolvedPath)
|
dr, err := i.api.Unixfs().Get(ctx, resolvedPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
webError(w, "ipfs cat "+html.EscapeString(contentPath.String()), err, http.StatusNotFound)
|
webError(w, "ipfs cat "+html.EscapeString(contentPath.String()), err, http.StatusNotFound)
|
||||||
return
|
return
|
||||||
@ -23,7 +28,7 @@ func (i *gatewayHandler) serveUnixFs(w http.ResponseWriter, r *http.Request, res
|
|||||||
// Handling Unixfs file
|
// Handling Unixfs file
|
||||||
if f, ok := dr.(files.File); ok {
|
if f, ok := dr.(files.File); ok {
|
||||||
logger.Debugw("serving unixfs file", "path", contentPath)
|
logger.Debugw("serving unixfs file", "path", contentPath)
|
||||||
i.serveFile(w, r, contentPath, resolvedPath.Cid(), f, begin)
|
i.serveFile(w, r, resolvedPath, contentPath, f, begin)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,9 +10,12 @@ import (
|
|||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
files "github.com/ipfs/go-ipfs-files"
|
files "github.com/ipfs/go-ipfs-files"
|
||||||
"github.com/ipfs/go-ipfs/assets"
|
"github.com/ipfs/go-ipfs/assets"
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
path "github.com/ipfs/go-path"
|
path "github.com/ipfs/go-path"
|
||||||
"github.com/ipfs/go-path/resolver"
|
"github.com/ipfs/go-path/resolver"
|
||||||
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -20,6 +23,8 @@ import (
|
|||||||
//
|
//
|
||||||
// It will return index.html if present, or generate directory listing otherwise.
|
// It will return index.html if present, or generate directory listing otherwise.
|
||||||
func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, dir files.Directory, begin time.Time, logger *zap.SugaredLogger) {
|
func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, dir files.Directory, begin time.Time, logger *zap.SugaredLogger) {
|
||||||
|
ctx, span := tracing.Span(r.Context(), "Gateway", "ServeDirectory", trace.WithAttributes(attribute.String("path", resolvedPath.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
// HostnameOption might have constructed an IPNS/IPFS path using the Host header.
|
// HostnameOption might have constructed an IPNS/IPFS path using the Host header.
|
||||||
// In this case, we need the original path for constructing redirects
|
// In this case, we need the original path for constructing redirects
|
||||||
@ -35,7 +40,7 @@ func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request,
|
|||||||
|
|
||||||
// Check if directory has index.html, if so, serveFile
|
// Check if directory has index.html, if so, serveFile
|
||||||
idxPath := ipath.Join(resolvedPath, "index.html")
|
idxPath := ipath.Join(resolvedPath, "index.html")
|
||||||
idx, err := i.api.Unixfs().Get(r.Context(), idxPath)
|
idx, err := i.api.Unixfs().Get(ctx, idxPath)
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
cpath := contentPath.String()
|
cpath := contentPath.String()
|
||||||
@ -63,7 +68,7 @@ func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request,
|
|||||||
|
|
||||||
logger.Debugw("serving index.html file", "path", idxPath)
|
logger.Debugw("serving index.html file", "path", idxPath)
|
||||||
// write to request
|
// write to request
|
||||||
i.serveFile(w, r, idxPath, resolvedPath.Cid(), f, begin)
|
i.serveFile(w, r, resolvedPath, idxPath, f, begin)
|
||||||
return
|
return
|
||||||
case resolver.ErrNoLink:
|
case resolver.ErrNoLink:
|
||||||
logger.Debugw("no index.html; noop", "path", idxPath)
|
logger.Debugw("no index.html; noop", "path", idxPath)
|
||||||
@ -111,7 +116,7 @@ func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request,
|
|||||||
size = humanize.Bytes(uint64(s))
|
size = humanize.Bytes(uint64(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
resolved, err := i.api.ResolvePath(r.Context(), ipath.Join(resolvedPath, dirit.Name()))
|
resolved, err := i.api.ResolvePath(ctx, ipath.Join(resolvedPath, dirit.Name()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
internalWebError(w, err)
|
internalWebError(w, err)
|
||||||
return
|
return
|
||||||
|
@ -10,17 +10,21 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gabriel-vasile/mimetype"
|
"github.com/gabriel-vasile/mimetype"
|
||||||
cid "github.com/ipfs/go-cid"
|
|
||||||
files "github.com/ipfs/go-ipfs-files"
|
files "github.com/ipfs/go-ipfs-files"
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
// serveFile returns data behind a file along with HTTP headers based on
|
// serveFile returns data behind a file along with HTTP headers based on
|
||||||
// the file itself, its CID and the contentPath used for accessing it.
|
// the file itself, its CID and the contentPath used for accessing it.
|
||||||
func (i *gatewayHandler) serveFile(w http.ResponseWriter, r *http.Request, contentPath ipath.Path, fileCid cid.Cid, file files.File, begin time.Time) {
|
func (i *gatewayHandler) serveFile(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, file files.File, begin time.Time) {
|
||||||
|
_, span := tracing.Span(r.Context(), "Gateway", "ServeFile", trace.WithAttributes(attribute.String("path", resolvedPath.String())))
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
// Set Cache-Control and read optional Last-Modified time
|
// Set Cache-Control and read optional Last-Modified time
|
||||||
modtime := addCacheControlHeaders(w, r, contentPath, fileCid)
|
modtime := addCacheControlHeaders(w, r, contentPath, resolvedPath.Cid())
|
||||||
|
|
||||||
// Set Content-Disposition
|
// Set Content-Disposition
|
||||||
name := addContentDispositionHeader(w, r, contentPath)
|
name := addContentDispositionHeader(w, r, contentPath)
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
files "github.com/ipfs/go-ipfs-files"
|
files "github.com/ipfs/go-ipfs-files"
|
||||||
pin "github.com/ipfs/go-ipfs-pinner"
|
pin "github.com/ipfs/go-ipfs-pinner"
|
||||||
posinfo "github.com/ipfs/go-ipfs-posinfo"
|
posinfo "github.com/ipfs/go-ipfs-posinfo"
|
||||||
|
"github.com/ipfs/go-ipfs/tracing"
|
||||||
ipld "github.com/ipfs/go-ipld-format"
|
ipld "github.com/ipfs/go-ipld-format"
|
||||||
logging "github.com/ipfs/go-log"
|
logging "github.com/ipfs/go-log"
|
||||||
dag "github.com/ipfs/go-merkledag"
|
dag "github.com/ipfs/go-merkledag"
|
||||||
@ -158,20 +159,23 @@ func (adder *Adder) curRootNode() (ipld.Node, error) {
|
|||||||
|
|
||||||
// Recursively pins the root node of Adder and
|
// Recursively pins the root node of Adder and
|
||||||
// writes the pin state to the backing datastore.
|
// writes the pin state to the backing datastore.
|
||||||
func (adder *Adder) PinRoot(root ipld.Node) error {
|
func (adder *Adder) PinRoot(ctx context.Context, root ipld.Node) error {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreUnix.Adder", "PinRoot")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
if !adder.Pin {
|
if !adder.Pin {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rnk := root.Cid()
|
rnk := root.Cid()
|
||||||
|
|
||||||
err := adder.dagService.Add(adder.ctx, root)
|
err := adder.dagService.Add(ctx, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if adder.tempRoot.Defined() {
|
if adder.tempRoot.Defined() {
|
||||||
err := adder.pinning.Unpin(adder.ctx, adder.tempRoot, true)
|
err := adder.pinning.Unpin(ctx, adder.tempRoot, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -179,7 +183,7 @@ func (adder *Adder) PinRoot(root ipld.Node) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
adder.pinning.PinWithMode(rnk, pin.Recursive)
|
adder.pinning.PinWithMode(rnk, pin.Recursive)
|
||||||
return adder.pinning.Flush(adder.ctx)
|
return adder.pinning.Flush(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adder *Adder) outputDirs(path string, fsn mfs.FSNode) error {
|
func (adder *Adder) outputDirs(path string, fsn mfs.FSNode) error {
|
||||||
@ -255,6 +259,9 @@ func (adder *Adder) addNode(node ipld.Node, path string) error {
|
|||||||
|
|
||||||
// AddAllAndPin adds the given request's files and pin them.
|
// AddAllAndPin adds the given request's files and pin them.
|
||||||
func (adder *Adder) AddAllAndPin(ctx context.Context, file files.Node) (ipld.Node, error) {
|
func (adder *Adder) AddAllAndPin(ctx context.Context, file files.Node) (ipld.Node, error) {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreUnix.Adder", "AddAllAndPin")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
if adder.Pin {
|
if adder.Pin {
|
||||||
adder.unlocker = adder.gcLocker.PinLock(ctx)
|
adder.unlocker = adder.gcLocker.PinLock(ctx)
|
||||||
}
|
}
|
||||||
@ -330,10 +337,13 @@ func (adder *Adder) AddAllAndPin(ctx context.Context, file files.Node) (ipld.Nod
|
|||||||
if !adder.Pin {
|
if !adder.Pin {
|
||||||
return nd, nil
|
return nd, nil
|
||||||
}
|
}
|
||||||
return nd, adder.PinRoot(nd)
|
return nd, adder.PinRoot(ctx, nd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adder *Adder) addFileNode(ctx context.Context, path string, file files.Node, toplevel bool) error {
|
func (adder *Adder) addFileNode(ctx context.Context, path string, file files.Node, toplevel bool) error {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreUnix.Adder", "AddFileNode")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
err := adder.maybePauseForGC(ctx)
|
err := adder.maybePauseForGC(ctx)
|
||||||
@ -436,13 +446,16 @@ func (adder *Adder) addDir(ctx context.Context, path string, dir files.Directory
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (adder *Adder) maybePauseForGC(ctx context.Context) error {
|
func (adder *Adder) maybePauseForGC(ctx context.Context) error {
|
||||||
|
ctx, span := tracing.Span(ctx, "CoreUnix.Adder", "MaybePauseForGC")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
if adder.unlocker != nil && adder.gcLocker.GCRequested(ctx) {
|
if adder.unlocker != nil && adder.gcLocker.GCRequested(ctx) {
|
||||||
rn, err := adder.curRootNode()
|
rn, err := adder.curRootNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = adder.PinRoot(rn)
|
err = adder.PinRoot(ctx, rn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ This is a document for helping debug go-ipfs. Please add to it if you can!
|
|||||||
- [Analyzing the stack dump](#analyzing-the-stack-dump)
|
- [Analyzing the stack dump](#analyzing-the-stack-dump)
|
||||||
- [Analyzing the CPU Profile](#analyzing-the-cpu-profile)
|
- [Analyzing the CPU Profile](#analyzing-the-cpu-profile)
|
||||||
- [Analyzing vars and memory statistics](#analyzing-vars-and-memory-statistics)
|
- [Analyzing vars and memory statistics](#analyzing-vars-and-memory-statistics)
|
||||||
|
- [Tracing](#tracing)
|
||||||
- [Other](#other)
|
- [Other](#other)
|
||||||
|
|
||||||
### Beginning
|
### Beginning
|
||||||
@ -95,6 +96,11 @@ the quickest way to easily point out where the hot spots in the code are.
|
|||||||
|
|
||||||
The output is JSON formatted and includes badger store statistics, the command line run, and the output from Go's [runtime.ReadMemStats](https://golang.org/pkg/runtime/#ReadMemStats). The [MemStats](https://golang.org/pkg/runtime/#MemStats) has useful information about memory allocation and garbage collection.
|
The output is JSON formatted and includes badger store statistics, the command line run, and the output from Go's [runtime.ReadMemStats](https://golang.org/pkg/runtime/#ReadMemStats). The [MemStats](https://golang.org/pkg/runtime/#MemStats) has useful information about memory allocation and garbage collection.
|
||||||
|
|
||||||
|
### Tracing
|
||||||
|
|
||||||
|
Experimental tracing via OpenTelemetry suite of tools is available.
|
||||||
|
See `tracing/doc.go` for more details.
|
||||||
|
|
||||||
### Other
|
### Other
|
||||||
|
|
||||||
If you have any questions, or want us to analyze some weird go-ipfs behaviour,
|
If you have any questions, or want us to analyze some weird go-ipfs behaviour,
|
||||||
|
@ -102,3 +102,73 @@ Deprecated: Use the `Swarm.Transports.Multiplexers` config field.
|
|||||||
Tells go-ipfs which multiplexers to use in which order.
|
Tells go-ipfs which multiplexers to use in which order.
|
||||||
|
|
||||||
Default: "/yamux/1.0.0 /mplex/6.7.0"
|
Default: "/yamux/1.0.0 /mplex/6.7.0"
|
||||||
|
|
||||||
|
# Tracing
|
||||||
|
**NOTE** Tracing support is experimental--releases may contain tracing-related breaking changes.
|
||||||
|
|
||||||
|
## `IPFS_TRACING`
|
||||||
|
Enables OpenTelemetry tracing.
|
||||||
|
|
||||||
|
Default: false
|
||||||
|
|
||||||
|
## `IPFS_TRACING_JAEGER`
|
||||||
|
Enables the Jaeger exporter for OpenTelemetry.
|
||||||
|
|
||||||
|
For additional Jaeger exporter configuration, see: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#jaeger-exporter
|
||||||
|
|
||||||
|
Default: false
|
||||||
|
|
||||||
|
### How to use Jaeger UI
|
||||||
|
|
||||||
|
One can use the `jaegertracing/all-in-one` Docker image to run a full Jaeger
|
||||||
|
stack and configure go-ipfs to publish traces to it (here, in an ephemeral
|
||||||
|
container):
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ docker run --rm -it --name jaeger \
|
||||||
|
-e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
|
||||||
|
-p 5775:5775/udp \
|
||||||
|
-p 6831:6831/udp \
|
||||||
|
-p 6832:6832/udp \
|
||||||
|
-p 5778:5778 \
|
||||||
|
-p 16686:16686 \
|
||||||
|
-p 14268:14268 \
|
||||||
|
-p 14250:14250 \
|
||||||
|
-p 9411:9411 \
|
||||||
|
jaegertracing/all-in-one
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, in other terminal, start go-ipfs with Jaeger tracing enabled:
|
||||||
|
```
|
||||||
|
$ IPFS_TRACING=1 IPFS_TRACING_JAEGER=1 ipfs daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, the [Jaeger UI](https://github.com/jaegertracing/jaeger-ui#readme) is available at http://localhost:16686
|
||||||
|
|
||||||
|
|
||||||
|
## `IPFS_TRACING_OTLP_HTTP`
|
||||||
|
Enables the OTLP HTTP exporter for OpenTelemetry.
|
||||||
|
|
||||||
|
For additional exporter configuration, see: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md
|
||||||
|
|
||||||
|
Default: false
|
||||||
|
|
||||||
|
## `IPFS_TRACING_OTLP_GRPC`
|
||||||
|
Enables the OTLP gRPC exporter for OpenTelemetry.
|
||||||
|
|
||||||
|
For additional exporter configuration, see: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md
|
||||||
|
|
||||||
|
Default: false
|
||||||
|
|
||||||
|
## `IPFS_TRACING_FILE`
|
||||||
|
Enables the file exporter for OpenTelemetry, writing traces to the given file in JSON format.
|
||||||
|
|
||||||
|
Example: "/var/log/ipfs-traces.json"
|
||||||
|
|
||||||
|
Default: "" (disabled)
|
||||||
|
|
||||||
|
## `IPFS_TRACING_RATIO`
|
||||||
|
The ratio of traces to export, as a floating point value in the interval [0, 1].
|
||||||
|
|
||||||
|
Deault: 1.0 (export all traces)
|
||||||
|
|
||||||
|
8
go.mod
8
go.mod
@ -107,6 +107,14 @@ require (
|
|||||||
go.uber.org/dig v1.14.0
|
go.uber.org/dig v1.14.0
|
||||||
go.uber.org/fx v1.16.0
|
go.uber.org/fx v1.16.0
|
||||||
go.uber.org/zap v1.21.0
|
go.uber.org/zap v1.21.0
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.27.0
|
||||||
|
go.opentelemetry.io/otel v1.2.0
|
||||||
|
go.opentelemetry.io/otel/exporters/jaeger v1.2.0
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.2.0
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.2.0
|
||||||
|
go.opentelemetry.io/otel/sdk v1.2.0
|
||||||
|
go.opentelemetry.io/otel/trace v1.2.0
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||||
golang.org/x/sys v0.0.0-20211025112917-711f33c9992c
|
golang.org/x/sys v0.0.0-20211025112917-711f33c9992c
|
||||||
|
44
go.sum
44
go.sum
@ -118,6 +118,8 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7
|
|||||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
||||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/ceramicnetwork/go-dag-jose v0.1.0 h1:yJ/HVlfKpnD3LdYP03AHyTvbm3BpPiz2oZiOeReJRdU=
|
github.com/ceramicnetwork/go-dag-jose v0.1.0 h1:yJ/HVlfKpnD3LdYP03AHyTvbm3BpPiz2oZiOeReJRdU=
|
||||||
github.com/ceramicnetwork/go-dag-jose v0.1.0/go.mod h1:qYA1nYt0X8u4XoMAVoOV3upUVKtrxy/I670Dg5F0wjI=
|
github.com/ceramicnetwork/go-dag-jose v0.1.0/go.mod h1:qYA1nYt0X8u4XoMAVoOV3upUVKtrxy/I670Dg5F0wjI=
|
||||||
@ -136,7 +138,11 @@ github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4
|
|||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
@ -195,12 +201,15 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 h1:BBso6MBKW8ncyZLv37o+KNyy0HrrHgfnOaGQC2qvN+A=
|
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 h1:BBso6MBKW8ncyZLv37o+KNyy0HrrHgfnOaGQC2qvN+A=
|
||||||
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg=
|
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||||
|
github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o=
|
||||||
|
github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||||
github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ=
|
github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ=
|
||||||
github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ=
|
github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ=
|
||||||
@ -345,6 +354,7 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de
|
|||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
|
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
|
||||||
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
|
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
|
||||||
@ -1326,6 +1336,7 @@ github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3
|
|||||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||||
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
@ -1400,15 +1411,35 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|||||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
||||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||||
go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.27.0 h1:0BgiNWjN7rUWO9HdjF4L12r8OW86QkVQcYmCjnayJLo=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.27.0/go.mod h1:bdvm3YpMxWAgEfQhtTBaVR8ceXPRuRBSQrvOBnIlHxc=
|
||||||
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
|
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
|
||||||
go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8=
|
go.opentelemetry.io/otel v1.2.0 h1:YOQDvxO1FayUcT9MIhJhgMyNO1WqoduiyvQHzGN0kUQ=
|
||||||
|
go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I=
|
||||||
|
go.opentelemetry.io/otel/exporters/jaeger v1.2.0 h1:C/5Egj3MJBXRJi22cSl07suqPqtZLnLFmH//OxETUEc=
|
||||||
|
go.opentelemetry.io/otel/exporters/jaeger v1.2.0/go.mod h1:KJLFbEMKTNPIfOxcg/WikIozEoKcPgJRz3Ce1vLlM8E=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 h1:xzbcGykysUh776gzD1LUPsNNHKWN0kQWDnJhn1ddUuk=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0/go.mod h1:14T5gr+Y6s2AgHPqBMgnGwp04csUjQmYXFWPeiBoq5s=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0 h1:VsgsSCDwOSuO8eMVh63Cd4nACMqgjpmAeJSIvVNneD0=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0/go.mod h1:9mLBBnPRf3sf+ASVH2p9xREXVBvwib02FxcKnavtExg=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.2.0 h1:j/jXNzS6Dy0DFgO/oyCvin4H7vTQBg2Vdi6idIzWhCI=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.2.0/go.mod h1:k5GnE4m4Jyy2DNh6UAzG6Nml51nuqQyszV7O1ksQAnE=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.2.0 h1:OiYdrCq1Ctwnovp6EofSPwlp5aGy4LgKNbkg7PtEUw8=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.2.0/go.mod h1:DUFCmFkXr0VtAHl5Zq2JRx24G6ze5CAq8YfdD36RdX8=
|
||||||
|
go.opentelemetry.io/otel/internal/metric v0.25.0 h1:w/7RXe16WdPylaIXDgcYM6t/q0K5lXgSdZOEbIEyliE=
|
||||||
|
go.opentelemetry.io/otel/internal/metric v0.25.0/go.mod h1:Nhuw26QSX7d6n4duoqAFi5KOQR4AuzyMcl5eXOgwxtc=
|
||||||
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
|
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
|
||||||
go.opentelemetry.io/otel/oteltest v0.20.0 h1:HiITxCawalo5vQzdHfKeZurV8x7ljcqAgiWzF6Vaeaw=
|
go.opentelemetry.io/otel/metric v0.25.0 h1:7cXOnCADUsR3+EOqxPaSKwhEuNu0gz/56dRN1hpIdKw=
|
||||||
|
go.opentelemetry.io/otel/metric v0.25.0/go.mod h1:E884FSpQfnJOMMUaq+05IWlJ4rjZpk2s/F1Ju+TEEm8=
|
||||||
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
|
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
|
||||||
go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw=
|
go.opentelemetry.io/otel/sdk v1.2.0 h1:wKN260u4DesJYhyjxDa7LRFkuhH7ncEVKU37LWcyNIo=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.2.0/go.mod h1:jNN8QtpvbsKhgaC6V5lHiejMoKD+V8uadoSafgHPx1U=
|
||||||
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
|
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
|
||||||
|
go.opentelemetry.io/otel/trace v1.2.0 h1:Ys3iqbqZhcf28hHzrm5WAquMkDHNZTUkw7KHbuNjej0=
|
||||||
|
go.opentelemetry.io/otel/trace v1.2.0/go.mod h1:N5FLswTubnxKxOJHM7XZC074qpeEdLy3CgAVsdMucK0=
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
|
go.opentelemetry.io/proto/otlp v0.10.0 h1:n7brgtEbDvXEgGyKKo8SobKT1e9FewlDtXzkVP5djoE=
|
||||||
|
go.opentelemetry.io/proto/otlp v0.10.0/go.mod h1:zG20xCK0szZ1xdokeSOwEcmlXu+x9kkdRe6N1DhKcfU=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
@ -1663,6 +1694,7 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210317225723-c4fcb01b228e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210317225723-c4fcb01b228e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -1841,8 +1873,10 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
|
|||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
|
|
||||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
|
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
||||||
|
google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A=
|
||||||
|
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
@ -70,7 +70,7 @@ test_go_fmt:
|
|||||||
TEST_GO += test_go_fmt
|
TEST_GO += test_go_fmt
|
||||||
|
|
||||||
test_go_lint: test/bin/golangci-lint
|
test_go_lint: test/bin/golangci-lint
|
||||||
golangci-lint run ./...
|
golangci-lint run --timeout=3m ./...
|
||||||
.PHONY: test_go_lint
|
.PHONY: test_go_lint
|
||||||
|
|
||||||
test_go: $(TEST_GO)
|
test_go: $(TEST_GO)
|
||||||
|
@ -241,6 +241,7 @@ func (loader *PluginLoader) Inject() error {
|
|||||||
|
|
||||||
for _, pl := range loader.plugins {
|
for _, pl := range loader.plugins {
|
||||||
if pl, ok := pl.(plugin.PluginIPLD); ok {
|
if pl, ok := pl.(plugin.PluginIPLD); ok {
|
||||||
|
|
||||||
err := injectIPLDPlugin(pl)
|
err := injectIPLDPlugin(pl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
loader.state = loaderFailed
|
loader.state = loaderFailed
|
||||||
@ -338,6 +339,7 @@ func injectIPLDPlugin(pl plugin.PluginIPLD) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func injectTracerPlugin(pl plugin.PluginTracer) error {
|
func injectTracerPlugin(pl plugin.PluginTracer) error {
|
||||||
|
log.Warn("Tracer plugins are deprecated, it's recommended to configure an OpenTelemetry collector instead.")
|
||||||
tracer, err := pl.InitTracer()
|
tracer, err := pl.InitTracer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
57
test/sharness/t0310-tracing.sh
Executable file
57
test/sharness/t0310-tracing.sh
Executable file
@ -0,0 +1,57 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Copyright (c) 2022 Protocol Labs
|
||||||
|
# MIT/Apache-2.0 Licensed; see the LICENSE file in this repository.
|
||||||
|
#
|
||||||
|
|
||||||
|
test_description="Test tracing"
|
||||||
|
|
||||||
|
. lib/test-lib.sh
|
||||||
|
|
||||||
|
test_init_ipfs
|
||||||
|
|
||||||
|
export IPFS_TRACING=1
|
||||||
|
export IPFS_TRACING_OTLP_GRPC=1
|
||||||
|
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
|
||||||
|
|
||||||
|
cat <<EOF > collector-config.yaml
|
||||||
|
receivers:
|
||||||
|
otlp:
|
||||||
|
protocols:
|
||||||
|
grpc:
|
||||||
|
|
||||||
|
processors:
|
||||||
|
batch:
|
||||||
|
|
||||||
|
exporters:
|
||||||
|
file:
|
||||||
|
path: /traces/traces.json
|
||||||
|
|
||||||
|
service:
|
||||||
|
pipelines:
|
||||||
|
traces:
|
||||||
|
receivers: [otlp]
|
||||||
|
processors: [batch]
|
||||||
|
exporters: [file]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# touch traces.json and give it 777 perms, in case docker runs as a different user
|
||||||
|
rm -rf traces.json && touch traces.json && chmod 777 traces.json
|
||||||
|
|
||||||
|
test_expect_success "run opentelemetry collector" '
|
||||||
|
docker run --rm -d -v "$PWD/collector-config.yaml":/config.yaml -v "$PWD":/traces --net=host --name=ipfs-test-otel-collector otel/opentelemetry-collector-contrib:0.48.0 --config /config.yaml
|
||||||
|
'
|
||||||
|
|
||||||
|
test_launch_ipfs_daemon
|
||||||
|
|
||||||
|
test_expect_success "check that a swarm span eventually appears in exported traces" '
|
||||||
|
until cat traces.json | grep CoreAPI.SwarmAPI >/dev/null; do sleep 0.1; done
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success "kill docker container" '
|
||||||
|
docker kill ipfs-test-otel-collector
|
||||||
|
'
|
||||||
|
|
||||||
|
test_kill_ipfs_daemon
|
||||||
|
|
||||||
|
test_done
|
66
tracing/doc.go
Normal file
66
tracing/doc.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// Package tracing contains the tracing logic for go-ipfs, including configuring the tracer and
|
||||||
|
// helping keep consistent naming conventions across the stack.
|
||||||
|
//
|
||||||
|
// NOTE: Tracing is currently experimental. Span names may change unexpectedly, spans may be removed,
|
||||||
|
// and backwards-incompatible changes may be made to tracing configuration, options, and defaults.
|
||||||
|
//
|
||||||
|
// go-ipfs uses OpenTelemetry as its tracing API, and when possible, standard OpenTelemetry environment
|
||||||
|
// variables can be used to configure it. Multiple exporters can also be installed simultaneously,
|
||||||
|
// including one that writes traces to a JSON file on disk.
|
||||||
|
//
|
||||||
|
// In general, tracing is configured through environment variables. The IPFS-specific environment variables are:
|
||||||
|
//
|
||||||
|
// - IPFS_TRACING: enable tracing in go-ipfs
|
||||||
|
// - IPFS_TRACING_JAEGER: enable the Jaeger exporter
|
||||||
|
// - IPFS_TRACING_RATIO: the ratio of traces to export, defaults to 1 (export everything)
|
||||||
|
// - IPFS_TRACING_FILE: write traces to the given filename
|
||||||
|
// - IPFS_TRACING_OTLP_HTTP: enable the OTLP HTTP exporter
|
||||||
|
// - IPFS_TRACING_OTLP_GRPC: enable the OTLP gRPC exporter
|
||||||
|
//
|
||||||
|
// Different exporters have their own set of environment variables, depending on the exporter. These are typically
|
||||||
|
// standard environment variables. Some common ones:
|
||||||
|
//
|
||||||
|
// Jaeger:
|
||||||
|
//
|
||||||
|
// - OTEL_EXPORTER_JAEGER_AGENT_HOST
|
||||||
|
// - OTEL_EXPORTER_JAEGER_AGENT_PORT
|
||||||
|
// - OTEL_EXPORTER_JAEGER_ENDPOINT
|
||||||
|
// - OTEL_EXPORTER_JAEGER_USER
|
||||||
|
// - OTEL_EXPORTER_JAEGER_PASSWORD
|
||||||
|
//
|
||||||
|
// OTLP HTTP/gRPC:
|
||||||
|
//
|
||||||
|
// - OTEL_EXPORTER_OTLP_ENDPOINT
|
||||||
|
// - OTEL_EXPORTER_OTLP_CERTIFICATE
|
||||||
|
// - OTEL_EXPORTER_OTLP_HEADERS
|
||||||
|
// - OTEL_EXPORTER_OTLP_COMPRESSION
|
||||||
|
// - OTEL_EXPORTER_OTLP_TIMEOUT
|
||||||
|
//
|
||||||
|
// For example, if you run a local IPFS daemon, you can use the jaegertracing/all-in-one Docker image to run
|
||||||
|
// a full Jaeger stack and configure go-ipfs to publish traces to it:
|
||||||
|
//
|
||||||
|
// docker run -d --name jaeger \
|
||||||
|
// -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
|
||||||
|
// -p 5775:5775/udp \
|
||||||
|
// -p 6831:6831/udp \
|
||||||
|
// -p 6832:6832/udp \
|
||||||
|
// -p 5778:5778 \
|
||||||
|
// -p 16686:16686 \
|
||||||
|
// -p 14268:14268 \
|
||||||
|
// -p 14250:14250 \
|
||||||
|
// -p 9411:9411 \
|
||||||
|
// jaegertracing/all-in-one
|
||||||
|
// IPFS_TRACING=1 IPFS_TRACING_JAEGER=1 ipfs daemon
|
||||||
|
//
|
||||||
|
// In this example the Jaeger UI is available at http://localhost:16686.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Implementer Notes
|
||||||
|
//
|
||||||
|
// Span names follow a convention of <Component>.<Span>, some examples:
|
||||||
|
//
|
||||||
|
// - component=Gateway + span=Request -> Gateway.Request
|
||||||
|
// - component=CoreAPI.PinAPI + span=Verify.CheckPin -> CoreAPI.PinAPI.Verify.CheckPin
|
||||||
|
//
|
||||||
|
// We follow the OpenTelemetry convention of using whatever TracerProvider is registered globally.
|
||||||
|
package tracing
|
136
tracing/tracing.go
Normal file
136
tracing/tracing.go
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
package tracing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
version "github.com/ipfs/go-ipfs"
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
"go.opentelemetry.io/otel/exporters/jaeger"
|
||||||
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
||||||
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
|
||||||
|
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
|
||||||
|
"go.opentelemetry.io/otel/sdk/resource"
|
||||||
|
"go.opentelemetry.io/otel/sdk/trace"
|
||||||
|
semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
|
||||||
|
traceapi "go.opentelemetry.io/otel/trace"
|
||||||
|
)
|
||||||
|
|
||||||
|
var exporterBuilders = map[string]func(context.Context, string) (trace.SpanExporter, error){
|
||||||
|
"IPFS_TRACING_JAEGER": func(ctx context.Context, s string) (trace.SpanExporter, error) {
|
||||||
|
return jaeger.New(jaeger.WithCollectorEndpoint())
|
||||||
|
},
|
||||||
|
"IPFS_TRACING_FILE": func(ctx context.Context, s string) (trace.SpanExporter, error) {
|
||||||
|
return newFileExporter(s)
|
||||||
|
},
|
||||||
|
"IPFS_TRACING_OTLP_HTTP": func(ctx context.Context, s string) (trace.SpanExporter, error) {
|
||||||
|
return otlptracehttp.New(ctx)
|
||||||
|
},
|
||||||
|
"IPFS_TRACING_OTLP_GRPC": func(ctx context.Context, s string) (trace.SpanExporter, error) {
|
||||||
|
return otlptracegrpc.New(ctx)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileExporter wraps a file-writing exporter and closes the file when the exporter is shutdown.
|
||||||
|
type fileExporter struct {
|
||||||
|
file *os.File
|
||||||
|
writerExporter *stdouttrace.Exporter
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ trace.SpanExporter = &fileExporter{}
|
||||||
|
|
||||||
|
func newFileExporter(file string) (*fileExporter, error) {
|
||||||
|
f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("opening %s: %w", file, err)
|
||||||
|
}
|
||||||
|
stdoutExporter, err := stdouttrace.New(stdouttrace.WithWriter(f))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &fileExporter{
|
||||||
|
writerExporter: stdoutExporter,
|
||||||
|
file: f,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *fileExporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {
|
||||||
|
return e.writerExporter.ExportSpans(ctx, spans)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *fileExporter) Shutdown(ctx context.Context) error {
|
||||||
|
if err := e.writerExporter.Shutdown(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := e.file.Close(); err != nil {
|
||||||
|
return fmt.Errorf("closing trace file: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// noopShutdownTracerProvider wraps a TracerProvider with a no-op Shutdown method.
|
||||||
|
type noopShutdownTracerProvider struct {
|
||||||
|
tp traceapi.TracerProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *noopShutdownTracerProvider) Shutdown(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (n *noopShutdownTracerProvider) Tracer(instrumentationName string, opts ...traceapi.TracerOption) traceapi.Tracer {
|
||||||
|
return n.tp.Tracer(instrumentationName, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShutdownTracerProvider interface {
|
||||||
|
traceapi.TracerProvider
|
||||||
|
Shutdown(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTracerProvider creates and configures a TracerProvider.
|
||||||
|
func NewTracerProvider(ctx context.Context) (ShutdownTracerProvider, error) {
|
||||||
|
if os.Getenv("IPFS_TRACING") == "" {
|
||||||
|
return &noopShutdownTracerProvider{tp: traceapi.NewNoopTracerProvider()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
options := []trace.TracerProviderOption{}
|
||||||
|
|
||||||
|
traceRatio := 1.0
|
||||||
|
if envRatio := os.Getenv("IPFS_TRACING_RATIO"); envRatio != "" {
|
||||||
|
r, err := strconv.ParseFloat(envRatio, 64)
|
||||||
|
if err == nil {
|
||||||
|
traceRatio = r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
options = append(options, trace.WithSampler(trace.ParentBased(trace.TraceIDRatioBased(traceRatio))))
|
||||||
|
|
||||||
|
r, err := resource.Merge(
|
||||||
|
resource.Default(),
|
||||||
|
resource.NewWithAttributes(
|
||||||
|
semconv.SchemaURL,
|
||||||
|
semconv.ServiceNameKey.String("go-ipfs"),
|
||||||
|
semconv.ServiceVersionKey.String(version.CurrentVersionNumber),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options = append(options, trace.WithResource(r))
|
||||||
|
|
||||||
|
for envVar, builder := range exporterBuilders {
|
||||||
|
if val := os.Getenv(envVar); val != "" {
|
||||||
|
exporter, err := builder(ctx, val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options = append(options, trace.WithBatcher(exporter))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return trace.NewTracerProvider(options...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Span starts a new span using the standard IPFS tracing conventions.
|
||||||
|
func Span(ctx context.Context, componentName string, spanName string, opts ...traceapi.SpanStartOption) (context.Context, traceapi.Span) {
|
||||||
|
return otel.Tracer("go-ipfs").Start(ctx, fmt.Sprintf("%s.%s", componentName, spanName), opts...)
|
||||||
|
}
|
Reference in New Issue
Block a user