mirror of
https://github.com/rclone/rclone.git
synced 2024-12-24 16:09:01 +01:00
257 lines
6.7 KiB
Go
257 lines
6.7 KiB
Go
// Copyright (C) 2015 Space Monkey, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package monkit
|
|
|
|
import (
|
|
"sort"
|
|
"sync"
|
|
)
|
|
|
|
type traceWatcherRef struct {
|
|
watcher func(*Trace)
|
|
}
|
|
|
|
// Registry encapsulates all of the top-level state for a monitoring system.
|
|
// In general, only the Default registry is ever used.
|
|
type Registry struct {
|
|
// sync/atomic things
|
|
traceWatcher *traceWatcherRef
|
|
|
|
watcherMtx sync.Mutex
|
|
watcherCounter int64
|
|
traceWatchers map[int64]func(*Trace)
|
|
|
|
scopeMtx sync.Mutex
|
|
scopes map[string]*Scope
|
|
|
|
spanMtx sync.Mutex
|
|
spans map[*Span]struct{}
|
|
|
|
orphanMtx sync.Mutex
|
|
orphans map[*Span]struct{}
|
|
}
|
|
|
|
// NewRegistry creates a NewRegistry, though you almost certainly just want
|
|
// to use Default.
|
|
func NewRegistry() *Registry {
|
|
return &Registry{
|
|
traceWatchers: map[int64]func(*Trace){},
|
|
scopes: map[string]*Scope{},
|
|
spans: map[*Span]struct{}{},
|
|
orphans: map[*Span]struct{}{}}
|
|
}
|
|
|
|
// Package creates a new monitoring Scope, named after the top level package.
|
|
// It's expected that you'll have something like
|
|
//
|
|
// var mon = monkit.Package()
|
|
//
|
|
// at the top of each package.
|
|
func (r *Registry) Package() *Scope {
|
|
return r.ScopeNamed(callerPackage(1))
|
|
}
|
|
|
|
// ScopeNamed is like Package, but lets you choose the name.
|
|
func (r *Registry) ScopeNamed(name string) *Scope {
|
|
r.scopeMtx.Lock()
|
|
defer r.scopeMtx.Unlock()
|
|
s, exists := r.scopes[name]
|
|
if exists {
|
|
return s
|
|
}
|
|
s = newScope(r, name)
|
|
r.scopes[name] = s
|
|
return s
|
|
}
|
|
|
|
func (r *Registry) observeTrace(t *Trace) {
|
|
watcher := loadTraceWatcherRef(&r.traceWatcher)
|
|
if watcher != nil {
|
|
watcher.watcher(t)
|
|
}
|
|
}
|
|
|
|
func (r *Registry) updateWatcher() {
|
|
cbs := make([]func(*Trace), 0, len(r.traceWatchers))
|
|
for _, cb := range r.traceWatchers {
|
|
cbs = append(cbs, cb)
|
|
}
|
|
switch len(cbs) {
|
|
case 0:
|
|
storeTraceWatcherRef(&r.traceWatcher, nil)
|
|
case 1:
|
|
storeTraceWatcherRef(&r.traceWatcher,
|
|
&traceWatcherRef{watcher: cbs[0]})
|
|
default:
|
|
storeTraceWatcherRef(&r.traceWatcher,
|
|
&traceWatcherRef{watcher: func(t *Trace) {
|
|
for _, cb := range cbs {
|
|
cb(t)
|
|
}
|
|
}})
|
|
}
|
|
}
|
|
|
|
// ObserveTraces lets you observe all traces flowing through the system.
|
|
// The passed in callback 'cb' will be called for every new trace as soon as
|
|
// it starts, until the returned cancel method is called.
|
|
// Note: this only applies to all new traces. If you want to find existing
|
|
// or running traces, please pull them off of live RootSpans.
|
|
func (r *Registry) ObserveTraces(cb func(*Trace)) (cancel func()) {
|
|
// even though observeTrace doesn't get a mutex, it's only ever loading
|
|
// the traceWatcher pointer, so we can use this mutex here to safely
|
|
// coordinate the setting of the traceWatcher pointer.
|
|
r.watcherMtx.Lock()
|
|
defer r.watcherMtx.Unlock()
|
|
|
|
cbId := r.watcherCounter
|
|
r.watcherCounter += 1
|
|
r.traceWatchers[cbId] = cb
|
|
r.updateWatcher()
|
|
|
|
return func() {
|
|
r.watcherMtx.Lock()
|
|
defer r.watcherMtx.Unlock()
|
|
delete(r.traceWatchers, cbId)
|
|
r.updateWatcher()
|
|
}
|
|
}
|
|
|
|
func (r *Registry) rootSpanStart(s *Span) {
|
|
r.spanMtx.Lock()
|
|
r.spans[s] = struct{}{}
|
|
r.spanMtx.Unlock()
|
|
}
|
|
|
|
func (r *Registry) rootSpanEnd(s *Span) {
|
|
r.spanMtx.Lock()
|
|
delete(r.spans, s)
|
|
r.spanMtx.Unlock()
|
|
}
|
|
|
|
func (r *Registry) orphanedSpan(s *Span) {
|
|
r.orphanMtx.Lock()
|
|
r.orphans[s] = struct{}{}
|
|
r.orphanMtx.Unlock()
|
|
}
|
|
|
|
func (r *Registry) orphanEnd(s *Span) {
|
|
r.orphanMtx.Lock()
|
|
delete(r.orphans, s)
|
|
r.orphanMtx.Unlock()
|
|
}
|
|
|
|
// RootSpans will call 'cb' on all currently executing Spans with no live or
|
|
// reachable parent. See also AllSpans.
|
|
func (r *Registry) RootSpans(cb func(s *Span)) {
|
|
r.spanMtx.Lock()
|
|
spans := make([]*Span, 0, len(r.spans))
|
|
for s := range r.spans {
|
|
spans = append(spans, s)
|
|
}
|
|
r.spanMtx.Unlock()
|
|
r.orphanMtx.Lock()
|
|
orphans := make([]*Span, 0, len(r.orphans))
|
|
for s := range r.orphans {
|
|
orphans = append(orphans, s)
|
|
}
|
|
r.orphanMtx.Unlock()
|
|
spans = append(spans, orphans...)
|
|
sort.Sort(spanSorter(spans))
|
|
for _, s := range spans {
|
|
cb(s)
|
|
}
|
|
}
|
|
|
|
func walkSpan(s *Span, cb func(s *Span)) {
|
|
cb(s)
|
|
s.Children(func(s *Span) {
|
|
walkSpan(s, cb)
|
|
})
|
|
}
|
|
|
|
// AllSpans calls 'cb' on all currently known Spans. See also RootSpans.
|
|
func (r *Registry) AllSpans(cb func(s *Span)) {
|
|
r.RootSpans(func(s *Span) { walkSpan(s, cb) })
|
|
}
|
|
|
|
// Scopes calls 'cb' on all currently known Scopes.
|
|
func (r *Registry) Scopes(cb func(s *Scope)) {
|
|
r.scopeMtx.Lock()
|
|
c := make([]*Scope, 0, len(r.scopes))
|
|
for _, s := range r.scopes {
|
|
c = append(c, s)
|
|
}
|
|
r.scopeMtx.Unlock()
|
|
sort.Sort(scopeSorter(c))
|
|
for _, s := range c {
|
|
cb(s)
|
|
}
|
|
}
|
|
|
|
// Funcs calls 'cb' on all currently known Funcs.
|
|
func (r *Registry) Funcs(cb func(f *Func)) {
|
|
r.Scopes(func(s *Scope) { s.Funcs(cb) })
|
|
}
|
|
|
|
// Stats implements the StatSource interface.
|
|
func (r *Registry) Stats(cb func(key SeriesKey, field string, val float64)) {
|
|
r.Scopes(func(s *Scope) {
|
|
s.Stats(func(key SeriesKey, field string, val float64) {
|
|
cb(key.WithTag("scope", s.name), field, val)
|
|
})
|
|
})
|
|
}
|
|
|
|
var _ StatSource = (*Registry)(nil)
|
|
|
|
// Default is the default Registry
|
|
var Default = NewRegistry()
|
|
|
|
// ScopeNamed is just a wrapper around Default.ScopeNamed
|
|
func ScopeNamed(name string) *Scope { return Default.ScopeNamed(name) }
|
|
|
|
// RootSpans is just a wrapper around Default.RootSpans
|
|
func RootSpans(cb func(s *Span)) { Default.RootSpans(cb) }
|
|
|
|
// Scopes is just a wrapper around Default.Scopes
|
|
func Scopes(cb func(s *Scope)) { Default.Scopes(cb) }
|
|
|
|
// Funcs is just a wrapper around Default.Funcs
|
|
func Funcs(cb func(f *Func)) { Default.Funcs(cb) }
|
|
|
|
// Package is just a wrapper around Default.Package
|
|
func Package() *Scope { return Default.ScopeNamed(callerPackage(1)) }
|
|
|
|
// Stats is just a wrapper around Default.Stats
|
|
func Stats(cb func(key SeriesKey, field string, val float64)) { Default.Stats(cb) }
|
|
|
|
type spanSorter []*Span
|
|
|
|
func (s spanSorter) Len() int { return len(s) }
|
|
func (s spanSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
|
|
func (s spanSorter) Less(i, j int) bool {
|
|
ispan, jspan := s[i], s[j]
|
|
iname, jname := ispan.f.FullName(), jspan.f.FullName()
|
|
return (iname < jname) || (iname == jname && ispan.id < jspan.id)
|
|
}
|
|
|
|
type scopeSorter []*Scope
|
|
|
|
func (s scopeSorter) Len() int { return len(s) }
|
|
func (s scopeSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
func (s scopeSorter) Less(i, j int) bool { return s[i].name < s[j].name }
|