mirror of
https://github.com/Oxalide/vsphere-influxdb-go.git
synced 2023-10-10 11:36:51 +00:00
add vendoring with go dep
This commit is contained in:
46
vendor/github.com/influxdata/influxdb/monitor/README.md
generated
vendored
Normal file
46
vendor/github.com/influxdata/influxdb/monitor/README.md
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
# System Monitoring
|
||||
_This functionality should be considered experimental and is subject to change._
|
||||
|
||||
_System Monitoring_ means all statistical and diagnostic information made availabe to the user of InfluxDB system, about the system itself. Its purpose is to assist with troubleshooting and performance analysis of the database itself.
|
||||
|
||||
## Statistics vs. Diagnostics
|
||||
A distinction is made between _statistics_ and _diagnostics_ for the purposes of monitoring. Generally a statistical quality is something that is being counted, and for which it makes sense to store persistently for historical analysis. Diagnostic information is not necessarily numerical, and may not make sense to store.
|
||||
|
||||
An example of statistical information would be the number of points received over UDP, or the number of queries executed. Examples of diagnostic information would be a list of current Graphite TCP connections, the version of InfluxDB, or the uptime of the process.
|
||||
|
||||
## System Statistics
|
||||
`SHOW STATS [FOR <module>]` displays statisics about subsystems within the running `influxd` process. Statistics include points received, points indexed, bytes written to disk, TCP connections handled etc. These statistics are all zero when the InfluxDB process starts. If _module_ is specified, it must be single-quoted. For example `SHOW STATS FOR 'httpd'`.
|
||||
|
||||
All statistics are written, by default, by each node to a "monitor" database within the InfluxDB system, allowing analysis of aggregated statistical data using the standard InfluxQL language. This allows users to track the performance of their system. Importantly, this allows cluster-level statistics to be viewed, since by querying the monitor database, statistics from all nodes may be queried. This can be a very powerful approach for troubleshooting your InfluxDB system and understanding its behaviour.
|
||||
|
||||
## System Diagnostics
|
||||
`SHOW DIAGNOSTICS [FOR <module>]` displays various diagnostic information about the `influxd` process. This information is not stored persistently within the InfluxDB system. If _module_ is specified, it must be single-quoted. For example `SHOW STATS FOR 'build'`.
|
||||
|
||||
## Standard expvar support
|
||||
All statistical information is available at HTTP API endpoint `/debug/vars`, in [expvar](https://golang.org/pkg/expvar/) format, allowing external systems to monitor an InfluxDB node. By default, the full path to this endpoint is `http://localhost:8086/debug/vars`.
|
||||
|
||||
## Configuration
|
||||
The `monitor` module allows the following configuration:
|
||||
|
||||
* Whether to write statistical and diagnostic information to an InfluxDB system. This is enabled by default.
|
||||
* The name of the database to where this information should be written. Defaults to `_internal`. The information is written to the default retention policy for the given database.
|
||||
* The name of the retention policy, along with full configuration control of the retention policy, if the default retention policy is not suitable.
|
||||
* The rate at which this information should be written. The default rate is once every 10 seconds.
|
||||
|
||||
# Design and Implementation
|
||||
|
||||
A new module named `monitor` supports all basic statistics and diagnostic functionality. This includes:
|
||||
|
||||
* Allowing other modules to register statistics and diagnostics information, allowing it to be accessed on demand by the `monitor` module.
|
||||
* Serving the statistics and diagnostic information to the user, in response to commands such as `SHOW DIAGNOSTICS`.
|
||||
* Expose standard Go runtime information such as garbage collection statistics.
|
||||
* Make all collected expvar data via HTTP, for collection by 3rd-party tools.
|
||||
* Writing the statistical information to the "monitor" database, for query purposes.
|
||||
|
||||
## Registering statistics and diagnostics
|
||||
|
||||
To export statistical information with the `monitor` system, a service should implement the `monitor.Reporter` interface. Services added to the Server will be automatically added to the list of statistics returned. Any service that is not added to the `Services` slice will need to modify the `Server`'s `Statistics(map[string]string)` method to aggregate the call to the service's `Statistics(map[string]string)` method so they are combined into a single response. The `Statistics(map[string]string)` method should return a statistics slice with the passed in tags included. The statistics should be kept inside of an internal structure and should be accessed in a thread-safe way. It is common to create a struct for holding the statistics and using `sync/atomic` instead of locking. If using `sync/atomic`, be sure to align the values in the struct so it works properly on `i386`.
|
||||
|
||||
To register diagnostic information, `monitor.RegisterDiagnosticsClient` is called, passing a `influxdb.monitor.DiagsClient` object to `monitor`. Implementing the `influxdb.monitor.DiagsClient` interface requires that your component have function returning diagnostic information in specific form, so that it can be displayed by the `monitor` system.
|
||||
|
||||
Statistical information is reset to its initial state when a server is restarted.
|
22
vendor/github.com/influxdata/influxdb/monitor/build_info.go
generated
vendored
Normal file
22
vendor/github.com/influxdata/influxdb/monitor/build_info.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package monitor
|
||||
|
||||
import "github.com/influxdata/influxdb/monitor/diagnostics"
|
||||
|
||||
// build holds information of the build of the current executable.
|
||||
type build struct {
|
||||
Version string
|
||||
Commit string
|
||||
Branch string
|
||||
Time string
|
||||
}
|
||||
|
||||
func (b *build) Diagnostics() (*diagnostics.Diagnostics, error) {
|
||||
d := map[string]interface{}{
|
||||
"Version": b.Version,
|
||||
"Commit": b.Commit,
|
||||
"Branch": b.Branch,
|
||||
"Build Time": b.Time,
|
||||
}
|
||||
|
||||
return diagnostics.RowFromMap(d), nil
|
||||
}
|
63
vendor/github.com/influxdata/influxdb/monitor/config.go
generated
vendored
Normal file
63
vendor/github.com/influxdata/influxdb/monitor/config.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/influxdb/monitor/diagnostics"
|
||||
"github.com/influxdata/influxdb/toml"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultStoreEnabled is whether the system writes gathered information in
|
||||
// an InfluxDB system for historical analysis.
|
||||
DefaultStoreEnabled = true
|
||||
|
||||
// DefaultStoreDatabase is the name of the database where gathered information is written.
|
||||
DefaultStoreDatabase = "_internal"
|
||||
|
||||
// DefaultStoreInterval is the period between storing gathered information.
|
||||
DefaultStoreInterval = 10 * time.Second
|
||||
)
|
||||
|
||||
// Config represents the configuration for the monitor service.
|
||||
type Config struct {
|
||||
StoreEnabled bool `toml:"store-enabled"`
|
||||
StoreDatabase string `toml:"store-database"`
|
||||
StoreInterval toml.Duration `toml:"store-interval"`
|
||||
}
|
||||
|
||||
// NewConfig returns an instance of Config with defaults.
|
||||
func NewConfig() Config {
|
||||
return Config{
|
||||
StoreEnabled: true,
|
||||
StoreDatabase: DefaultStoreDatabase,
|
||||
StoreInterval: toml.Duration(DefaultStoreInterval),
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates that the configuration is acceptable.
|
||||
func (c Config) Validate() error {
|
||||
if c.StoreInterval <= 0 {
|
||||
return errors.New("monitor store interval must be positive")
|
||||
}
|
||||
if c.StoreDatabase == "" {
|
||||
return errors.New("monitor store database name must not be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Diagnostics returns a diagnostics representation of a subset of the Config.
|
||||
func (c Config) Diagnostics() (*diagnostics.Diagnostics, error) {
|
||||
if !c.StoreEnabled {
|
||||
return diagnostics.RowFromMap(map[string]interface{}{
|
||||
"store-enabled": false,
|
||||
}), nil
|
||||
}
|
||||
|
||||
return diagnostics.RowFromMap(map[string]interface{}{
|
||||
"store-enabled": true,
|
||||
"store-database": c.StoreDatabase,
|
||||
"store-interval": c.StoreInterval,
|
||||
}), nil
|
||||
}
|
52
vendor/github.com/influxdata/influxdb/monitor/config_test.go
generated
vendored
Normal file
52
vendor/github.com/influxdata/influxdb/monitor/config_test.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package monitor_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/influxdata/influxdb/monitor"
|
||||
)
|
||||
|
||||
func TestConfig_Parse(t *testing.T) {
|
||||
// Parse configuration.
|
||||
var c monitor.Config
|
||||
if _, err := toml.Decode(`
|
||||
store-enabled=true
|
||||
store-database="the_db"
|
||||
store-interval="10m"
|
||||
`, &c); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Validate configuration.
|
||||
if !c.StoreEnabled {
|
||||
t.Fatalf("unexpected store-enabled: %v", c.StoreEnabled)
|
||||
} else if c.StoreDatabase != "the_db" {
|
||||
t.Fatalf("unexpected store-database: %s", c.StoreDatabase)
|
||||
} else if time.Duration(c.StoreInterval) != 10*time.Minute {
|
||||
t.Fatalf("unexpected store-interval: %s", c.StoreInterval)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfig_Validate(t *testing.T) {
|
||||
// NewConfig must validate correctly.
|
||||
c := monitor.NewConfig()
|
||||
if err := c.Validate(); err != nil {
|
||||
t.Fatalf("unexpected validation error: %s", err)
|
||||
}
|
||||
|
||||
// Non-positive duration is invalid.
|
||||
c = monitor.NewConfig()
|
||||
c.StoreInterval *= 0
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Fatalf("unexpected successful validation for %#v", c)
|
||||
}
|
||||
|
||||
// Empty database is invalid.
|
||||
c = monitor.NewConfig()
|
||||
c.StoreDatabase = ""
|
||||
if err := c.Validate(); err == nil {
|
||||
t.Fatalf("unexpected successful validation for %#v", c)
|
||||
}
|
||||
}
|
64
vendor/github.com/influxdata/influxdb/monitor/diagnostics/diagnostics.go
generated
vendored
Normal file
64
vendor/github.com/influxdata/influxdb/monitor/diagnostics/diagnostics.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// Package diagnostics provides the diagnostics type so that
|
||||
// other packages can provide diagnostics without depending on the monitor package.
|
||||
package diagnostics // import "github.com/influxdata/influxdb/monitor/diagnostics"
|
||||
|
||||
import "sort"
|
||||
|
||||
// Client is the interface modules implement if they register diagnostics with monitor.
|
||||
type Client interface {
|
||||
Diagnostics() (*Diagnostics, error)
|
||||
}
|
||||
|
||||
// The ClientFunc type is an adapter to allow the use of
|
||||
// ordinary functions as Diagnostics clients.
|
||||
type ClientFunc func() (*Diagnostics, error)
|
||||
|
||||
// Diagnostics calls f().
|
||||
func (f ClientFunc) Diagnostics() (*Diagnostics, error) {
|
||||
return f()
|
||||
}
|
||||
|
||||
// Diagnostics represents a table of diagnostic information. The first value
|
||||
// is the name of the columns, the second is a slice of interface slices containing
|
||||
// the values for each column, by row. This information is never written to an InfluxDB
|
||||
// system and is display-only. An example showing, say, connections follows:
|
||||
//
|
||||
// source_ip source_port dest_ip dest_port
|
||||
// 182.1.0.2 2890 127.0.0.1 38901
|
||||
// 174.33.1.2 2924 127.0.0.1 38902
|
||||
type Diagnostics struct {
|
||||
Columns []string
|
||||
Rows [][]interface{}
|
||||
}
|
||||
|
||||
// NewDiagnostic initialises a new Diagnostics with the specified columns.
|
||||
func NewDiagnostics(columns []string) *Diagnostics {
|
||||
return &Diagnostics{
|
||||
Columns: columns,
|
||||
Rows: make([][]interface{}, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// AddRow appends the provided row to the Diagnostics' rows.
|
||||
func (d *Diagnostics) AddRow(r []interface{}) {
|
||||
d.Rows = append(d.Rows, r)
|
||||
}
|
||||
|
||||
// RowFromMap returns a new one-row Diagnostics from a map.
|
||||
func RowFromMap(m map[string]interface{}) *Diagnostics {
|
||||
// Display columns in deterministic order.
|
||||
sortedKeys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
sortedKeys = append(sortedKeys, k)
|
||||
}
|
||||
sort.Strings(sortedKeys)
|
||||
|
||||
d := NewDiagnostics(sortedKeys)
|
||||
row := make([]interface{}, len(sortedKeys))
|
||||
for i, k := range sortedKeys {
|
||||
row[i] = m[k]
|
||||
}
|
||||
d.AddRow(row)
|
||||
|
||||
return d
|
||||
}
|
21
vendor/github.com/influxdata/influxdb/monitor/go_runtime.go
generated
vendored
Normal file
21
vendor/github.com/influxdata/influxdb/monitor/go_runtime.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/influxdata/influxdb/monitor/diagnostics"
|
||||
)
|
||||
|
||||
// goRuntime captures Go runtime diagnostics.
|
||||
type goRuntime struct{}
|
||||
|
||||
func (g *goRuntime) Diagnostics() (*diagnostics.Diagnostics, error) {
|
||||
d := map[string]interface{}{
|
||||
"GOARCH": runtime.GOARCH,
|
||||
"GOOS": runtime.GOOS,
|
||||
"GOMAXPROCS": runtime.GOMAXPROCS(-1),
|
||||
"version": runtime.Version(),
|
||||
}
|
||||
|
||||
return diagnostics.RowFromMap(d), nil
|
||||
}
|
23
vendor/github.com/influxdata/influxdb/monitor/network.go
generated
vendored
Normal file
23
vendor/github.com/influxdata/influxdb/monitor/network.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/influxdata/influxdb/monitor/diagnostics"
|
||||
)
|
||||
|
||||
// network captures network diagnostics.
|
||||
type network struct{}
|
||||
|
||||
func (n *network) Diagnostics() (*diagnostics.Diagnostics, error) {
|
||||
h, err := os.Hostname()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d := map[string]interface{}{
|
||||
"hostname": h,
|
||||
}
|
||||
|
||||
return diagnostics.RowFromMap(d), nil
|
||||
}
|
10
vendor/github.com/influxdata/influxdb/monitor/reporter.go
generated
vendored
Normal file
10
vendor/github.com/influxdata/influxdb/monitor/reporter.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
package monitor
|
||||
|
||||
import "github.com/influxdata/influxdb/models"
|
||||
|
||||
// Reporter is an interface for gathering internal statistics.
|
||||
type Reporter interface {
|
||||
// Statistics returns the statistics for the reporter,
|
||||
// with the given tags merged into the result.
|
||||
Statistics(tags map[string]string) []models.Statistic
|
||||
}
|
481
vendor/github.com/influxdata/influxdb/monitor/service.go
generated
vendored
Normal file
481
vendor/github.com/influxdata/influxdb/monitor/service.go
generated
vendored
Normal file
@@ -0,0 +1,481 @@
|
||||
// Package monitor provides a service and associated functionality
|
||||
// for InfluxDB to self-monitor internal statistics and diagnostics.
|
||||
package monitor // import "github.com/influxdata/influxdb/monitor"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"expvar"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/influxdb/models"
|
||||
"github.com/influxdata/influxdb/monitor/diagnostics"
|
||||
"github.com/influxdata/influxdb/services/meta"
|
||||
"github.com/uber-go/zap"
|
||||
)
|
||||
|
||||
// Policy constants.
|
||||
const (
|
||||
// Name of the retention policy used by the monitor service.
|
||||
MonitorRetentionPolicy = "monitor"
|
||||
|
||||
// Duration of the monitor retention policy.
|
||||
MonitorRetentionPolicyDuration = 7 * 24 * time.Hour
|
||||
|
||||
// Default replication factor to set on the monitor retention policy.
|
||||
MonitorRetentionPolicyReplicaN = 1
|
||||
)
|
||||
|
||||
// Monitor represents an instance of the monitor system.
|
||||
type Monitor struct {
|
||||
// Build information for diagnostics.
|
||||
Version string
|
||||
Commit string
|
||||
Branch string
|
||||
BuildTime string
|
||||
|
||||
wg sync.WaitGroup
|
||||
|
||||
mu sync.RWMutex
|
||||
globalTags map[string]string
|
||||
diagRegistrations map[string]diagnostics.Client
|
||||
reporter Reporter
|
||||
done chan struct{}
|
||||
storeCreated bool
|
||||
storeEnabled bool
|
||||
|
||||
storeDatabase string
|
||||
storeRetentionPolicy string
|
||||
storeInterval time.Duration
|
||||
|
||||
MetaClient interface {
|
||||
CreateDatabaseWithRetentionPolicy(name string, spec *meta.RetentionPolicySpec) (*meta.DatabaseInfo, error)
|
||||
Database(name string) *meta.DatabaseInfo
|
||||
}
|
||||
|
||||
// Writer for pushing stats back into the database.
|
||||
PointsWriter PointsWriter
|
||||
|
||||
Logger zap.Logger
|
||||
}
|
||||
|
||||
// PointsWriter is a simplified interface for writing the points the monitor gathers.
|
||||
type PointsWriter interface {
|
||||
WritePoints(database, retentionPolicy string, points models.Points) error
|
||||
}
|
||||
|
||||
// New returns a new instance of the monitor system.
|
||||
func New(r Reporter, c Config) *Monitor {
|
||||
return &Monitor{
|
||||
globalTags: make(map[string]string),
|
||||
diagRegistrations: make(map[string]diagnostics.Client),
|
||||
reporter: r,
|
||||
storeEnabled: c.StoreEnabled,
|
||||
storeDatabase: c.StoreDatabase,
|
||||
storeInterval: time.Duration(c.StoreInterval),
|
||||
storeRetentionPolicy: MonitorRetentionPolicy,
|
||||
Logger: zap.New(zap.NullEncoder()),
|
||||
}
|
||||
}
|
||||
|
||||
// open returns whether the monitor service is open.
|
||||
func (m *Monitor) open() bool {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
return m.done != nil
|
||||
}
|
||||
|
||||
// Open opens the monitoring system, using the given clusterID, node ID, and hostname
|
||||
// for identification purpose.
|
||||
func (m *Monitor) Open() error {
|
||||
if m.open() {
|
||||
m.Logger.Info("Monitor is already open")
|
||||
return nil
|
||||
}
|
||||
|
||||
m.Logger.Info("Starting monitor system")
|
||||
|
||||
// Self-register various stats and diagnostics.
|
||||
m.RegisterDiagnosticsClient("build", &build{
|
||||
Version: m.Version,
|
||||
Commit: m.Commit,
|
||||
Branch: m.Branch,
|
||||
Time: m.BuildTime,
|
||||
})
|
||||
m.RegisterDiagnosticsClient("runtime", &goRuntime{})
|
||||
m.RegisterDiagnosticsClient("network", &network{})
|
||||
m.RegisterDiagnosticsClient("system", &system{})
|
||||
|
||||
m.mu.Lock()
|
||||
m.done = make(chan struct{})
|
||||
m.mu.Unlock()
|
||||
|
||||
// If enabled, record stats in a InfluxDB system.
|
||||
if m.storeEnabled {
|
||||
// Start periodic writes to system.
|
||||
m.wg.Add(1)
|
||||
go m.storeStatistics()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Monitor) writePoints(p models.Points) error {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
if err := m.PointsWriter.WritePoints(m.storeDatabase, m.storeRetentionPolicy, p); err != nil {
|
||||
m.Logger.Info(fmt.Sprintf("failed to store statistics: %s", err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the monitor system.
|
||||
func (m *Monitor) Close() error {
|
||||
if !m.open() {
|
||||
m.Logger.Info("Monitor is already closed.")
|
||||
return nil
|
||||
}
|
||||
|
||||
m.Logger.Info("shutting down monitor system")
|
||||
m.mu.Lock()
|
||||
close(m.done)
|
||||
m.mu.Unlock()
|
||||
|
||||
m.wg.Wait()
|
||||
|
||||
m.mu.Lock()
|
||||
m.done = nil
|
||||
m.mu.Unlock()
|
||||
|
||||
m.DeregisterDiagnosticsClient("build")
|
||||
m.DeregisterDiagnosticsClient("runtime")
|
||||
m.DeregisterDiagnosticsClient("network")
|
||||
m.DeregisterDiagnosticsClient("system")
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetGlobalTag can be used to set tags that will appear on all points
|
||||
// written by the Monitor.
|
||||
func (m *Monitor) SetGlobalTag(key string, value interface{}) {
|
||||
m.mu.Lock()
|
||||
m.globalTags[key] = fmt.Sprintf("%v", value)
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// RemoteWriterConfig represents the configuration of a remote writer.
|
||||
type RemoteWriterConfig struct {
|
||||
RemoteAddr string
|
||||
NodeID string
|
||||
Username string
|
||||
Password string
|
||||
ClusterID uint64
|
||||
}
|
||||
|
||||
// SetPointsWriter can be used to set a writer for the monitoring points.
|
||||
func (m *Monitor) SetPointsWriter(pw PointsWriter) error {
|
||||
if !m.storeEnabled {
|
||||
// not enabled, nothing to do
|
||||
return nil
|
||||
}
|
||||
m.mu.Lock()
|
||||
m.PointsWriter = pw
|
||||
m.mu.Unlock()
|
||||
|
||||
// Subsequent calls to an already open Monitor are just a no-op.
|
||||
return m.Open()
|
||||
}
|
||||
|
||||
// WithLogger sets the logger for the Monitor.
|
||||
func (m *Monitor) WithLogger(log zap.Logger) {
|
||||
m.Logger = log.With(zap.String("service", "monitor"))
|
||||
}
|
||||
|
||||
// RegisterDiagnosticsClient registers a diagnostics client with the given name and tags.
|
||||
func (m *Monitor) RegisterDiagnosticsClient(name string, client diagnostics.Client) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.diagRegistrations[name] = client
|
||||
m.Logger.Info(fmt.Sprintf(`'%s' registered for diagnostics monitoring`, name))
|
||||
}
|
||||
|
||||
// DeregisterDiagnosticsClient deregisters a diagnostics client by name.
|
||||
func (m *Monitor) DeregisterDiagnosticsClient(name string) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
delete(m.diagRegistrations, name)
|
||||
}
|
||||
|
||||
// Statistics returns the combined statistics for all expvar data. The given
|
||||
// tags are added to each of the returned statistics.
|
||||
func (m *Monitor) Statistics(tags map[string]string) ([]*Statistic, error) {
|
||||
var statistics []*Statistic
|
||||
|
||||
expvar.Do(func(kv expvar.KeyValue) {
|
||||
// Skip built-in expvar stats.
|
||||
if kv.Key == "memstats" || kv.Key == "cmdline" {
|
||||
return
|
||||
}
|
||||
|
||||
statistic := &Statistic{
|
||||
Statistic: models.NewStatistic(""),
|
||||
}
|
||||
|
||||
// Add any supplied tags.
|
||||
for k, v := range tags {
|
||||
statistic.Tags[k] = v
|
||||
}
|
||||
|
||||
// Every other top-level expvar value is a map.
|
||||
m := kv.Value.(*expvar.Map)
|
||||
|
||||
m.Do(func(subKV expvar.KeyValue) {
|
||||
switch subKV.Key {
|
||||
case "name":
|
||||
// straight to string name.
|
||||
u, err := strconv.Unquote(subKV.Value.String())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
statistic.Name = u
|
||||
case "tags":
|
||||
// string-string tags map.
|
||||
n := subKV.Value.(*expvar.Map)
|
||||
n.Do(func(t expvar.KeyValue) {
|
||||
u, err := strconv.Unquote(t.Value.String())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
statistic.Tags[t.Key] = u
|
||||
})
|
||||
case "values":
|
||||
// string-interface map.
|
||||
n := subKV.Value.(*expvar.Map)
|
||||
n.Do(func(kv expvar.KeyValue) {
|
||||
var f interface{}
|
||||
var err error
|
||||
switch v := kv.Value.(type) {
|
||||
case *expvar.Float:
|
||||
f, err = strconv.ParseFloat(v.String(), 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case *expvar.Int:
|
||||
f, err = strconv.ParseInt(v.String(), 10, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
default:
|
||||
return
|
||||
}
|
||||
statistic.Values[kv.Key] = f
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// If a registered client has no field data, don't include it in the results
|
||||
if len(statistic.Values) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
statistics = append(statistics, statistic)
|
||||
})
|
||||
|
||||
// Add Go memstats.
|
||||
statistic := &Statistic{
|
||||
Statistic: models.NewStatistic("runtime"),
|
||||
}
|
||||
|
||||
// Add any supplied tags to Go memstats
|
||||
for k, v := range tags {
|
||||
statistic.Tags[k] = v
|
||||
}
|
||||
|
||||
var rt runtime.MemStats
|
||||
runtime.ReadMemStats(&rt)
|
||||
statistic.Values = map[string]interface{}{
|
||||
"Alloc": int64(rt.Alloc),
|
||||
"TotalAlloc": int64(rt.TotalAlloc),
|
||||
"Sys": int64(rt.Sys),
|
||||
"Lookups": int64(rt.Lookups),
|
||||
"Mallocs": int64(rt.Mallocs),
|
||||
"Frees": int64(rt.Frees),
|
||||
"HeapAlloc": int64(rt.HeapAlloc),
|
||||
"HeapSys": int64(rt.HeapSys),
|
||||
"HeapIdle": int64(rt.HeapIdle),
|
||||
"HeapInUse": int64(rt.HeapInuse),
|
||||
"HeapReleased": int64(rt.HeapReleased),
|
||||
"HeapObjects": int64(rt.HeapObjects),
|
||||
"PauseTotalNs": int64(rt.PauseTotalNs),
|
||||
"NumGC": int64(rt.NumGC),
|
||||
"NumGoroutine": int64(runtime.NumGoroutine()),
|
||||
}
|
||||
statistics = append(statistics, statistic)
|
||||
|
||||
statistics = m.gatherStatistics(statistics, tags)
|
||||
return statistics, nil
|
||||
}
|
||||
|
||||
func (m *Monitor) gatherStatistics(statistics []*Statistic, tags map[string]string) []*Statistic {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
for _, s := range m.reporter.Statistics(tags) {
|
||||
statistics = append(statistics, &Statistic{Statistic: s})
|
||||
}
|
||||
return statistics
|
||||
}
|
||||
|
||||
// Diagnostics fetches diagnostic information for each registered
|
||||
// diagnostic client. It skips any clients that return an error when
|
||||
// retrieving their diagnostics.
|
||||
func (m *Monitor) Diagnostics() (map[string]*diagnostics.Diagnostics, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
diags := make(map[string]*diagnostics.Diagnostics, len(m.diagRegistrations))
|
||||
for k, v := range m.diagRegistrations {
|
||||
d, err := v.Diagnostics()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
diags[k] = d
|
||||
}
|
||||
return diags, nil
|
||||
}
|
||||
|
||||
// createInternalStorage ensures the internal storage has been created.
|
||||
func (m *Monitor) createInternalStorage() {
|
||||
if m.storeCreated {
|
||||
return
|
||||
}
|
||||
|
||||
if di := m.MetaClient.Database(m.storeDatabase); di == nil {
|
||||
duration := MonitorRetentionPolicyDuration
|
||||
replicaN := MonitorRetentionPolicyReplicaN
|
||||
spec := meta.RetentionPolicySpec{
|
||||
Name: MonitorRetentionPolicy,
|
||||
Duration: &duration,
|
||||
ReplicaN: &replicaN,
|
||||
}
|
||||
|
||||
if _, err := m.MetaClient.CreateDatabaseWithRetentionPolicy(m.storeDatabase, &spec); err != nil {
|
||||
m.Logger.Info(fmt.Sprintf("failed to create database '%s', failed to create storage: %s",
|
||||
m.storeDatabase, err.Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Mark storage creation complete.
|
||||
m.storeCreated = true
|
||||
}
|
||||
|
||||
// waitUntilInterval waits until we are on an even interval for the duration.
|
||||
func (m *Monitor) waitUntilInterval(d time.Duration) error {
|
||||
now := time.Now()
|
||||
until := now.Truncate(d).Add(d)
|
||||
timer := time.NewTimer(until.Sub(now))
|
||||
defer timer.Stop()
|
||||
|
||||
select {
|
||||
case <-timer.C:
|
||||
return nil
|
||||
case <-m.done:
|
||||
return errors.New("interrupted")
|
||||
}
|
||||
}
|
||||
|
||||
// storeStatistics writes the statistics to an InfluxDB system.
|
||||
func (m *Monitor) storeStatistics() {
|
||||
defer m.wg.Done()
|
||||
m.Logger.Info(fmt.Sprintf("Storing statistics in database '%s' retention policy '%s', at interval %s",
|
||||
m.storeDatabase, m.storeRetentionPolicy, m.storeInterval))
|
||||
|
||||
hostname, _ := os.Hostname()
|
||||
m.SetGlobalTag("hostname", hostname)
|
||||
|
||||
// Wait until an even interval to start recording monitor statistics.
|
||||
// If we are interrupted before the interval for some reason, exit early.
|
||||
if err := m.waitUntilInterval(m.storeInterval); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tick := time.NewTicker(m.storeInterval)
|
||||
defer tick.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case now := <-tick.C:
|
||||
now = now.Truncate(m.storeInterval)
|
||||
func() {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.createInternalStorage()
|
||||
}()
|
||||
|
||||
stats, err := m.Statistics(m.globalTags)
|
||||
if err != nil {
|
||||
m.Logger.Info(fmt.Sprintf("failed to retrieve registered statistics: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
// Write all stats in batches
|
||||
batch := make(models.Points, 0, 5000)
|
||||
for _, s := range stats {
|
||||
pt, err := models.NewPoint(s.Name, models.NewTags(s.Tags), s.Values, now)
|
||||
if err != nil {
|
||||
m.Logger.Info(fmt.Sprintf("Dropping point %v: %v", s.Name, err))
|
||||
return
|
||||
}
|
||||
batch = append(batch, pt)
|
||||
if len(batch) == cap(batch) {
|
||||
m.writePoints(batch)
|
||||
batch = batch[:0]
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Write the last batch
|
||||
if len(batch) > 0 {
|
||||
m.writePoints(batch)
|
||||
}
|
||||
case <-m.done:
|
||||
m.Logger.Info(fmt.Sprintf("terminating storage of statistics"))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Statistic represents the information returned by a single monitor client.
|
||||
type Statistic struct {
|
||||
models.Statistic
|
||||
}
|
||||
|
||||
// ValueNames returns a sorted list of the value names, if any.
|
||||
func (s *Statistic) ValueNames() []string {
|
||||
a := make([]string, 0, len(s.Values))
|
||||
for k := range s.Values {
|
||||
a = append(a, k)
|
||||
}
|
||||
sort.Strings(a)
|
||||
return a
|
||||
}
|
||||
|
||||
// Statistics is a slice of sortable statistics.
|
||||
type Statistics []*Statistic
|
||||
|
||||
// Len implements sort.Interface.
|
||||
func (a Statistics) Len() int { return len(a) }
|
||||
|
||||
// Less implements sort.Interface.
|
||||
func (a Statistics) Less(i, j int) bool {
|
||||
return a[i].Name < a[j].Name
|
||||
}
|
||||
|
||||
// Swap implements sort.Interface.
|
||||
func (a Statistics) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
28
vendor/github.com/influxdata/influxdb/monitor/system.go
generated
vendored
Normal file
28
vendor/github.com/influxdata/influxdb/monitor/system.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/influxdb/monitor/diagnostics"
|
||||
)
|
||||
|
||||
var startTime time.Time
|
||||
|
||||
func init() {
|
||||
startTime = time.Now().UTC()
|
||||
}
|
||||
|
||||
// system captures system-level diagnostics.
|
||||
type system struct{}
|
||||
|
||||
func (s *system) Diagnostics() (*diagnostics.Diagnostics, error) {
|
||||
d := map[string]interface{}{
|
||||
"PID": os.Getpid(),
|
||||
"currentTime": time.Now().UTC(),
|
||||
"started": startTime,
|
||||
"uptime": time.Since(startTime).String(),
|
||||
}
|
||||
|
||||
return diagnostics.RowFromMap(d), nil
|
||||
}
|
Reference in New Issue
Block a user