This repository has been archived by the owner on Mar 4, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
config.go
163 lines (137 loc) · 4.53 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"time"
)
// Flags are the CLI options
// ConfFile specifies the location of the config file and overrides the default value
// LogFile specifies an output location for any logged information; default is *no* logging
type Flags struct {
ConfFile string
LogFile string
}
// Config defines the structure for the configuration information used by the application.
// It defaults to a JSON-encoded file named "purpleprom.conf" in the current working directory.
// The configuration is expressed as strict JSON, so unfortunately comments are not supported.
type Config struct {
PollInterval Duration `json:"pollinterval"`
Sensors []int `json:"sensors"`
Metrics Metrics `json:"metrics"`
}
type Metrics struct {
Enabled bool `json:"enabled"`
Path string `json:"path"`
Port int `json:"port"`
}
// configFlags handles the flag processing for any CLI options specified
func configFlags() *Flags {
f := new(Flags)
flag.StringVar(&f.ConfFile, "c", "purpleprom.conf", "Path to configuration file")
flag.StringVar(&f.LogFile, "o", "", "Enable logging information and path to output file")
flag.Parse()
return f
}
// configLogger enables/disables the logging and, if enabled, directs it to the named file
func configLogger(l string) {
// if no logger specified, then disable logging by redirecting to discard
if l == "" {
log.SetFlags(0)
log.SetOutput(ioutil.Discard)
return
}
// open the named file and redirect logging output to it
f, err := os.OpenFile(l, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0755)
if err != nil {
log.Fatal(err)
}
log.SetOutput(f)
log.Printf("Logging enabled to %s", l)
}
// configLoad reads in the specified file and attempts to unmarshal it.
// The Config struct is
func configLoad(p string) *Config {
f, err := os.Open(p)
if err != nil {
log.Fatal(err.Error())
}
defer f.Close()
// read file into a bytestream
b, _ := ioutil.ReadAll(f)
// create a Config and unmarshal the bytestream into it
c := new(Config)
err = json.Unmarshal(b, c)
if err != nil {
log.Fatal(err.Error())
}
// basic sanity checking and defaults if unspecified
if len(c.Sensors) <= 0 {
log.Fatal("No sensors specified in configuration.")
}
if c.PollInterval <= 0 {
c.PollInterval, _ = parseDuration("60s")
}
return c
}
// UnmarshalJSON provides an interface for customized processing of the Metrics element.
// It performs the initialization of select fields to default values prior to the actual unmarshaling.
// The default values will be overwritten if present in the config.
func (m *Metrics) UnmarshalJSON(data []byte) error {
m.Enabled = true
m.Port = 6005
m.Path = "/metrics"
// avoid circular reference
type Alias Metrics
tmp := (*Alias)(m)
return json.Unmarshal(data, tmp)
}
// The Duration type provides enables the JSON module to process strings as time.Durations.
// While time.Duration is available as a native type for CLI flags, it is not for the JSON parser.
// Note that in Go, you cannot define new methods on a non-local type so this workaround is the
// best alternative to hacking directly in the standard Go time module.
type Duration time.Duration
// Duration returns the time.Duration native type of the time module.
// This helper function makes it slightly less tedious to continually typecast a Duration into a time.Duration
func (d Duration) Duration() time.Duration {
return time.Duration(d)
}
// ParseDuration is a helper function to parse a string utilizing the underlying time.ParseDuration functionality.
func parseDuration(s string) (Duration, error) {
td, err := time.ParseDuration(s)
if err != nil {
return Duration(0), err
}
return Duration(td), nil
}
// MarshalJSON supplies an interface for processing Duration values which wrap the standard time.Duration type.
// It returns a byte array and any error encountered.
func (d Duration) MarshalJSON() ([]byte, error) {
return json.Marshal(time.Duration(d).String())
}
// UnmarshalJSON supplies an interface for processing Duration values which wrap the standard time.Duration type.
// It accepts a byte array and returns any error encountered.
func (d *Duration) UnmarshalJSON(b []byte) error {
var v interface{}
err := json.Unmarshal(b, &v)
if err != nil {
return err
}
switch value := v.(type) {
case float64:
*d = Duration(time.Duration(value))
return nil
case string:
tmp, err := time.ParseDuration(value)
if err != nil {
return err
}
*d = Duration(tmp)
return nil
default:
return fmt.Errorf("Invalid Duration specification: '%v'", value)
}
}