bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/cmd/scollector/collectors/metadata_linux.go (about) 1 package collectors 2 3 import ( 4 "errors" 5 "io/ioutil" 6 "net" 7 "strconv" 8 "strings" 9 "time" 10 11 "bosun.org/metadata" 12 "bosun.org/opentsdb" 13 "bosun.org/util" 14 ) 15 16 func init() { 17 collectors = append(collectors, &IntervalCollector{F: c_meta_linux_version, Interval: time.Minute * 30}) 18 collectors = append(collectors, &IntervalCollector{F: c_meta_linux_serial, Interval: time.Minute * 30}) 19 collectors = append(collectors, &IntervalCollector{F: c_meta_linux_ifaces, Interval: time.Minute * 30}) 20 } 21 22 func c_meta_linux_version() (opentsdb.MultiDataPoint, error) { 23 var md opentsdb.MultiDataPoint 24 _ = util.ReadCommand(func(line string) error { 25 metadata.AddMeta("", nil, "uname", line, true) 26 return nil 27 }, "uname", "-a") 28 if !readOSRelease() { 29 readIssue() 30 } 31 return md, nil 32 } 33 34 func readOSRelease() bool { 35 var found bool 36 _ = readLine("/etc/os-release", func(s string) error { 37 fields := strings.SplitN(s, "=", 2) 38 if len(fields) != 2 { 39 return nil 40 } 41 if fields[0] == "PRETTY_NAME" { 42 metadata.AddMeta("", nil, "version", strings.Trim(fields[1], `"`), true) 43 found = true 44 } 45 return nil 46 }) 47 return found 48 } 49 50 func readIssue() { 51 _ = util.ReadCommand(func(line string) error { 52 fields := strings.Fields(line) 53 hasNum := false 54 for i := 0; i < len(fields); { 55 if strings.HasPrefix(fields[i], `\`) { 56 fields = append(fields[:i], fields[i+1:]...) 57 } else { 58 if v, _ := strconv.ParseFloat(fields[i], 32); v > 0 { 59 hasNum = true 60 } 61 i++ 62 } 63 } 64 if !hasNum { 65 return nil 66 } 67 metadata.AddMeta("", nil, "version", strings.Join(fields, " "), true) 68 return nil 69 }, "cat", "/etc/issue") 70 } 71 72 func c_meta_linux_serial() (opentsdb.MultiDataPoint, error) { 73 var md opentsdb.MultiDataPoint 74 _ = util.ReadCommand(func(line string) error { 75 fields := strings.SplitN(line, ":", 2) 76 if len(fields) != 2 { 77 return nil 78 } 79 switch fields[0] { 80 case "\tSerial Number": 81 metadata.AddMeta("", nil, "serialNumber", strings.TrimSpace(fields[1]), true) 82 case "\tManufacturer": 83 metadata.AddMeta("", nil, "manufacturer", strings.TrimSpace(fields[1]), true) 84 case "\tProduct Name": 85 metadata.AddMeta("", nil, "model", strings.TrimSpace(fields[1]), true) 86 } 87 return nil 88 }, "dmidecode", "-t", "system") 89 return md, nil 90 } 91 92 var doneErr = errors.New("") 93 94 // metaLinuxIfacesMaster returns the bond master from s or "" if none exists. 95 func metaLinuxIfacesMaster(line string) string { 96 sp := strings.Fields(line) 97 for i := 4; i < len(sp); i += 2 { 98 if sp[i-1] == "master" { 99 return sp[i] 100 } 101 } 102 return "" 103 } 104 105 func c_meta_linux_ifaces() (opentsdb.MultiDataPoint, error) { 106 var md opentsdb.MultiDataPoint 107 metaIfaces(func(iface net.Interface, tags opentsdb.TagSet) { 108 if speed, err := ioutil.ReadFile("/sys/class/net/" + iface.Name + "/speed"); err == nil { 109 v, _ := strconv.Atoi(strings.TrimSpace(string(speed))) 110 if v > 0 { 111 const MbitToBit = 1e6 112 metadata.AddMeta("", tags, "speed", v*MbitToBit, true) 113 } 114 } 115 _ = util.ReadCommand(func(line string) error { 116 if v := metaLinuxIfacesMaster(line); v != "" { 117 metadata.AddMeta("", tags, "master", v, true) 118 return doneErr 119 } 120 return nil 121 }, "ip", "-o", "addr", "show", iface.Name) 122 }) 123 return md, nil 124 }