blob: 49ad421214ece7cf95c2fc61272103cd17ab53cb [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Robin Thellendfa70aaa2014-10-09 17:13:05 -07005// Package sysstats exports system statistics, and updates them periodically.
6// The package does not export any symbols, but needs to be imported for its
7// side-effects.
8package sysstats
9
10import (
11 "os"
12 "reflect"
13 "runtime"
14 "strings"
15 "time"
16
Todd Wangbd98a772015-04-07 18:18:24 -070017 "v.io/x/lib/buildinfo"
Jiri Simsaffceefa2015-02-28 11:03:34 -080018 "v.io/x/ref/lib/stats"
Robin Thellendfa70aaa2014-10-09 17:13:05 -070019)
20
21func init() {
22 now := time.Now()
23 stats.NewInteger("system/start-time-unix").Set(now.Unix())
24 stats.NewString("system/start-time-rfc1123").Set(now.Format(time.RFC1123))
25 stats.NewString("system/cmdline").Set(strings.Join(os.Args, " "))
26 stats.NewInteger("system/num-cpu").Set(int64(runtime.NumCPU()))
Robin Thellend6e2ec2c2014-12-05 12:38:11 -080027 stats.NewIntegerFunc("system/num-goroutine", func() int64 { return int64(runtime.NumGoroutine()) })
Robin Thellendfa70aaa2014-10-09 17:13:05 -070028 stats.NewString("system/version").Set(runtime.Version())
Robert Kroeger4692e292015-01-28 14:50:21 -080029 stats.NewInteger("system/pid").Set(int64(os.Getpid()))
Robin Thellendfa70aaa2014-10-09 17:13:05 -070030 if hostname, err := os.Hostname(); err == nil {
31 stats.NewString("system/hostname").Set(hostname)
32 }
33 exportEnv()
34 exportMemStats()
Bogdan Caprita4d2f6cc2015-02-24 16:58:22 -080035 exportBuildInfo()
Robin Thellendfa70aaa2014-10-09 17:13:05 -070036}
37
38func exportEnv() {
Srdjan Petrovic62f689c2014-11-12 11:05:35 -080039 var kv []stats.KeyValue
40 for _, v := range os.Environ() {
Robin Thellendfa70aaa2014-10-09 17:13:05 -070041 if parts := strings.SplitN(v, "=", 2); len(parts) == 2 {
Srdjan Petrovic62f689c2014-11-12 11:05:35 -080042 kv = append(kv, stats.KeyValue{parts[0], parts[1]})
Robin Thellendfa70aaa2014-10-09 17:13:05 -070043 }
44 }
45 stats.NewMap("system/environ").Set(kv)
46}
47
48func exportMemStats() {
49 mstats := stats.NewMap("system/memstats")
50
51 // Get field names to export.
52 var memstats runtime.MemStats
53 fieldNames := []string{}
54 v := reflect.ValueOf(memstats)
55 v.FieldByNameFunc(func(name string) bool {
56 switch v.FieldByName(name).Kind() {
57 case reflect.Bool, reflect.Uint32, reflect.Uint64:
58 fieldNames = append(fieldNames, name)
59 }
60 return false
61 })
62 updateStats := func() {
63 var memstats runtime.MemStats
64 runtime.ReadMemStats(&memstats)
65 v := reflect.ValueOf(memstats)
66 kv := make([]stats.KeyValue, len(fieldNames))
67 for i, name := range fieldNames {
68 kv[i] = stats.KeyValue{name, v.FieldByName(name).Interface()}
69 }
70 mstats.Set(kv)
71 }
72 // Update stats now and every 10 seconds afterwards.
73 updateStats()
74 go func() {
75 for {
76 time.Sleep(10 * time.Second)
77 updateStats()
78 }
79 }()
80}
Bogdan Caprita4d2f6cc2015-02-24 16:58:22 -080081
82func exportBuildInfo() {
83 kv := []stats.KeyValue{}
84 v := reflect.ValueOf(*buildinfo.Info())
85 for i := 0; i < v.NumField(); i++ {
86 kv = append(kv, stats.KeyValue{v.Type().Field(i).Name, v.Field(i).Interface()})
87 }
88 stats.NewMap("system/buildinfo").Set(kv)
89}