github.com/observiq/carbon@v0.9.11-0.20200820160507-1b872e368a5e/operator/builtin/output/file.go (about) 1 package output 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "html/template" 8 "os" 9 "sync" 10 11 "github.com/observiq/carbon/entry" 12 "github.com/observiq/carbon/operator" 13 "github.com/observiq/carbon/operator/helper" 14 ) 15 16 func init() { 17 operator.Register("file_output", func() operator.Builder { return NewFileOutputConfig("") }) 18 } 19 20 func NewFileOutputConfig(operatorID string) *FileOutputConfig { 21 return &FileOutputConfig{ 22 OutputConfig: helper.NewOutputConfig(operatorID, "file_output"), 23 } 24 } 25 26 // FileOutputConfig is the configuration of a file output operatorn. 27 type FileOutputConfig struct { 28 helper.OutputConfig `yaml:",inline"` 29 30 Path string `json:"path" yaml:"path"` 31 Format string `json:"format,omitempty" path:"format,omitempty"` 32 } 33 34 // Build will build a file output operator. 35 func (c FileOutputConfig) Build(context operator.BuildContext) (operator.Operator, error) { 36 outputOperator, err := c.OutputConfig.Build(context) 37 if err != nil { 38 return nil, err 39 } 40 41 var tmpl *template.Template 42 if c.Format != "" { 43 tmpl, err = template.New("file").Parse(c.Format) 44 if err != nil { 45 return nil, err 46 } 47 } 48 49 if c.Path == "" { 50 return nil, fmt.Errorf("must provide a path to output to") 51 } 52 53 fileOutput := &FileOutput{ 54 OutputOperator: outputOperator, 55 path: c.Path, 56 tmpl: tmpl, 57 } 58 59 return fileOutput, nil 60 } 61 62 // FileOutput is an operator that writes logs to a file. 63 type FileOutput struct { 64 helper.OutputOperator 65 66 path string 67 tmpl *template.Template 68 encoder *json.Encoder 69 file *os.File 70 mux sync.Mutex 71 } 72 73 // Start will open the output file. 74 func (fo *FileOutput) Start() error { 75 var err error 76 fo.file, err = os.OpenFile(fo.path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0660) 77 if err != nil { 78 return err 79 } 80 81 fo.encoder = json.NewEncoder(fo.file) 82 83 return nil 84 } 85 86 // Stop will close the output file. 87 func (fo *FileOutput) Stop() error { 88 if fo.file != nil { 89 fo.file.Close() 90 } 91 return nil 92 } 93 94 // Process will write an entry to the output file. 95 func (fo *FileOutput) Process(ctx context.Context, entry *entry.Entry) error { 96 fo.mux.Lock() 97 defer fo.mux.Unlock() 98 99 if fo.tmpl != nil { 100 err := fo.tmpl.Execute(fo.file, entry) 101 if err != nil { 102 return err 103 } 104 } else { 105 err := fo.encoder.Encode(entry) 106 if err != nil { 107 return err 108 } 109 } 110 111 return nil 112 }