Skip to content

Commit

Permalink
Introduce run metrics (#122)
Browse files Browse the repository at this point in the history
  • Loading branch information
tbauriedel committed Jun 28, 2024
1 parent 493f214 commit 45dd6b7
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 42 deletions.
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ linters:
linters-settings:
funlen:
ignore-comments: true
lines: 75
lines: 80
nestif:
min-complexity: 5
19 changes: 18 additions & 1 deletion internal/collection/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package collection
import (
"archive/zip"
"bytes"
"encoding/json"
"fmt"
"io"
"strings"
Expand All @@ -23,6 +24,7 @@ type Collection struct {
JournalLoggingInterval string
}

// New initializes new collection
func New(w io.Writer) (c *Collection) {
c = &Collection{
Output: zip.NewWriter(w),
Expand Down Expand Up @@ -141,7 +143,22 @@ func (c *Collection) AddFileYAML(fileName string, data interface{}) {
}

func (c *Collection) AddFileJSON(fileName string, data []byte) {
c.AddFileDataRaw(fileName, data)
var jsonData interface{}

err := json.Unmarshal(data, &jsonData)
if err != nil {
c.Log.Debugf("could not unmarshal JSON data for '%s': %s", fileName, err)
}

prettyJSON, err := json.MarshalIndent(jsonData, "", "")
if err != nil {
c.Log.Debugf("could not marshal JSON data for '%s': %s", fileName, err)
}

file := NewFile(fileName)
file.Data = prettyJSON

_ = c.AddFileToOutput(file)
}

func (c *Collection) AddFiles(prefix, source string) {
Expand Down
37 changes: 37 additions & 0 deletions internal/metrics/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package metrics

import (
"github.com/NETWAYS/support-collector/internal/obfuscate"
"os"
"strings"
"time"
)

type Metrics struct {
Command string `json:"command"`
Version string `json:"version"`
Timings map[string]time.Duration `json:"timings"`
}

// New creates new Metrics
func New(version string) (m *Metrics) {
return &Metrics{
Command: getCommand(),
Version: version,
Timings: make(map[string]time.Duration),
}
}

// getCommand returns the executed command and obfusactes *--icinga2* arguments
func getCommand() string {
args := os.Args

// Obfuscate icinga 2 api user and password
for i, arg := range args {
if strings.Contains(arg, "--icinga2") && i+1 < len(args) {
args[i+1] = obfuscate.Replacement
}
}

return strings.Join(args, " ")
}
100 changes: 62 additions & 38 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package main

import (
"encoding/json"
"fmt"
"github.com/NETWAYS/support-collector/internal/metrics"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -111,16 +113,31 @@ var (
outputFile string
commandTimeout = 60 * time.Second
noDetailedCollection bool
startTime = time.Now()
metric *metrics.Metrics
)

func main() {
handleArguments()

// set locale to C, to avoid translations in command output
// Set locale to C, to avoid translations in command output
_ = os.Setenv("LANG", "C")

c, cleanup := NewCollection(outputFile)
defer cleanup()
c, closeCollection := NewCollection(outputFile)
// Close collection
defer closeCollection()

// Initialize new metrics and defer function to save it to json
metric = metrics.New(getVersion())
defer func() {
// Save metrics to file
body, err := json.Marshal(metric)
if err != nil {
c.Log.Warn("cant unmarshal metrics: %w", err)
}

c.AddFileJSON("metrics.json", body)
}()

if noDetailedCollection {
c.Detailed = false
Expand All @@ -133,37 +150,16 @@ func main() {
c.Log.Warn("This tool should be run as a privileged user (root) to collect all necessary information")
}

var (
startTime = time.Now()
timings = map[string]time.Duration{}
)

// Set command Timeout from argument
c.ExecTimeout = commandTimeout

// Call all enabled modules
for _, name := range moduleOrder {
switch {
case util.StringInSlice(name, disabledModules):
c.Log.Debugf("Module %s is disabled", name)
case !util.StringInSlice(name, enabledModules):
c.Log.Debugf("Module %s is not enabled", name)
default:
moduleStart := time.Now()
// Collect modules
collectModules(c)

c.Log.Debugf("Start collecting data for module %s", name)
// Save overall timing
metric.Timings["total"] = time.Since(startTime)

for _, o := range extraObfuscators {
c.Log.Debugf("Adding custom obfuscator for '%s' to module %s", o, name)
c.RegisterObfuscator(obfuscate.NewAny(o))
}

modules[name](c)

timings[name] = time.Since(moduleStart)
c.Log.Debugf("Finished with module %s in %.3f seconds", name, timings[name].Seconds())
}
}
c.Log.Infof("Collection complete, took us %.3f seconds", metric.Timings["total"].Seconds())

// Collect obfuscation info
var files, count uint
Expand All @@ -178,12 +174,7 @@ func main() {
c.Log.Infof("Obfuscation replaced %d token in %d files (%d definitions)", count, files, len(c.Obfuscators))
}

// Save timings
timings["total"] = time.Since(startTime)
c.Log.Infof("Collection complete, took us %.3f seconds", timings["total"].Seconds())

c.AddFileYAML("timing.yml", timings)

// get absolute path of outputFile
path, err := filepath.Abs(outputFile)
if err != nil {
c.Log.Debug(err)
Expand Down Expand Up @@ -224,7 +215,7 @@ func handleArguments() {
flag.Parse()

if printVersion {
fmt.Println(Product, "version", buildVersion()) //nolint:forbidigo
fmt.Println(Product, "version", getBuildInfo()) //nolint:forbidigo
os.Exit(0)
}

Expand All @@ -241,6 +232,9 @@ func buildFileName() string {
return util.GetHostnameWithoutDomain() + "-" + FilePrefix + "-" + time.Now().Format("20060102-1504") + ".zip"
}

// NewCollection starts a new collection. outputFile will be created.
//
// Collection and cleanup function to defer are returned
func NewCollection(outputFile string) (*collection.Collection, func()) {
file, err := os.Create(outputFile)
if err != nil {
Expand All @@ -263,9 +257,8 @@ func NewCollection(outputFile string) (*collection.Collection, func()) {
Level: consoleLevel,
})

versionString := buildVersion()
versionString := getBuildInfo()
c.Log.Infof("Starting %s version %s", Product, versionString)
c.AddFileDataRaw("version", []byte(versionString+"\n"))

return c, func() {
// Close all open outputs in order, but only log errors
Expand All @@ -281,3 +274,34 @@ func NewCollection(outputFile string) (*collection.Collection, func()) {
}
}
}

func collectModules(c *collection.Collection) {
// Check if module is enabled / disabled and call it
for _, name := range moduleOrder {
switch {
case util.StringInSlice(name, disabledModules):
c.Log.Debugf("Module %s is disabled", name)
case !util.StringInSlice(name, enabledModules):
c.Log.Debugf("Module %s is not enabled", name)
default:
// Save current time
moduleStart := time.Now()

c.Log.Debugf("Start collecting data for module %s", name)

// Register custom obfuscators
for _, o := range extraObfuscators {
c.Log.Debugf("Adding custom obfuscator for '%s' to module %s", o, name)
c.RegisterObfuscator(obfuscate.NewAny(o))
}

// Call collection function for module
modules[name](c)

// Save runtime of module
metric.Timings[name] = time.Since(moduleStart)

c.Log.Debugf("Finished with module %s in %.3f seconds", name, metric.Timings[name].Seconds())
}
}
}
6 changes: 5 additions & 1 deletion modules/icinga2/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,12 @@ func Collect(c *collection.Collection) {
}

// With Icinga 2 >= 2.14 the icinga2.debug cache is no longer built automatically on every reload. To retrieve a current state we build it manually (only possible from 2.14.0)
// Needs to be done before commands are collected
if icinga2version >= "2.14.0" {
c.AddCommandOutput("dump-objects.txt", "icinga2", "daemon", "-C", "--dump-objects")
_, err = collection.LoadCommandOutput("icinga2", "daemon", "-C", "--dump-objects")
if err != nil {
c.Log.Warn(err)
}
}

for name, cmd := range commands {
Expand Down
6 changes: 5 additions & 1 deletion version.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var (
)

//goland:noinspection GoBoolExpressions
func buildVersion() string {
func getBuildInfo() string {
result := version

if commit != "" {
Expand All @@ -23,3 +23,7 @@ func buildVersion() string {

return result
}

func getVersion() string {
return version
}

0 comments on commit 45dd6b7

Please sign in to comment.