From 7ba58e134d9a6a0bf76317c006f2a480c0c22b72 Mon Sep 17 00:00:00 2001 From: silverboots Date: Sat, 18 Jun 2016 21:04:41 +0100 Subject: [PATCH] introduce timestamps to file content and path new parameter to allow timestamp prefix to each line in file. Also, add ability to introduce time parameters in path and file name. Will also create missing directories if required. --- plugins/outputs/file/file.go | 55 +++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/plugins/outputs/file/file.go b/plugins/outputs/file/file.go index 1d47642b2..4e85f138f 100644 --- a/plugins/outputs/file/file.go +++ b/plugins/outputs/file/file.go @@ -4,6 +4,8 @@ import ( "fmt" "io" "os" + "strings" + "time" "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/plugins/outputs" @@ -13,6 +15,8 @@ import ( type File struct { Files []string + Timestamp bool + writer io.Writer closers []io.Closer @@ -23,6 +27,9 @@ var sampleConfig = ` ## Files to write to, "stdout" is a specially handled file. files = ["stdout", "/tmp/metrics.out"] + ## Prefix each output line with timestamp + timestamp = true + ## Data format to output. ## Each data format has it's own unique set of configuration options, read ## more about them here: @@ -48,13 +55,24 @@ func (f *File) Connect() error { } else { var of *os.File var err error - if _, err := os.Stat(file); os.IsNotExist(err) { - of, err = os.Create(file) + generatedFile := generateFileName(file) + fmt.Printf("writing to output file [%s]", generatedFile) + if _, err := os.Stat(generatedFile); os.IsNotExist(err) { + // create directory f it doesn't exist + lastSlash := strings.LastIndex(generatedFile, "/") + if lastSlash != -1 { + err = os.MkdirAll(generatedFile[:lastSlash], os.ModeDir) + } + // create file if it doesn't exist + if err == nil { + of, err = os.Create(generatedFile) + } } else { - of, err = os.OpenFile(file, os.O_APPEND|os.O_WRONLY, os.ModeAppend) + of, err = os.OpenFile(generatedFile, os.O_APPEND|os.O_WRONLY, os.ModeAppend) } if err != nil { + fmt.Errorf("Failed to initialise file [%s] [%s]", generatedFile, err) return err } writers = append(writers, of) @@ -91,6 +109,12 @@ func (f *File) Write(metrics []telegraf.Metric) error { return nil } + prefix := "" + if f.Timestamp { + t := time.Now().UTC() + prefix = t.Format(time.RFC3339) + " " + } + for _, metric := range metrics { values, err := f.serializer.Serialize(metric) if err != nil { @@ -98,7 +122,7 @@ func (f *File) Write(metrics []telegraf.Metric) error { } for _, value := range values { - _, err = f.writer.Write([]byte(value + "\n")) + _, err = f.writer.Write([]byte(prefix + value + "\n")) if err != nil { return fmt.Errorf("FAILED to write message: %s, %s", value, err) } @@ -107,6 +131,29 @@ func (f *File) Write(metrics []telegraf.Metric) error { return nil } +// Generate filename, replace tokens enclosed by { and } with time format +func generateFileName(s string) string { + t := time.Now().UTC() + //split on opening brace + tokens := strings.Split(s, "{") + // first token has no left bracket + outputString := tokens[0] + // cycle through remaining tokens + for j := 1; j < len(tokens); j++ { + //find closing brace + index := strings.Index(tokens[j], "}") + // if -1 we have opening brace with no closing brace so we don't format + if index == -1 { + outputString += tokens[j] + } else { + // Extract enclosed token and format, concatenate anything after closing brace on output + generatedString := t.Format(tokens[j][:index]) + outputString += generatedString + tokens[j][index+1:] + } + } + return outputString +} + func init() { outputs.Add("file", func() telegraf.Output { return &File{}