diff --git a/example/config.yaml b/example/config.yaml index d439b1bcc..640c1abb8 100644 --- a/example/config.yaml +++ b/example/config.yaml @@ -14,20 +14,17 @@ startClock: 2019-01-01T00:00:00+09:00 # Optional (default: same as tick) metricsTick: 60 -# Metrics of simulated kubernetes cluster is written to a file at this path. +# Metrics of simulated kubernetes cluster is written +# to a file at this path or standard out if not specified. # The metrics is formatted with the given formatter. -# Optional (default: not writing metrics to a file) -metricsFile: +# Optional (default: not writing metrics) +metricsLogger: +- formatter: table - path: kubesim.log formatter: JSON - path: kubesim-hr.log formatter: humanReadable -# Metrics is (also) written to stdout. -# Optional (default: not writing metrics to stdout) -metricsStdout: - formatter: table - # Write configuration of each node. cluster: - metadata: diff --git a/pkg/config/config.go b/pkg/config/config.go index 7d58c3bfb..49394fc7d 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -32,19 +32,16 @@ type Config struct { Tick int StartClock string MetricsTick int - MetricsFile []MetricsFileConfig - MetricsStdout MetricsStdoutConfig + MetricsLogger []MetricsLoggerConfig Cluster []NodeConfig } // Made public to be parsed from YAML. -type MetricsFileConfig struct { - Path string - Formatter string -} - -type MetricsStdoutConfig struct { +type MetricsLoggerConfig struct { + // Path is a file path in which the metrics is written. + Path string + // Formetter is a type of metrics format. Formatter string } @@ -58,16 +55,12 @@ type NodeStatus struct { Allocatable map[v1.ResourceName]string } -// BuildMetricsFile builds metrics.FileWriter with the given MetricsFileConfig. +// BuildMetricsLogger builds metrics.FileWriter with the given MetricsLoggerConfig. // Returns error if the config is invalid or failed to create a FileWriter. -func BuildMetricsFile(conf []MetricsFileConfig) ([]*metrics.FileWriter, error) { +func BuildMetricsLogger(conf []MetricsLoggerConfig) ([]*metrics.FileWriter, error) { writers := make([]*metrics.FileWriter, 0, len(conf)) for _, conf := range conf { - if conf.Path == "" { - return nil, strongerrors.InvalidArgument(errors.New("empty metricsFile.Path")) - } - formatter, err := buildFormatter(conf.Formatter) if err != nil { return nil, err @@ -84,22 +77,6 @@ func BuildMetricsFile(conf []MetricsFileConfig) ([]*metrics.FileWriter, error) { return writers, nil } -// BuildMetricsStdout builds a metrics.StdoutWriter with the given MetricsStdoutConfig. -// Returns error if failed to parse. -func BuildMetricsStdout(conf MetricsStdoutConfig) (*metrics.StdoutWriter, error) { - if conf.Formatter == "" { - return nil, nil - } - - formatter, err := buildFormatter(conf.Formatter) - if err != nil { - return nil, err - } - - w := metrics.NewStdoutWriter(formatter) - return &w, nil -} - func buildFormatter(conf string) (metrics.Formatter, error) { switch conf { case "JSON": diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 688276468..6e9bab0b6 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -26,8 +26,8 @@ import ( "github.com/pfnet-research/k8s-cluster-simulator/pkg/metrics" ) -func TestBuildMetricsFile(t *testing.T) { - _, err := BuildMetricsFile([]MetricsFileConfig{MetricsFileConfig{ +func TestBuildMetricsLogger(t *testing.T) { + _, err := BuildMetricsLogger([]MetricsLoggerConfig{MetricsLoggerConfig{ Path: "", Formatter: "", }}) @@ -35,7 +35,7 @@ func TestBuildMetricsFile(t *testing.T) { t.Error("nil error") } - _, err = BuildMetricsFile([]MetricsFileConfig{MetricsFileConfig{ + _, err = BuildMetricsLogger([]MetricsLoggerConfig{MetricsLoggerConfig{ Path: "", Formatter: "foo", }}) @@ -43,7 +43,7 @@ func TestBuildMetricsFile(t *testing.T) { t.Error("nil error") } - _, err = BuildMetricsFile([]MetricsFileConfig{MetricsFileConfig{ + _, err = BuildMetricsLogger([]MetricsLoggerConfig{MetricsLoggerConfig{ Path: "foo", Formatter: "", }}) @@ -52,29 +52,6 @@ func TestBuildMetricsFile(t *testing.T) { } } -func TestBuildMetricsStdout(t *testing.T) { - actual, err := BuildMetricsStdout(MetricsStdoutConfig{ - Formatter: "", - }) - if actual != nil || err != nil { - t.Errorf("got: (%+v, %+v)\nwant: (nil, nil)", actual, err) - } - - _, err = BuildMetricsStdout(MetricsStdoutConfig{ - Formatter: "foo", - }) - if err == nil { - t.Error("nil error") - } - - _, err = BuildMetricsStdout(MetricsStdoutConfig{ - Formatter: "JSON", - }) - if err != nil { - t.Errorf("error %s", err.Error()) - } -} - func TestBuildFormatter(t *testing.T) { actual0, _ := buildFormatter("JSON") expected0 := &metrics.JSONFormatter{} diff --git a/pkg/kubesim.go b/pkg/kubesim.go index 3a95b746d..456ad954a 100644 --- a/pkg/kubesim.go +++ b/pkg/kubesim.go @@ -259,7 +259,7 @@ func buildCluster(conf *config.Config) (map[string]*node.Node, error) { func buildMetricsWriters(conf *config.Config) ([]metrics.Writer, error) { writers := []metrics.Writer{} - fileWriters, err := config.BuildMetricsFile(conf.MetricsFile) + fileWriters, err := config.BuildMetricsLogger(conf.MetricsLogger) if err != nil { return []metrics.Writer{}, err } @@ -269,15 +269,6 @@ func buildMetricsWriters(conf *config.Config) ([]metrics.Writer, error) { writers = append(writers, writer) } - stdoutWriter, err := config.BuildMetricsStdout(conf.MetricsStdout) - if err != nil { - return []metrics.Writer{}, err - } - if stdoutWriter != nil { - log.L.Info("Metrics and log written to Stdout") - writers = append(writers, stdoutWriter) - } - return writers, nil } diff --git a/pkg/metrics/file_writer.go b/pkg/metrics/file_writer.go index ebe27a19f..6c648679f 100644 --- a/pkg/metrics/file_writer.go +++ b/pkg/metrics/file_writer.go @@ -25,13 +25,23 @@ type FileWriter struct { } // NewFileWriter creates a new FileWriter with a file at the given path, and the formatter that -// formats metrics to a string. -// If the file exists, it will be truncaed. +// formats metrics to a string +// If /dev/stdout or empty string is given, the standard out is set. +// If /dev/stderr is given, the standard error is set. +// Otherwise, the file of a given path is set and it will be truncated if it exists. // Returns error if failed to create a file. func NewFileWriter(path string, formatter Formatter) (*FileWriter, error) { - file, err := os.Create(path) - if err != nil { - return nil, err + var file *os.File + if path == "/dev/stdout" || path == "stdout" || path == "" { + file = os.Stdout + } else if path == "/dev/stderr" || path == "stderr" { + file = os.Stderr + } else { + f, err := os.Create(path) + if err != nil { + return nil, err + } + file = f } return &FileWriter{