swarm: initial instrumentation (#15969)
* swarm: initial instrumentation with go-metrics * swarm: initialise metrics collection and add ResettingTimer to HTTP requests * swarm: update metrics flags names. remove redundant Timer. * swarm: rename method for periodically updating gauges * swarm: finalise metrics after feedback * swarm/network: always init kad metrics containers * swarm/network: off-by-one index in metrics containers * swarm, metrics: resolved conflicts
This commit is contained in:
parent
b677a07d36
commit
dcca613a0b
@ -43,6 +43,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/swarm"
|
"github.com/ethereum/go-ethereum/swarm"
|
||||||
bzzapi "github.com/ethereum/go-ethereum/swarm/api"
|
bzzapi "github.com/ethereum/go-ethereum/swarm/api"
|
||||||
|
swarmmetrics "github.com/ethereum/go-ethereum/swarm/metrics"
|
||||||
|
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
@ -359,9 +360,14 @@ DEPRECATED: use 'swarm db clean'.
|
|||||||
DeprecatedEnsAddrFlag,
|
DeprecatedEnsAddrFlag,
|
||||||
}
|
}
|
||||||
app.Flags = append(app.Flags, debug.Flags...)
|
app.Flags = append(app.Flags, debug.Flags...)
|
||||||
|
app.Flags = append(app.Flags, swarmmetrics.Flags...)
|
||||||
app.Before = func(ctx *cli.Context) error {
|
app.Before = func(ctx *cli.Context) error {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
return debug.Setup(ctx)
|
if err := debug.Setup(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
swarmmetrics.Setup(ctx)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
app.After = func(ctx *cli.Context) error {
|
app.After = func(ctx *cli.Context) error {
|
||||||
debug.Exit()
|
debug.Exit()
|
||||||
|
@ -35,7 +35,6 @@ func init() {
|
|||||||
Enabled = true
|
Enabled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//exp.Exp(DefaultRegistry)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CollectProcessMetrics periodically collects various metrics about the running
|
// CollectProcessMetrics periodically collects various metrics about the running
|
||||||
|
@ -32,11 +32,31 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/swarm/storage"
|
"github.com/ethereum/go-ethereum/swarm/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
var hashMatcher = regexp.MustCompile("^[0-9A-Fa-f]{64}")
|
var hashMatcher = regexp.MustCompile("^[0-9A-Fa-f]{64}")
|
||||||
|
|
||||||
|
//setup metrics
|
||||||
|
var (
|
||||||
|
apiResolveCount = metrics.NewRegisteredCounter("api.resolve.count", nil)
|
||||||
|
apiResolveFail = metrics.NewRegisteredCounter("api.resolve.fail", nil)
|
||||||
|
apiPutCount = metrics.NewRegisteredCounter("api.put.count", nil)
|
||||||
|
apiPutFail = metrics.NewRegisteredCounter("api.put.fail", nil)
|
||||||
|
apiGetCount = metrics.NewRegisteredCounter("api.get.count", nil)
|
||||||
|
apiGetNotFound = metrics.NewRegisteredCounter("api.get.notfound", nil)
|
||||||
|
apiGetHttp300 = metrics.NewRegisteredCounter("api.get.http.300", nil)
|
||||||
|
apiModifyCount = metrics.NewRegisteredCounter("api.modify.count", nil)
|
||||||
|
apiModifyFail = metrics.NewRegisteredCounter("api.modify.fail", nil)
|
||||||
|
apiAddFileCount = metrics.NewRegisteredCounter("api.addfile.count", nil)
|
||||||
|
apiAddFileFail = metrics.NewRegisteredCounter("api.addfile.fail", nil)
|
||||||
|
apiRmFileCount = metrics.NewRegisteredCounter("api.removefile.count", nil)
|
||||||
|
apiRmFileFail = metrics.NewRegisteredCounter("api.removefile.fail", nil)
|
||||||
|
apiAppendFileCount = metrics.NewRegisteredCounter("api.appendfile.count", nil)
|
||||||
|
apiAppendFileFail = metrics.NewRegisteredCounter("api.appendfile.fail", nil)
|
||||||
|
)
|
||||||
|
|
||||||
type Resolver interface {
|
type Resolver interface {
|
||||||
Resolve(string) (common.Hash, error)
|
Resolve(string) (common.Hash, error)
|
||||||
}
|
}
|
||||||
@ -155,6 +175,7 @@ type ErrResolve error
|
|||||||
|
|
||||||
// DNS Resolver
|
// DNS Resolver
|
||||||
func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
||||||
|
apiResolveCount.Inc(1)
|
||||||
log.Trace(fmt.Sprintf("Resolving : %v", uri.Addr))
|
log.Trace(fmt.Sprintf("Resolving : %v", uri.Addr))
|
||||||
|
|
||||||
// if the URI is immutable, check if the address is a hash
|
// if the URI is immutable, check if the address is a hash
|
||||||
@ -169,6 +190,7 @@ func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
|||||||
// if DNS is not configured, check if the address is a hash
|
// if DNS is not configured, check if the address is a hash
|
||||||
if self.dns == nil {
|
if self.dns == nil {
|
||||||
if !isHash {
|
if !isHash {
|
||||||
|
apiResolveFail.Inc(1)
|
||||||
return nil, fmt.Errorf("no DNS to resolve name: %q", uri.Addr)
|
return nil, fmt.Errorf("no DNS to resolve name: %q", uri.Addr)
|
||||||
}
|
}
|
||||||
return common.Hex2Bytes(uri.Addr), nil
|
return common.Hex2Bytes(uri.Addr), nil
|
||||||
@ -179,6 +201,7 @@ func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return resolved[:], nil
|
return resolved[:], nil
|
||||||
} else if !isHash {
|
} else if !isHash {
|
||||||
|
apiResolveFail.Inc(1)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return common.Hex2Bytes(uri.Addr), nil
|
return common.Hex2Bytes(uri.Addr), nil
|
||||||
@ -186,16 +209,19 @@ func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
|||||||
|
|
||||||
// Put provides singleton manifest creation on top of dpa store
|
// Put provides singleton manifest creation on top of dpa store
|
||||||
func (self *Api) Put(content, contentType string) (storage.Key, error) {
|
func (self *Api) Put(content, contentType string) (storage.Key, error) {
|
||||||
|
apiPutCount.Inc(1)
|
||||||
r := strings.NewReader(content)
|
r := strings.NewReader(content)
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
key, err := self.dpa.Store(r, int64(len(content)), wg, nil)
|
key, err := self.dpa.Store(r, int64(len(content)), wg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiPutFail.Inc(1)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType)
|
manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType)
|
||||||
r = strings.NewReader(manifest)
|
r = strings.NewReader(manifest)
|
||||||
key, err = self.dpa.Store(r, int64(len(manifest)), wg, nil)
|
key, err = self.dpa.Store(r, int64(len(manifest)), wg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiPutFail.Inc(1)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
@ -206,8 +232,10 @@ func (self *Api) Put(content, contentType string) (storage.Key, error) {
|
|||||||
// to resolve basePath to content using dpa retrieve
|
// to resolve basePath to content using dpa retrieve
|
||||||
// it returns a section reader, mimeType, status and an error
|
// it returns a section reader, mimeType, status and an error
|
||||||
func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionReader, mimeType string, status int, err error) {
|
func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionReader, mimeType string, status int, err error) {
|
||||||
|
apiGetCount.Inc(1)
|
||||||
trie, err := loadManifest(self.dpa, key, nil)
|
trie, err := loadManifest(self.dpa, key, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiGetNotFound.Inc(1)
|
||||||
status = http.StatusNotFound
|
status = http.StatusNotFound
|
||||||
log.Warn(fmt.Sprintf("loadManifestTrie error: %v", err))
|
log.Warn(fmt.Sprintf("loadManifestTrie error: %v", err))
|
||||||
return
|
return
|
||||||
@ -221,6 +249,7 @@ func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionRe
|
|||||||
key = common.Hex2Bytes(entry.Hash)
|
key = common.Hex2Bytes(entry.Hash)
|
||||||
status = entry.Status
|
status = entry.Status
|
||||||
if status == http.StatusMultipleChoices {
|
if status == http.StatusMultipleChoices {
|
||||||
|
apiGetHttp300.Inc(1)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
mimeType = entry.ContentType
|
mimeType = entry.ContentType
|
||||||
@ -229,6 +258,7 @@ func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionRe
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
status = http.StatusNotFound
|
status = http.StatusNotFound
|
||||||
|
apiGetNotFound.Inc(1)
|
||||||
err = fmt.Errorf("manifest entry for '%s' not found", path)
|
err = fmt.Errorf("manifest entry for '%s' not found", path)
|
||||||
log.Warn(fmt.Sprintf("%v", err))
|
log.Warn(fmt.Sprintf("%v", err))
|
||||||
}
|
}
|
||||||
@ -236,9 +266,11 @@ func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) Modify(key storage.Key, path, contentHash, contentType string) (storage.Key, error) {
|
func (self *Api) Modify(key storage.Key, path, contentHash, contentType string) (storage.Key, error) {
|
||||||
|
apiModifyCount.Inc(1)
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
trie, err := loadManifest(self.dpa, key, quitC)
|
trie, err := loadManifest(self.dpa, key, quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiModifyFail.Inc(1)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if contentHash != "" {
|
if contentHash != "" {
|
||||||
@ -253,19 +285,23 @@ func (self *Api) Modify(key storage.Key, path, contentHash, contentType string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := trie.recalcAndStore(); err != nil {
|
if err := trie.recalcAndStore(); err != nil {
|
||||||
|
apiModifyFail.Inc(1)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return trie.hash, nil
|
return trie.hash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) AddFile(mhash, path, fname string, content []byte, nameresolver bool) (storage.Key, string, error) {
|
func (self *Api) AddFile(mhash, path, fname string, content []byte, nameresolver bool) (storage.Key, string, error) {
|
||||||
|
apiAddFileCount.Inc(1)
|
||||||
|
|
||||||
uri, err := Parse("bzz:/" + mhash)
|
uri, err := Parse("bzz:/" + mhash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiAddFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
mkey, err := self.Resolve(uri)
|
mkey, err := self.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiAddFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,16 +320,19 @@ func (self *Api) AddFile(mhash, path, fname string, content []byte, nameresolver
|
|||||||
|
|
||||||
mw, err := self.NewManifestWriter(mkey, nil)
|
mw, err := self.NewManifestWriter(mkey, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiAddFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
fkey, err := mw.AddEntry(bytes.NewReader(content), entry)
|
fkey, err := mw.AddEntry(bytes.NewReader(content), entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiAddFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
newMkey, err := mw.Store()
|
newMkey, err := mw.Store()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiAddFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -303,13 +342,16 @@ func (self *Api) AddFile(mhash, path, fname string, content []byte, nameresolver
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (string, error) {
|
func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (string, error) {
|
||||||
|
apiRmFileCount.Inc(1)
|
||||||
|
|
||||||
uri, err := Parse("bzz:/" + mhash)
|
uri, err := Parse("bzz:/" + mhash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiRmFileFail.Inc(1)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
mkey, err := self.Resolve(uri)
|
mkey, err := self.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiRmFileFail.Inc(1)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,16 +362,19 @@ func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (strin
|
|||||||
|
|
||||||
mw, err := self.NewManifestWriter(mkey, nil)
|
mw, err := self.NewManifestWriter(mkey, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiRmFileFail.Inc(1)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mw.RemoveEntry(filepath.Join(path, fname))
|
err = mw.RemoveEntry(filepath.Join(path, fname))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiRmFileFail.Inc(1)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
newMkey, err := mw.Store()
|
newMkey, err := mw.Store()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiRmFileFail.Inc(1)
|
||||||
return "", err
|
return "", err
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -338,6 +383,7 @@ func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, content []byte, oldKey storage.Key, offset int64, addSize int64, nameresolver bool) (storage.Key, string, error) {
|
func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, content []byte, oldKey storage.Key, offset int64, addSize int64, nameresolver bool) (storage.Key, string, error) {
|
||||||
|
apiAppendFileCount.Inc(1)
|
||||||
|
|
||||||
buffSize := offset + addSize
|
buffSize := offset + addSize
|
||||||
if buffSize < existingSize {
|
if buffSize < existingSize {
|
||||||
@ -366,10 +412,12 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
|||||||
|
|
||||||
uri, err := Parse("bzz:/" + mhash)
|
uri, err := Parse("bzz:/" + mhash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiAppendFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
mkey, err := self.Resolve(uri)
|
mkey, err := self.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiAppendFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,11 +428,13 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
|||||||
|
|
||||||
mw, err := self.NewManifestWriter(mkey, nil)
|
mw, err := self.NewManifestWriter(mkey, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiAppendFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mw.RemoveEntry(filepath.Join(path, fname))
|
err = mw.RemoveEntry(filepath.Join(path, fname))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiAppendFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,11 +448,13 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
|||||||
|
|
||||||
fkey, err := mw.AddEntry(io.Reader(combinedReader), entry)
|
fkey, err := mw.AddEntry(io.Reader(combinedReader), entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiAppendFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
newMkey, err := mw.Store()
|
newMkey, err := mw.Store()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
apiAppendFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -412,6 +464,7 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) BuildDirectoryTree(mhash string, nameresolver bool) (key storage.Key, manifestEntryMap map[string]*manifestTrieEntry, err error) {
|
func (self *Api) BuildDirectoryTree(mhash string, nameresolver bool) (key storage.Key, manifestEntryMap map[string]*manifestTrieEntry, err error) {
|
||||||
|
|
||||||
uri, err := Parse("bzz:/" + mhash)
|
uri, err := Parse("bzz:/" + mhash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
@ -29,12 +29,19 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/swarm/api"
|
"github.com/ethereum/go-ethereum/swarm/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
//templateMap holds a mapping of an HTTP error code to a template
|
//templateMap holds a mapping of an HTTP error code to a template
|
||||||
var templateMap map[int]*template.Template
|
var templateMap map[int]*template.Template
|
||||||
|
|
||||||
|
//metrics variables
|
||||||
|
var (
|
||||||
|
htmlCounter = metrics.NewRegisteredCounter("api.http.errorpage.html.count", nil)
|
||||||
|
jsonCounter = metrics.NewRegisteredCounter("api.http.errorpage.json.count", nil)
|
||||||
|
)
|
||||||
|
|
||||||
//parameters needed for formatting the correct HTML page
|
//parameters needed for formatting the correct HTML page
|
||||||
type ErrorParams struct {
|
type ErrorParams struct {
|
||||||
Msg string
|
Msg string
|
||||||
@ -132,6 +139,7 @@ func respond(w http.ResponseWriter, r *http.Request, params *ErrorParams) {
|
|||||||
|
|
||||||
//return a HTML page
|
//return a HTML page
|
||||||
func respondHtml(w http.ResponseWriter, params *ErrorParams) {
|
func respondHtml(w http.ResponseWriter, params *ErrorParams) {
|
||||||
|
htmlCounter.Inc(1)
|
||||||
err := params.template.Execute(w, params)
|
err := params.template.Execute(w, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err.Error())
|
log.Error(err.Error())
|
||||||
@ -140,6 +148,7 @@ func respondHtml(w http.ResponseWriter, params *ErrorParams) {
|
|||||||
|
|
||||||
//return JSON
|
//return JSON
|
||||||
func respondJson(w http.ResponseWriter, params *ErrorParams) {
|
func respondJson(w http.ResponseWriter, params *ErrorParams) {
|
||||||
|
jsonCounter.Inc(1)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(params)
|
json.NewEncoder(w).Encode(params)
|
||||||
}
|
}
|
||||||
|
@ -37,11 +37,35 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/swarm/api"
|
"github.com/ethereum/go-ethereum/swarm/api"
|
||||||
"github.com/ethereum/go-ethereum/swarm/storage"
|
"github.com/ethereum/go-ethereum/swarm/storage"
|
||||||
"github.com/rs/cors"
|
"github.com/rs/cors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//setup metrics
|
||||||
|
var (
|
||||||
|
postRawCount = metrics.NewRegisteredCounter("api.http.post.raw.count", nil)
|
||||||
|
postRawFail = metrics.NewRegisteredCounter("api.http.post.raw.fail", nil)
|
||||||
|
postFilesCount = metrics.NewRegisteredCounter("api.http.post.files.count", nil)
|
||||||
|
postFilesFail = metrics.NewRegisteredCounter("api.http.post.files.fail", nil)
|
||||||
|
deleteCount = metrics.NewRegisteredCounter("api.http.delete.count", nil)
|
||||||
|
deleteFail = metrics.NewRegisteredCounter("api.http.delete.fail", nil)
|
||||||
|
getCount = metrics.NewRegisteredCounter("api.http.get.count", nil)
|
||||||
|
getFail = metrics.NewRegisteredCounter("api.http.get.fail", nil)
|
||||||
|
getFileCount = metrics.NewRegisteredCounter("api.http.get.file.count", nil)
|
||||||
|
getFileNotFound = metrics.NewRegisteredCounter("api.http.get.file.notfound", nil)
|
||||||
|
getFileFail = metrics.NewRegisteredCounter("api.http.get.file.fail", nil)
|
||||||
|
getFilesCount = metrics.NewRegisteredCounter("api.http.get.files.count", nil)
|
||||||
|
getFilesFail = metrics.NewRegisteredCounter("api.http.get.files.fail", nil)
|
||||||
|
getListCount = metrics.NewRegisteredCounter("api.http.get.list.count", nil)
|
||||||
|
getListFail = metrics.NewRegisteredCounter("api.http.get.list.fail", nil)
|
||||||
|
requestCount = metrics.NewRegisteredCounter("http.request.count", nil)
|
||||||
|
htmlRequestCount = metrics.NewRegisteredCounter("http.request.html.count", nil)
|
||||||
|
jsonRequestCount = metrics.NewRegisteredCounter("http.request.json.count", nil)
|
||||||
|
requestTimer = metrics.NewRegisteredResettingTimer("http.request.time", nil)
|
||||||
|
)
|
||||||
|
|
||||||
// ServerConfig is the basic configuration needed for the HTTP server and also
|
// ServerConfig is the basic configuration needed for the HTTP server and also
|
||||||
// includes CORS settings.
|
// includes CORS settings.
|
||||||
type ServerConfig struct {
|
type ServerConfig struct {
|
||||||
@ -89,18 +113,22 @@ type Request struct {
|
|||||||
// HandlePostRaw handles a POST request to a raw bzz-raw:/ URI, stores the request
|
// HandlePostRaw handles a POST request to a raw bzz-raw:/ URI, stores the request
|
||||||
// body in swarm and returns the resulting storage key as a text/plain response
|
// body in swarm and returns the resulting storage key as a text/plain response
|
||||||
func (s *Server) HandlePostRaw(w http.ResponseWriter, r *Request) {
|
func (s *Server) HandlePostRaw(w http.ResponseWriter, r *Request) {
|
||||||
|
postRawCount.Inc(1)
|
||||||
if r.uri.Path != "" {
|
if r.uri.Path != "" {
|
||||||
|
postRawFail.Inc(1)
|
||||||
s.BadRequest(w, r, "raw POST request cannot contain a path")
|
s.BadRequest(w, r, "raw POST request cannot contain a path")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Header.Get("Content-Length") == "" {
|
if r.Header.Get("Content-Length") == "" {
|
||||||
|
postRawFail.Inc(1)
|
||||||
s.BadRequest(w, r, "missing Content-Length header in request")
|
s.BadRequest(w, r, "missing Content-Length header in request")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err := s.api.Store(r.Body, r.ContentLength, nil)
|
key, err := s.api.Store(r.Body, r.ContentLength, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
postRawFail.Inc(1)
|
||||||
s.Error(w, r, err)
|
s.Error(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -117,8 +145,10 @@ func (s *Server) HandlePostRaw(w http.ResponseWriter, r *Request) {
|
|||||||
// existing manifest or to a new manifest under <path> and returns the
|
// existing manifest or to a new manifest under <path> and returns the
|
||||||
// resulting manifest hash as a text/plain response
|
// resulting manifest hash as a text/plain response
|
||||||
func (s *Server) HandlePostFiles(w http.ResponseWriter, r *Request) {
|
func (s *Server) HandlePostFiles(w http.ResponseWriter, r *Request) {
|
||||||
|
postFilesCount.Inc(1)
|
||||||
contentType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
contentType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
postFilesFail.Inc(1)
|
||||||
s.BadRequest(w, r, err.Error())
|
s.BadRequest(w, r, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -127,12 +157,14 @@ func (s *Server) HandlePostFiles(w http.ResponseWriter, r *Request) {
|
|||||||
if r.uri.Addr != "" {
|
if r.uri.Addr != "" {
|
||||||
key, err = s.api.Resolve(r.uri)
|
key, err = s.api.Resolve(r.uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
postFilesFail.Inc(1)
|
||||||
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
|
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
key, err = s.api.NewManifest()
|
key, err = s.api.NewManifest()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
postFilesFail.Inc(1)
|
||||||
s.Error(w, r, err)
|
s.Error(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -152,6 +184,7 @@ func (s *Server) HandlePostFiles(w http.ResponseWriter, r *Request) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
postFilesFail.Inc(1)
|
||||||
s.Error(w, r, fmt.Errorf("error creating manifest: %s", err))
|
s.Error(w, r, fmt.Errorf("error creating manifest: %s", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -270,8 +303,10 @@ func (s *Server) handleDirectUpload(req *Request, mw *api.ManifestWriter) error
|
|||||||
// <path> from <manifest> and returns the resulting manifest hash as a
|
// <path> from <manifest> and returns the resulting manifest hash as a
|
||||||
// text/plain response
|
// text/plain response
|
||||||
func (s *Server) HandleDelete(w http.ResponseWriter, r *Request) {
|
func (s *Server) HandleDelete(w http.ResponseWriter, r *Request) {
|
||||||
|
deleteCount.Inc(1)
|
||||||
key, err := s.api.Resolve(r.uri)
|
key, err := s.api.Resolve(r.uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
deleteFail.Inc(1)
|
||||||
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
|
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -281,6 +316,7 @@ func (s *Server) HandleDelete(w http.ResponseWriter, r *Request) {
|
|||||||
return mw.RemoveEntry(r.uri.Path)
|
return mw.RemoveEntry(r.uri.Path)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
deleteFail.Inc(1)
|
||||||
s.Error(w, r, fmt.Errorf("error updating manifest: %s", err))
|
s.Error(w, r, fmt.Errorf("error updating manifest: %s", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -296,8 +332,10 @@ func (s *Server) HandleDelete(w http.ResponseWriter, r *Request) {
|
|||||||
// - bzz-hash://<key> and responds with the hash of the content stored
|
// - bzz-hash://<key> and responds with the hash of the content stored
|
||||||
// at the given storage key as a text/plain response
|
// at the given storage key as a text/plain response
|
||||||
func (s *Server) HandleGet(w http.ResponseWriter, r *Request) {
|
func (s *Server) HandleGet(w http.ResponseWriter, r *Request) {
|
||||||
|
getCount.Inc(1)
|
||||||
key, err := s.api.Resolve(r.uri)
|
key, err := s.api.Resolve(r.uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
getFail.Inc(1)
|
||||||
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
|
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -307,6 +345,7 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *Request) {
|
|||||||
if r.uri.Path != "" {
|
if r.uri.Path != "" {
|
||||||
walker, err := s.api.NewManifestWalker(key, nil)
|
walker, err := s.api.NewManifestWalker(key, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
getFail.Inc(1)
|
||||||
s.BadRequest(w, r, fmt.Sprintf("%s is not a manifest", key))
|
s.BadRequest(w, r, fmt.Sprintf("%s is not a manifest", key))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -335,6 +374,7 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *Request) {
|
|||||||
return api.SkipManifest
|
return api.SkipManifest
|
||||||
})
|
})
|
||||||
if entry == nil {
|
if entry == nil {
|
||||||
|
getFail.Inc(1)
|
||||||
s.NotFound(w, r, fmt.Errorf("Manifest entry could not be loaded"))
|
s.NotFound(w, r, fmt.Errorf("Manifest entry could not be loaded"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -344,6 +384,7 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *Request) {
|
|||||||
// check the root chunk exists by retrieving the file's size
|
// check the root chunk exists by retrieving the file's size
|
||||||
reader := s.api.Retrieve(key)
|
reader := s.api.Retrieve(key)
|
||||||
if _, err := reader.Size(nil); err != nil {
|
if _, err := reader.Size(nil); err != nil {
|
||||||
|
getFail.Inc(1)
|
||||||
s.NotFound(w, r, fmt.Errorf("Root chunk not found %s: %s", key, err))
|
s.NotFound(w, r, fmt.Errorf("Root chunk not found %s: %s", key, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -370,19 +411,23 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *Request) {
|
|||||||
// header of "application/x-tar" and returns a tar stream of all files
|
// header of "application/x-tar" and returns a tar stream of all files
|
||||||
// contained in the manifest
|
// contained in the manifest
|
||||||
func (s *Server) HandleGetFiles(w http.ResponseWriter, r *Request) {
|
func (s *Server) HandleGetFiles(w http.ResponseWriter, r *Request) {
|
||||||
|
getFilesCount.Inc(1)
|
||||||
if r.uri.Path != "" {
|
if r.uri.Path != "" {
|
||||||
|
getFilesFail.Inc(1)
|
||||||
s.BadRequest(w, r, "files request cannot contain a path")
|
s.BadRequest(w, r, "files request cannot contain a path")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err := s.api.Resolve(r.uri)
|
key, err := s.api.Resolve(r.uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
getFilesFail.Inc(1)
|
||||||
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
|
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
walker, err := s.api.NewManifestWalker(key, nil)
|
walker, err := s.api.NewManifestWalker(key, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
getFilesFail.Inc(1)
|
||||||
s.Error(w, r, err)
|
s.Error(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -430,6 +475,7 @@ func (s *Server) HandleGetFiles(w http.ResponseWriter, r *Request) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
getFilesFail.Inc(1)
|
||||||
s.logError("error generating tar stream: %s", err)
|
s.logError("error generating tar stream: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -438,6 +484,7 @@ func (s *Server) HandleGetFiles(w http.ResponseWriter, r *Request) {
|
|||||||
// a list of all files contained in <manifest> under <path> grouped into
|
// a list of all files contained in <manifest> under <path> grouped into
|
||||||
// common prefixes using "/" as a delimiter
|
// common prefixes using "/" as a delimiter
|
||||||
func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) {
|
func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) {
|
||||||
|
getListCount.Inc(1)
|
||||||
// ensure the root path has a trailing slash so that relative URLs work
|
// ensure the root path has a trailing slash so that relative URLs work
|
||||||
if r.uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") {
|
if r.uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") {
|
||||||
http.Redirect(w, &r.Request, r.URL.Path+"/", http.StatusMovedPermanently)
|
http.Redirect(w, &r.Request, r.URL.Path+"/", http.StatusMovedPermanently)
|
||||||
@ -446,6 +493,7 @@ func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) {
|
|||||||
|
|
||||||
key, err := s.api.Resolve(r.uri)
|
key, err := s.api.Resolve(r.uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
getListFail.Inc(1)
|
||||||
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
|
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -453,6 +501,7 @@ func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) {
|
|||||||
list, err := s.getManifestList(key, r.uri.Path)
|
list, err := s.getManifestList(key, r.uri.Path)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
getListFail.Inc(1)
|
||||||
s.Error(w, r, err)
|
s.Error(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -470,6 +519,7 @@ func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) {
|
|||||||
List: &list,
|
List: &list,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
getListFail.Inc(1)
|
||||||
s.logError("error rendering list HTML: %s", err)
|
s.logError("error rendering list HTML: %s", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -538,6 +588,7 @@ func (s *Server) getManifestList(key storage.Key, prefix string) (list api.Manif
|
|||||||
// HandleGetFile handles a GET request to bzz://<manifest>/<path> and responds
|
// HandleGetFile handles a GET request to bzz://<manifest>/<path> and responds
|
||||||
// with the content of the file at <path> from the given <manifest>
|
// with the content of the file at <path> from the given <manifest>
|
||||||
func (s *Server) HandleGetFile(w http.ResponseWriter, r *Request) {
|
func (s *Server) HandleGetFile(w http.ResponseWriter, r *Request) {
|
||||||
|
getFileCount.Inc(1)
|
||||||
// ensure the root path has a trailing slash so that relative URLs work
|
// ensure the root path has a trailing slash so that relative URLs work
|
||||||
if r.uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") {
|
if r.uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") {
|
||||||
http.Redirect(w, &r.Request, r.URL.Path+"/", http.StatusMovedPermanently)
|
http.Redirect(w, &r.Request, r.URL.Path+"/", http.StatusMovedPermanently)
|
||||||
@ -546,6 +597,7 @@ func (s *Server) HandleGetFile(w http.ResponseWriter, r *Request) {
|
|||||||
|
|
||||||
key, err := s.api.Resolve(r.uri)
|
key, err := s.api.Resolve(r.uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
getFileFail.Inc(1)
|
||||||
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
|
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -554,8 +606,10 @@ func (s *Server) HandleGetFile(w http.ResponseWriter, r *Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
switch status {
|
switch status {
|
||||||
case http.StatusNotFound:
|
case http.StatusNotFound:
|
||||||
|
getFileNotFound.Inc(1)
|
||||||
s.NotFound(w, r, err)
|
s.NotFound(w, r, err)
|
||||||
default:
|
default:
|
||||||
|
getFileFail.Inc(1)
|
||||||
s.Error(w, r, err)
|
s.Error(w, r, err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -567,6 +621,7 @@ func (s *Server) HandleGetFile(w http.ResponseWriter, r *Request) {
|
|||||||
list, err := s.getManifestList(key, r.uri.Path)
|
list, err := s.getManifestList(key, r.uri.Path)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
getFileFail.Inc(1)
|
||||||
s.Error(w, r, err)
|
s.Error(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -579,6 +634,7 @@ func (s *Server) HandleGetFile(w http.ResponseWriter, r *Request) {
|
|||||||
|
|
||||||
// check the root chunk exists by retrieving the file's size
|
// check the root chunk exists by retrieving the file's size
|
||||||
if _, err := reader.Size(nil); err != nil {
|
if _, err := reader.Size(nil); err != nil {
|
||||||
|
getFileNotFound.Inc(1)
|
||||||
s.NotFound(w, r, fmt.Errorf("File not found %s: %s", r.uri, err))
|
s.NotFound(w, r, fmt.Errorf("File not found %s: %s", r.uri, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -589,6 +645,19 @@ func (s *Server) HandleGetFile(w http.ResponseWriter, r *Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if metrics.Enabled {
|
||||||
|
//The increment for request count and request timer themselves have a flag check
|
||||||
|
//for metrics.Enabled. Nevertheless, we introduce the if here because we
|
||||||
|
//are looking into the header just to see what request type it is (json/html).
|
||||||
|
//So let's take advantage and add all metrics related stuff here
|
||||||
|
requestCount.Inc(1)
|
||||||
|
defer requestTimer.UpdateSince(time.Now())
|
||||||
|
if r.Header.Get("Accept") == "application/json" {
|
||||||
|
jsonRequestCount.Inc(1)
|
||||||
|
} else {
|
||||||
|
htmlRequestCount.Inc(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
s.logDebug("HTTP %s request URL: '%s', Host: '%s', Path: '%s', Referer: '%s', Accept: '%s'", r.Method, r.RequestURI, r.URL.Host, r.URL.Path, r.Referer(), r.Header.Get("Accept"))
|
s.logDebug("HTTP %s request URL: '%s', Host: '%s', Path: '%s', Referer: '%s', Accept: '%s'", r.Method, r.RequestURI, r.URL.Host, r.URL.Path, r.Referer(), r.Header.Get("Accept"))
|
||||||
|
|
||||||
uri, err := api.Parse(strings.TrimLeft(r.URL.Path, "/"))
|
uri, err := api.Parse(strings.TrimLeft(r.URL.Path, "/"))
|
||||||
|
@ -47,7 +47,6 @@ func externalUnmount(mountPoint string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addFileToSwarm(sf *SwarmFile, content []byte, size int) error {
|
func addFileToSwarm(sf *SwarmFile, content []byte, size int) error {
|
||||||
|
|
||||||
fkey, mhash, err := sf.mountInfo.swarmApi.AddFile(sf.mountInfo.LatestManifest, sf.path, sf.name, content, true)
|
fkey, mhash, err := sf.mountInfo.swarmApi.AddFile(sf.mountInfo.LatestManifest, sf.path, sf.name, content, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -64,11 +63,9 @@ func addFileToSwarm(sf *SwarmFile, content []byte, size int) error {
|
|||||||
|
|
||||||
log.Info("Added new file:", "fname", sf.name, "New Manifest hash", mhash)
|
log.Info("Added new file:", "fname", sf.name, "New Manifest hash", mhash)
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeFileFromSwarm(sf *SwarmFile) error {
|
func removeFileFromSwarm(sf *SwarmFile) error {
|
||||||
|
|
||||||
mkey, err := sf.mountInfo.swarmApi.RemoveFile(sf.mountInfo.LatestManifest, sf.path, sf.name, true)
|
mkey, err := sf.mountInfo.swarmApi.RemoveFile(sf.mountInfo.LatestManifest, sf.path, sf.name, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -83,7 +80,6 @@ func removeFileFromSwarm(sf *SwarmFile) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func removeDirectoryFromSwarm(sd *SwarmDir) error {
|
func removeDirectoryFromSwarm(sd *SwarmDir) error {
|
||||||
|
|
||||||
if len(sd.directories) == 0 && len(sd.files) == 0 {
|
if len(sd.directories) == 0 && len(sd.files) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -103,11 +99,9 @@ func removeDirectoryFromSwarm(sd *SwarmDir) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendToExistingFileInSwarm(sf *SwarmFile, content []byte, offset int64, length int64) error {
|
func appendToExistingFileInSwarm(sf *SwarmFile, content []byte, offset int64, length int64) error {
|
||||||
|
|
||||||
fkey, mhash, err := sf.mountInfo.swarmApi.AppendFile(sf.mountInfo.LatestManifest, sf.path, sf.name, sf.fileSize, content, sf.key, offset, length, true)
|
fkey, mhash, err := sf.mountInfo.swarmApi.AppendFile(sf.mountInfo.LatestManifest, sf.path, sf.name, sf.fileSize, content, sf.key, offset, length, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -124,5 +118,4 @@ func appendToExistingFileInSwarm(sf *SwarmFile, content []byte, offset int64, le
|
|||||||
|
|
||||||
log.Info("Appended file:", "fname", sf.name, "New Manifest hash", mhash)
|
log.Info("Appended file:", "fname", sf.name, "New Manifest hash", mhash)
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
82
swarm/metrics/flags.go
Normal file
82
swarm/metrics/flags.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// Copyright 2018 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
gethmetrics "github.com/ethereum/go-ethereum/metrics"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics/influxdb"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
metricsInfluxDBEndpointFlag = cli.StringFlag{
|
||||||
|
Name: "metrics.influxdb.endpoint",
|
||||||
|
Usage: "Metrics InfluxDB endpoint",
|
||||||
|
Value: "http://127.0.0.1:8086",
|
||||||
|
}
|
||||||
|
metricsInfluxDBDatabaseFlag = cli.StringFlag{
|
||||||
|
Name: "metrics.influxdb.database",
|
||||||
|
Usage: "metrics InfluxDB database",
|
||||||
|
Value: "metrics",
|
||||||
|
}
|
||||||
|
metricsInfluxDBUsernameFlag = cli.StringFlag{
|
||||||
|
Name: "metrics.influxdb.username",
|
||||||
|
Usage: "metrics InfluxDB username",
|
||||||
|
Value: "",
|
||||||
|
}
|
||||||
|
metricsInfluxDBPasswordFlag = cli.StringFlag{
|
||||||
|
Name: "metrics.influxdb.password",
|
||||||
|
Usage: "metrics InfluxDB password",
|
||||||
|
Value: "",
|
||||||
|
}
|
||||||
|
// The `host` tag is part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB.
|
||||||
|
// It is used so that we can group all nodes and average a measurement across all of them, but also so
|
||||||
|
// that we can select a specific node and inspect its measurements.
|
||||||
|
// https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key
|
||||||
|
metricsInfluxDBHostTagFlag = cli.StringFlag{
|
||||||
|
Name: "metrics.influxdb.host.tag",
|
||||||
|
Usage: "metrics InfluxDB `host` tag attached to all measurements",
|
||||||
|
Value: "localhost",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Flags holds all command-line flags required for metrics collection.
|
||||||
|
var Flags = []cli.Flag{
|
||||||
|
utils.MetricsEnabledFlag,
|
||||||
|
metricsInfluxDBEndpointFlag, metricsInfluxDBDatabaseFlag, metricsInfluxDBUsernameFlag, metricsInfluxDBPasswordFlag, metricsInfluxDBHostTagFlag,
|
||||||
|
}
|
||||||
|
|
||||||
|
func Setup(ctx *cli.Context) {
|
||||||
|
if gethmetrics.Enabled {
|
||||||
|
var (
|
||||||
|
endpoint = ctx.GlobalString(metricsInfluxDBEndpointFlag.Name)
|
||||||
|
database = ctx.GlobalString(metricsInfluxDBDatabaseFlag.Name)
|
||||||
|
username = ctx.GlobalString(metricsInfluxDBUsernameFlag.Name)
|
||||||
|
password = ctx.GlobalString(metricsInfluxDBPasswordFlag.Name)
|
||||||
|
hosttag = ctx.GlobalString(metricsInfluxDBHostTagFlag.Name)
|
||||||
|
)
|
||||||
|
|
||||||
|
log.Info("Enabling swarm metrics collection and export")
|
||||||
|
go influxdb.InfluxDBWithTags(gethmetrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "swarm.", map[string]string{
|
||||||
|
"host": hosttag,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -23,9 +23,19 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/swarm/storage"
|
"github.com/ethereum/go-ethereum/swarm/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//metrics variables
|
||||||
|
var (
|
||||||
|
syncReceiveCount = metrics.NewRegisteredCounter("network.sync.recv.count", nil)
|
||||||
|
syncReceiveIgnore = metrics.NewRegisteredCounter("network.sync.recv.ignore", nil)
|
||||||
|
syncSendCount = metrics.NewRegisteredCounter("network.sync.send.count", nil)
|
||||||
|
syncSendRefused = metrics.NewRegisteredCounter("network.sync.send.refused", nil)
|
||||||
|
syncSendNotFound = metrics.NewRegisteredCounter("network.sync.send.notfound", nil)
|
||||||
|
)
|
||||||
|
|
||||||
// Handler for storage/retrieval related protocol requests
|
// Handler for storage/retrieval related protocol requests
|
||||||
// implements the StorageHandler interface used by the bzz protocol
|
// implements the StorageHandler interface used by the bzz protocol
|
||||||
type Depo struct {
|
type Depo struct {
|
||||||
@ -107,6 +117,7 @@ func (self *Depo) HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) {
|
|||||||
log.Trace(fmt.Sprintf("Depo.handleStoreRequest: %v not found locally. create new chunk/request", req.Key))
|
log.Trace(fmt.Sprintf("Depo.handleStoreRequest: %v not found locally. create new chunk/request", req.Key))
|
||||||
// not found in memory cache, ie., a genuine store request
|
// not found in memory cache, ie., a genuine store request
|
||||||
// create chunk
|
// create chunk
|
||||||
|
syncReceiveCount.Inc(1)
|
||||||
chunk = storage.NewChunk(req.Key, nil)
|
chunk = storage.NewChunk(req.Key, nil)
|
||||||
|
|
||||||
case chunk.SData == nil:
|
case chunk.SData == nil:
|
||||||
@ -116,6 +127,7 @@ func (self *Depo) HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) {
|
|||||||
default:
|
default:
|
||||||
// data is found, store request ignored
|
// data is found, store request ignored
|
||||||
// this should update access count?
|
// this should update access count?
|
||||||
|
syncReceiveIgnore.Inc(1)
|
||||||
log.Trace(fmt.Sprintf("Depo.HandleStoreRequest: %v found locally. ignore.", req))
|
log.Trace(fmt.Sprintf("Depo.HandleStoreRequest: %v found locally. ignore.", req))
|
||||||
islocal = true
|
islocal = true
|
||||||
//return
|
//return
|
||||||
@ -172,11 +184,14 @@ func (self *Depo) HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer)
|
|||||||
SData: chunk.SData,
|
SData: chunk.SData,
|
||||||
requestTimeout: req.timeout, //
|
requestTimeout: req.timeout, //
|
||||||
}
|
}
|
||||||
|
syncSendCount.Inc(1)
|
||||||
p.syncer.addRequest(sreq, DeliverReq)
|
p.syncer.addRequest(sreq, DeliverReq)
|
||||||
} else {
|
} else {
|
||||||
|
syncSendRefused.Inc(1)
|
||||||
log.Trace(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - content found, not wanted", req.Key.Log()))
|
log.Trace(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - content found, not wanted", req.Key.Log()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
syncSendNotFound.Inc(1)
|
||||||
log.Trace(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - content not found locally. asked swarm for help. will get back", req.Key.Log()))
|
log.Trace(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - content not found locally. asked swarm for help. will get back", req.Key.Log()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
"github.com/ethereum/go-ethereum/p2p/netutil"
|
"github.com/ethereum/go-ethereum/p2p/netutil"
|
||||||
"github.com/ethereum/go-ethereum/swarm/network/kademlia"
|
"github.com/ethereum/go-ethereum/swarm/network/kademlia"
|
||||||
@ -39,6 +40,12 @@ import (
|
|||||||
// connections and disconnections are reported and relayed
|
// connections and disconnections are reported and relayed
|
||||||
// to keep the nodetable uptodate
|
// to keep the nodetable uptodate
|
||||||
|
|
||||||
|
var (
|
||||||
|
peersNumGauge = metrics.NewRegisteredGauge("network.peers.num", nil)
|
||||||
|
addPeerCounter = metrics.NewRegisteredCounter("network.addpeer.count", nil)
|
||||||
|
removePeerCounter = metrics.NewRegisteredCounter("network.removepeer.count", nil)
|
||||||
|
)
|
||||||
|
|
||||||
type Hive struct {
|
type Hive struct {
|
||||||
listenAddr func() string
|
listenAddr func() string
|
||||||
callInterval uint64
|
callInterval uint64
|
||||||
@ -192,6 +199,7 @@ func (self *Hive) Start(id discover.NodeID, listenAddr func() string, connectPee
|
|||||||
func (self *Hive) keepAlive() {
|
func (self *Hive) keepAlive() {
|
||||||
alarm := time.NewTicker(time.Duration(self.callInterval)).C
|
alarm := time.NewTicker(time.Duration(self.callInterval)).C
|
||||||
for {
|
for {
|
||||||
|
peersNumGauge.Update(int64(self.kad.Count()))
|
||||||
select {
|
select {
|
||||||
case <-alarm:
|
case <-alarm:
|
||||||
if self.kad.DBCount() > 0 {
|
if self.kad.DBCount() > 0 {
|
||||||
@ -223,6 +231,7 @@ func (self *Hive) Stop() error {
|
|||||||
|
|
||||||
// called at the end of a successful protocol handshake
|
// called at the end of a successful protocol handshake
|
||||||
func (self *Hive) addPeer(p *peer) error {
|
func (self *Hive) addPeer(p *peer) error {
|
||||||
|
addPeerCounter.Inc(1)
|
||||||
defer func() {
|
defer func() {
|
||||||
select {
|
select {
|
||||||
case self.more <- true:
|
case self.more <- true:
|
||||||
@ -247,6 +256,7 @@ func (self *Hive) addPeer(p *peer) error {
|
|||||||
|
|
||||||
// called after peer disconnected
|
// called after peer disconnected
|
||||||
func (self *Hive) removePeer(p *peer) {
|
func (self *Hive) removePeer(p *peer) {
|
||||||
|
removePeerCounter.Inc(1)
|
||||||
log.Debug(fmt.Sprintf("bee %v removed", p))
|
log.Debug(fmt.Sprintf("bee %v removed", p))
|
||||||
self.kad.Off(p, saveSync)
|
self.kad.Off(p, saveSync)
|
||||||
select {
|
select {
|
||||||
|
@ -24,6 +24,16 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
//metrics variables
|
||||||
|
//For metrics, we want to count how many times peers are added/removed
|
||||||
|
//at a certain index. Thus we do that with an array of counters with
|
||||||
|
//entry for each index
|
||||||
|
var (
|
||||||
|
bucketAddIndexCount []metrics.Counter
|
||||||
|
bucketRmIndexCount []metrics.Counter
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -88,12 +98,14 @@ type Node interface {
|
|||||||
// params is KadParams configuration
|
// params is KadParams configuration
|
||||||
func New(addr Address, params *KadParams) *Kademlia {
|
func New(addr Address, params *KadParams) *Kademlia {
|
||||||
buckets := make([][]Node, params.MaxProx+1)
|
buckets := make([][]Node, params.MaxProx+1)
|
||||||
return &Kademlia{
|
kad := &Kademlia{
|
||||||
addr: addr,
|
addr: addr,
|
||||||
KadParams: params,
|
KadParams: params,
|
||||||
buckets: buckets,
|
buckets: buckets,
|
||||||
db: newKadDb(addr, params),
|
db: newKadDb(addr, params),
|
||||||
}
|
}
|
||||||
|
kad.initMetricsVariables()
|
||||||
|
return kad
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessor for KAD base address
|
// accessor for KAD base address
|
||||||
@ -138,6 +150,7 @@ func (self *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error
|
|||||||
// TODO: give priority to peers with active traffic
|
// TODO: give priority to peers with active traffic
|
||||||
if len(bucket) < self.BucketSize { // >= allows us to add peers beyond the bucketsize limitation
|
if len(bucket) < self.BucketSize { // >= allows us to add peers beyond the bucketsize limitation
|
||||||
self.buckets[index] = append(bucket, node)
|
self.buckets[index] = append(bucket, node)
|
||||||
|
bucketAddIndexCount[index].Inc(1)
|
||||||
log.Debug(fmt.Sprintf("add node %v to table", node))
|
log.Debug(fmt.Sprintf("add node %v to table", node))
|
||||||
self.setProxLimit(index, true)
|
self.setProxLimit(index, true)
|
||||||
record.node = node
|
record.node = node
|
||||||
@ -178,6 +191,7 @@ func (self *Kademlia) Off(node Node, cb func(*NodeRecord, Node)) (err error) {
|
|||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
|
|
||||||
index := self.proximityBin(node.Addr())
|
index := self.proximityBin(node.Addr())
|
||||||
|
bucketRmIndexCount[index].Inc(1)
|
||||||
bucket := self.buckets[index]
|
bucket := self.buckets[index]
|
||||||
for i := 0; i < len(bucket); i++ {
|
for i := 0; i < len(bucket); i++ {
|
||||||
if node.Addr() == bucket[i].Addr() {
|
if node.Addr() == bucket[i].Addr() {
|
||||||
@ -426,3 +440,15 @@ func (self *Kademlia) String() string {
|
|||||||
rows = append(rows, "=========================================================================")
|
rows = append(rows, "=========================================================================")
|
||||||
return strings.Join(rows, "\n")
|
return strings.Join(rows, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//We have to build up the array of counters for each index
|
||||||
|
func (self *Kademlia) initMetricsVariables() {
|
||||||
|
//create the arrays
|
||||||
|
bucketAddIndexCount = make([]metrics.Counter, self.MaxProx+1)
|
||||||
|
bucketRmIndexCount = make([]metrics.Counter, self.MaxProx+1)
|
||||||
|
//at each index create a metrics counter
|
||||||
|
for i := 0; i < (self.KadParams.MaxProx + 1); i++ {
|
||||||
|
bucketAddIndexCount[i] = metrics.NewRegisteredCounter(fmt.Sprintf("network.kademlia.bucket.add.%d.index", i), nil)
|
||||||
|
bucketRmIndexCount[i] = metrics.NewRegisteredCounter(fmt.Sprintf("network.kademlia.bucket.rm.%d.index", i), nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -39,12 +39,26 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/contracts/chequebook"
|
"github.com/ethereum/go-ethereum/contracts/chequebook"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
bzzswap "github.com/ethereum/go-ethereum/swarm/services/swap"
|
bzzswap "github.com/ethereum/go-ethereum/swarm/services/swap"
|
||||||
"github.com/ethereum/go-ethereum/swarm/services/swap/swap"
|
"github.com/ethereum/go-ethereum/swarm/services/swap/swap"
|
||||||
"github.com/ethereum/go-ethereum/swarm/storage"
|
"github.com/ethereum/go-ethereum/swarm/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//metrics variables
|
||||||
|
var (
|
||||||
|
storeRequestMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.storerequest.count", nil)
|
||||||
|
retrieveRequestMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.retrieverequest.count", nil)
|
||||||
|
peersMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.peers.count", nil)
|
||||||
|
syncRequestMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.syncrequest.count", nil)
|
||||||
|
unsyncedKeysMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.unsyncedkeys.count", nil)
|
||||||
|
deliverRequestMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.deliverrequest.count", nil)
|
||||||
|
paymentMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.payment.count", nil)
|
||||||
|
invalidMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.invalid.count", nil)
|
||||||
|
handleStatusMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.handlestatus.count", nil)
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = 0
|
Version = 0
|
||||||
ProtocolLength = uint64(8)
|
ProtocolLength = uint64(8)
|
||||||
@ -206,6 +220,7 @@ func (self *bzz) handle() error {
|
|||||||
|
|
||||||
case storeRequestMsg:
|
case storeRequestMsg:
|
||||||
// store requests are dispatched to netStore
|
// store requests are dispatched to netStore
|
||||||
|
storeRequestMsgCounter.Inc(1)
|
||||||
var req storeRequestMsgData
|
var req storeRequestMsgData
|
||||||
if err := msg.Decode(&req); err != nil {
|
if err := msg.Decode(&req); err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
@ -221,6 +236,7 @@ func (self *bzz) handle() error {
|
|||||||
|
|
||||||
case retrieveRequestMsg:
|
case retrieveRequestMsg:
|
||||||
// retrieve Requests are dispatched to netStore
|
// retrieve Requests are dispatched to netStore
|
||||||
|
retrieveRequestMsgCounter.Inc(1)
|
||||||
var req retrieveRequestMsgData
|
var req retrieveRequestMsgData
|
||||||
if err := msg.Decode(&req); err != nil {
|
if err := msg.Decode(&req); err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
@ -241,6 +257,7 @@ func (self *bzz) handle() error {
|
|||||||
case peersMsg:
|
case peersMsg:
|
||||||
// response to lookups and immediate response to retrieve requests
|
// response to lookups and immediate response to retrieve requests
|
||||||
// dispatches new peer data to the hive that adds them to KADDB
|
// dispatches new peer data to the hive that adds them to KADDB
|
||||||
|
peersMsgCounter.Inc(1)
|
||||||
var req peersMsgData
|
var req peersMsgData
|
||||||
if err := msg.Decode(&req); err != nil {
|
if err := msg.Decode(&req); err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
@ -250,6 +267,7 @@ func (self *bzz) handle() error {
|
|||||||
self.hive.HandlePeersMsg(&req, &peer{bzz: self})
|
self.hive.HandlePeersMsg(&req, &peer{bzz: self})
|
||||||
|
|
||||||
case syncRequestMsg:
|
case syncRequestMsg:
|
||||||
|
syncRequestMsgCounter.Inc(1)
|
||||||
var req syncRequestMsgData
|
var req syncRequestMsgData
|
||||||
if err := msg.Decode(&req); err != nil {
|
if err := msg.Decode(&req); err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
@ -260,6 +278,7 @@ func (self *bzz) handle() error {
|
|||||||
|
|
||||||
case unsyncedKeysMsg:
|
case unsyncedKeysMsg:
|
||||||
// coming from parent node offering
|
// coming from parent node offering
|
||||||
|
unsyncedKeysMsgCounter.Inc(1)
|
||||||
var req unsyncedKeysMsgData
|
var req unsyncedKeysMsgData
|
||||||
if err := msg.Decode(&req); err != nil {
|
if err := msg.Decode(&req); err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
@ -274,6 +293,7 @@ func (self *bzz) handle() error {
|
|||||||
case deliveryRequestMsg:
|
case deliveryRequestMsg:
|
||||||
// response to syncKeysMsg hashes filtered not existing in db
|
// response to syncKeysMsg hashes filtered not existing in db
|
||||||
// also relays the last synced state to the source
|
// also relays the last synced state to the source
|
||||||
|
deliverRequestMsgCounter.Inc(1)
|
||||||
var req deliveryRequestMsgData
|
var req deliveryRequestMsgData
|
||||||
if err := msg.Decode(&req); err != nil {
|
if err := msg.Decode(&req); err != nil {
|
||||||
return fmt.Errorf("<-msg %v: %v", msg, err)
|
return fmt.Errorf("<-msg %v: %v", msg, err)
|
||||||
@ -287,6 +307,7 @@ func (self *bzz) handle() error {
|
|||||||
|
|
||||||
case paymentMsg:
|
case paymentMsg:
|
||||||
// swap protocol message for payment, Units paid for, Cheque paid with
|
// swap protocol message for payment, Units paid for, Cheque paid with
|
||||||
|
paymentMsgCounter.Inc(1)
|
||||||
if self.swapEnabled {
|
if self.swapEnabled {
|
||||||
var req paymentMsgData
|
var req paymentMsgData
|
||||||
if err := msg.Decode(&req); err != nil {
|
if err := msg.Decode(&req); err != nil {
|
||||||
@ -298,6 +319,7 @@ func (self *bzz) handle() error {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
// no other message is allowed
|
// no other message is allowed
|
||||||
|
invalidMsgCounter.Inc(1)
|
||||||
return fmt.Errorf("invalid message code: %v", msg.Code)
|
return fmt.Errorf("invalid message code: %v", msg.Code)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -332,6 +354,8 @@ func (self *bzz) handleStatus() (err error) {
|
|||||||
return fmt.Errorf("first msg has code %x (!= %x)", msg.Code, statusMsg)
|
return fmt.Errorf("first msg has code %x (!= %x)", msg.Code, statusMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleStatusMsgCounter.Inc(1)
|
||||||
|
|
||||||
if msg.Size > ProtocolMaxMsgSize {
|
if msg.Size > ProtocolMaxMsgSize {
|
||||||
return fmt.Errorf("message too long: %v > %v", msg.Size, ProtocolMaxMsgSize)
|
return fmt.Errorf("message too long: %v > %v", msg.Size, ProtocolMaxMsgSize)
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -63,6 +65,11 @@ var (
|
|||||||
errOperationTimedOut = errors.New("operation timed out")
|
errOperationTimedOut = errors.New("operation timed out")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//metrics variables
|
||||||
|
var (
|
||||||
|
newChunkCounter = metrics.NewRegisteredCounter("storage.chunks.new", nil)
|
||||||
|
)
|
||||||
|
|
||||||
type TreeChunker struct {
|
type TreeChunker struct {
|
||||||
branches int64
|
branches int64
|
||||||
hashFunc SwarmHasher
|
hashFunc SwarmHasher
|
||||||
@ -298,6 +305,13 @@ func (self *TreeChunker) hashChunk(hasher SwarmHash, job *hashJob, chunkC chan *
|
|||||||
job.parentWg.Done()
|
job.parentWg.Done()
|
||||||
|
|
||||||
if chunkC != nil {
|
if chunkC != nil {
|
||||||
|
//NOTE: this increases the chunk count even if the local node already has this chunk;
|
||||||
|
//on file upload the node will increase this counter even if the same file has already been uploaded
|
||||||
|
//So it should be evaluated whether it is worth keeping this counter
|
||||||
|
//and/or actually better track when the chunk is Put to the local database
|
||||||
|
//(which may question the need for disambiguation when a completely new chunk has been created
|
||||||
|
//and/or a chunk is being put to the local DB; for chunk tracking it may be worth distinguishing
|
||||||
|
newChunkCounter.Inc(1)
|
||||||
chunkC <- newChunk
|
chunkC <- newChunk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,18 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
"github.com/syndtr/goleveldb/leveldb/iterator"
|
"github.com/syndtr/goleveldb/leveldb/iterator"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//metrics variables
|
||||||
|
var (
|
||||||
|
gcCounter = metrics.NewRegisteredCounter("storage.db.dbstore.gc.count", nil)
|
||||||
|
dbStoreDeleteCounter = metrics.NewRegisteredCounter("storage.db.dbstore.rm.count", nil)
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultDbCapacity = 5000000
|
defaultDbCapacity = 5000000
|
||||||
defaultRadius = 0 // not yet used
|
defaultRadius = 0 // not yet used
|
||||||
@ -255,6 +262,7 @@ func (s *DbStore) collectGarbage(ratio float32) {
|
|||||||
// actual gc
|
// actual gc
|
||||||
for i := 0; i < gcnt; i++ {
|
for i := 0; i < gcnt; i++ {
|
||||||
if s.gcArray[i].value <= cutval {
|
if s.gcArray[i].value <= cutval {
|
||||||
|
gcCounter.Inc(1)
|
||||||
s.delete(s.gcArray[i].idx, s.gcArray[i].idxKey)
|
s.delete(s.gcArray[i].idx, s.gcArray[i].idxKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -383,6 +391,7 @@ func (s *DbStore) delete(idx uint64, idxKey []byte) {
|
|||||||
batch := new(leveldb.Batch)
|
batch := new(leveldb.Batch)
|
||||||
batch.Delete(idxKey)
|
batch.Delete(idxKey)
|
||||||
batch.Delete(getDataKey(idx))
|
batch.Delete(getDataKey(idx))
|
||||||
|
dbStoreDeleteCounter.Inc(1)
|
||||||
s.entryCnt--
|
s.entryCnt--
|
||||||
batch.Put(keyEntryCnt, U64ToBytes(s.entryCnt))
|
batch.Put(keyEntryCnt, U64ToBytes(s.entryCnt))
|
||||||
s.db.Write(batch)
|
s.db.Write(batch)
|
||||||
|
@ -18,6 +18,13 @@ package storage
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
//metrics variables
|
||||||
|
var (
|
||||||
|
dbStorePutCounter = metrics.NewRegisteredCounter("storage.db.dbstore.put.count", nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// LocalStore is a combination of inmemory db over a disk persisted db
|
// LocalStore is a combination of inmemory db over a disk persisted db
|
||||||
@ -39,6 +46,14 @@ func NewLocalStore(hash SwarmHasher, params *StoreParams) (*LocalStore, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *LocalStore) CacheCounter() uint64 {
|
||||||
|
return uint64(self.memStore.(*MemStore).Counter())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *LocalStore) DbCounter() uint64 {
|
||||||
|
return self.DbStore.(*DbStore).Counter()
|
||||||
|
}
|
||||||
|
|
||||||
// LocalStore is itself a chunk store
|
// LocalStore is itself a chunk store
|
||||||
// unsafe, in that the data is not integrity checked
|
// unsafe, in that the data is not integrity checked
|
||||||
func (self *LocalStore) Put(chunk *Chunk) {
|
func (self *LocalStore) Put(chunk *Chunk) {
|
||||||
@ -48,6 +63,7 @@ func (self *LocalStore) Put(chunk *Chunk) {
|
|||||||
chunk.wg.Add(1)
|
chunk.wg.Add(1)
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
|
dbStorePutCounter.Inc(1)
|
||||||
self.DbStore.Put(chunk)
|
self.DbStore.Put(chunk)
|
||||||
if chunk.wg != nil {
|
if chunk.wg != nil {
|
||||||
chunk.wg.Done()
|
chunk.wg.Done()
|
||||||
|
@ -23,6 +23,13 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
//metrics variables
|
||||||
|
var (
|
||||||
|
memstorePutCounter = metrics.NewRegisteredCounter("storage.db.memstore.put.count", nil)
|
||||||
|
memstoreRemoveCounter = metrics.NewRegisteredCounter("storage.db.memstore.rm.count", nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -130,6 +137,10 @@ func (s *MemStore) setCapacity(c uint) {
|
|||||||
s.capacity = c
|
s.capacity = c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *MemStore) Counter() uint {
|
||||||
|
return s.entryCnt
|
||||||
|
}
|
||||||
|
|
||||||
// entry (not its copy) is going to be in MemStore
|
// entry (not its copy) is going to be in MemStore
|
||||||
func (s *MemStore) Put(entry *Chunk) {
|
func (s *MemStore) Put(entry *Chunk) {
|
||||||
if s.capacity == 0 {
|
if s.capacity == 0 {
|
||||||
@ -145,6 +156,8 @@ func (s *MemStore) Put(entry *Chunk) {
|
|||||||
|
|
||||||
s.accessCnt++
|
s.accessCnt++
|
||||||
|
|
||||||
|
memstorePutCounter.Inc(1)
|
||||||
|
|
||||||
node := s.memtree
|
node := s.memtree
|
||||||
bitpos := uint(0)
|
bitpos := uint(0)
|
||||||
for node.entry == nil {
|
for node.entry == nil {
|
||||||
@ -289,6 +302,7 @@ func (s *MemStore) removeOldest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if node.entry.SData != nil {
|
if node.entry.SData != nil {
|
||||||
|
memstoreRemoveCounter.Inc(1)
|
||||||
node.entry = nil
|
node.entry = nil
|
||||||
s.entryCnt--
|
s.entryCnt--
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
@ -46,6 +47,16 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/swarm/storage"
|
"github.com/ethereum/go-ethereum/swarm/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
startTime time.Time
|
||||||
|
updateGaugesPeriod = 5 * time.Second
|
||||||
|
startCounter = metrics.NewRegisteredCounter("stack,start", nil)
|
||||||
|
stopCounter = metrics.NewRegisteredCounter("stack,stop", nil)
|
||||||
|
uptimeGauge = metrics.NewRegisteredGauge("stack.uptime", nil)
|
||||||
|
dbSizeGauge = metrics.NewRegisteredGauge("storage.db.chunks.size", nil)
|
||||||
|
cacheSizeGauge = metrics.NewRegisteredGauge("storage.db.cache.size", nil)
|
||||||
|
)
|
||||||
|
|
||||||
// the swarm stack
|
// the swarm stack
|
||||||
type Swarm struct {
|
type Swarm struct {
|
||||||
config *api.Config // swarm configuration
|
config *api.Config // swarm configuration
|
||||||
@ -262,6 +273,7 @@ Start is called when the stack is started
|
|||||||
*/
|
*/
|
||||||
// implements the node.Service interface
|
// implements the node.Service interface
|
||||||
func (self *Swarm) Start(srv *p2p.Server) error {
|
func (self *Swarm) Start(srv *p2p.Server) error {
|
||||||
|
startTime = time.Now()
|
||||||
connectPeer := func(url string) error {
|
connectPeer := func(url string) error {
|
||||||
node, err := discover.ParseNode(url)
|
node, err := discover.ParseNode(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -307,9 +319,28 @@ func (self *Swarm) Start(srv *p2p.Server) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.periodicallyUpdateGauges()
|
||||||
|
|
||||||
|
startCounter.Inc(1)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *Swarm) periodicallyUpdateGauges() {
|
||||||
|
ticker := time.NewTicker(updateGaugesPeriod)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
self.updateGauges()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Swarm) updateGauges() {
|
||||||
|
dbSizeGauge.Update(int64(self.lstore.DbCounter()))
|
||||||
|
cacheSizeGauge.Update(int64(self.lstore.CacheCounter()))
|
||||||
|
uptimeGauge.Update(time.Since(startTime).Nanoseconds())
|
||||||
|
}
|
||||||
|
|
||||||
// implements the node.Service interface
|
// implements the node.Service interface
|
||||||
// stops all component services.
|
// stops all component services.
|
||||||
func (self *Swarm) Stop() error {
|
func (self *Swarm) Stop() error {
|
||||||
@ -324,6 +355,7 @@ func (self *Swarm) Stop() error {
|
|||||||
self.lstore.DbStore.Close()
|
self.lstore.DbStore.Close()
|
||||||
}
|
}
|
||||||
self.sfs.Stop()
|
self.sfs.Stop()
|
||||||
|
stopCounter.Inc(1)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user