github.com/Jeffail/benthos/v3@v3.65.0/lib/output/stdout.go (about) 1 package output 2 3 import ( 4 "context" 5 "os" 6 "time" 7 8 "github.com/Jeffail/benthos/v3/internal/codec" 9 "github.com/Jeffail/benthos/v3/internal/docs" 10 "github.com/Jeffail/benthos/v3/internal/shutdown" 11 "github.com/Jeffail/benthos/v3/lib/log" 12 "github.com/Jeffail/benthos/v3/lib/metrics" 13 "github.com/Jeffail/benthos/v3/lib/output/writer" 14 "github.com/Jeffail/benthos/v3/lib/types" 15 ) 16 17 //------------------------------------------------------------------------------ 18 19 var multipartCodecDoc = (` 20 ## Batches and Multipart Messages 21 22 When writing multipart (batched) messages using the ` + "`lines`" + ` codec the last message ends with double delimiters. E.g. the messages "foo", "bar" and "baz" would be written as: 23 24 ` + "```" + ` 25 foo\n 26 bar\n 27 baz\n 28 ` + "```" + ` 29 30 Whereas a multipart message [ "foo", "bar", "baz" ] would be written as: 31 32 ` + "```" + ` 33 foo\n 34 bar\n 35 baz\n\n 36 ` + "```" + ` 37 38 This enables consumers of this output feed to reconstruct the original batches. However, if you wish to avoid this behaviour then add a ` + "[`split` processor](/docs/components/processors/split)" + ` before messages reach this output.`)[1:] 39 40 func init() { 41 Constructors[TypeSTDOUT] = TypeSpec{ 42 constructor: fromSimpleConstructor(NewSTDOUT), 43 Summary: ` 44 Prints messages to stdout as a continuous stream of data, dividing messages according to the specified codec.`, 45 Description: multipartCodecDoc, 46 FieldSpecs: docs.FieldSpecs{ 47 codec.WriterDocs.AtVersion("3.46.0"), 48 docs.FieldDeprecated("delimiter"), 49 }, 50 Categories: []Category{ 51 CategoryLocal, 52 }, 53 } 54 } 55 56 //------------------------------------------------------------------------------ 57 58 // STDOUTConfig contains configuration fields for the stdout based output type. 59 type STDOUTConfig struct { 60 Codec string `json:"codec" yaml:"codec"` 61 Delim string `json:"delimiter" yaml:"delimiter"` 62 } 63 64 // NewSTDOUTConfig creates a new STDOUTConfig with default values. 65 func NewSTDOUTConfig() STDOUTConfig { 66 return STDOUTConfig{ 67 Codec: "lines", 68 Delim: "", 69 } 70 } 71 72 //------------------------------------------------------------------------------ 73 74 // NewSTDOUT creates a new STDOUT output type. 75 func NewSTDOUT(conf Config, mgr types.Manager, log log.Modular, stats metrics.Type) (Type, error) { 76 if len(conf.STDOUT.Delim) > 0 { 77 conf.STDOUT.Codec = "delim:" + conf.STDOUT.Delim 78 } 79 f, err := newStdoutWriter(conf.STDOUT.Codec, log, stats) 80 if err != nil { 81 return nil, err 82 } 83 w, err := NewAsyncWriter(TypeSTDOUT, 1, f, log, stats) 84 if err != nil { 85 return nil, err 86 } 87 if aw, ok := w.(*AsyncWriter); ok { 88 aw.SetNoCancel() 89 } 90 return w, nil 91 } 92 93 type stdoutWriter struct { 94 handle codec.Writer 95 shutSig *shutdown.Signaller 96 } 97 98 func newStdoutWriter(codecStr string, log log.Modular, stats metrics.Type) (*stdoutWriter, error) { 99 codec, _, err := codec.GetWriter(codecStr) 100 if err != nil { 101 return nil, err 102 } 103 104 handle, err := codec(os.Stdout) 105 if err != nil { 106 return nil, err 107 } 108 109 return &stdoutWriter{ 110 handle: handle, 111 shutSig: shutdown.NewSignaller(), 112 }, nil 113 } 114 115 func (w *stdoutWriter) ConnectWithContext(ctx context.Context) error { 116 return nil 117 } 118 119 func (w *stdoutWriter) WriteWithContext(ctx context.Context, msg types.Message) error { 120 err := writer.IterateBatchedSend(msg, func(i int, p types.Part) error { 121 return w.handle.Write(ctx, p) 122 }) 123 if err != nil { 124 return err 125 } 126 if msg.Len() > 1 { 127 if w.handle != nil { 128 w.handle.EndBatch() 129 } 130 } 131 return nil 132 } 133 134 func (w *stdoutWriter) CloseAsync() { 135 } 136 137 func (w *stdoutWriter) WaitForClose(timeout time.Duration) error { 138 return nil 139 }