@@ -42,6 +42,7 @@ struct flb_file_conf {
4242 const char * out_file ;
4343 const char * delimiter ;
4444 const char * label_delimiter ;
45+ const char * template ;
4546 int format ;
4647};
4748
@@ -84,6 +85,7 @@ static int cb_file_init(struct flb_output_instance *ins,
8485 conf -> format = FLB_OUT_FILE_FMT_JSON ; /* default */
8586 conf -> delimiter = NULL ;
8687 conf -> label_delimiter = NULL ;
88+ conf -> template = NULL ;
8789
8890 /* Optional output file name/path */
8991 tmp = flb_output_get_property ("Path" , ins );
@@ -113,6 +115,10 @@ static int cb_file_init(struct flb_output_instance *ins,
113115 conf -> delimiter = NULL ;
114116 conf -> label_delimiter = NULL ;
115117 }
118+ else if (!strcasecmp (tmp , "template" )) {
119+ conf -> format = FLB_OUT_FILE_FMT_TEMPLATE ;
120+ conf -> template = "{time} {message}" ;
121+ }
116122 }
117123
118124 tmp = flb_output_get_property ("delimiter" , ins );
@@ -127,6 +133,11 @@ static int cb_file_init(struct flb_output_instance *ins,
127133 conf -> label_delimiter = ret_str ;
128134 }
129135
136+ tmp = flb_output_get_property ("template" , ins );
137+ if (tmp != NULL ) {
138+ conf -> template = tmp ;
139+ }
140+
130141 /* Set the context */
131142 flb_output_set_context (ins , conf );
132143
@@ -186,6 +197,100 @@ static int ltsv_output(FILE *fp, struct flb_time *tm, msgpack_object *obj,
186197 return 0 ;
187198}
188199
200+ static int template_output_write (FILE * fp , struct flb_time * tm , msgpack_object * obj ,
201+ const char * key , int size )
202+ {
203+ int i ;
204+ msgpack_object_kv * kv ;
205+
206+ /*
207+ * Right now we treat "{time}" specially and fill the placeholder
208+ * with the metadata timestamp (formatted as float).
209+ */
210+ if (!strncmp (key , "time" , size )) {
211+ fprintf (fp , "%f" , flb_time_to_double (tm ));
212+ return 0 ;
213+ }
214+
215+ if (obj -> type != MSGPACK_OBJECT_MAP ) {
216+ flb_error ("[out_file] invalid object type (type=%i)" , obj -> type );
217+ return -1 ;
218+ }
219+
220+ for (i = 0 ; i < obj -> via .map .size ; i ++ ) {
221+ kv = obj -> via .map .ptr + i ;
222+
223+ if (size != kv -> key .via .str .size ) {
224+ continue ;
225+ }
226+
227+ if (!memcmp (key , kv -> key .via .str .ptr , size )) {
228+ if (kv -> val .type == MSGPACK_OBJECT_STR ) {
229+ fwrite (kv -> val .via .str .ptr , 1 , kv -> val .via .str .size , fp );
230+ } else {
231+ msgpack_object_print (fp , kv -> val );
232+ }
233+ return 0 ;
234+ }
235+ }
236+ return -1 ;
237+ }
238+
239+ /*
240+ * Python-like string templating for out_file.
241+ *
242+ * This accepts a format string like "my name is {name}" and fills
243+ * placeholders using corresponding values in a record.
244+ *
245+ * e.g. {"name":"Tom"} => "my name is Tom"
246+ */
247+ static int template_output (FILE * fp , struct flb_time * tm , msgpack_object * obj ,
248+ struct flb_file_conf * ctx )
249+ {
250+ int i ;
251+ int len = strlen (ctx -> template );
252+ int keysize ;
253+ const char * key ;
254+ const char * pos ;
255+ const char * inbrace = NULL ; /* points to the last open brace */
256+
257+ for (i = 0 ; i < len ; i ++ ) {
258+ pos = ctx -> template + i ;
259+ if (* pos == '{' ) {
260+ if (inbrace ) {
261+ /*
262+ * This means that we find another open brace inside
263+ * braces (e.g. "{a{b}"). Ignore the previous one.
264+ */
265+ fwrite (inbrace , 1 , pos - inbrace , fp );
266+ }
267+ inbrace = pos ;
268+ }
269+ else if (* pos == '}' && inbrace ) {
270+ key = inbrace + 1 ;
271+ keysize = pos - inbrace - 1 ;
272+
273+ if (template_output_write (fp , tm , obj , key , keysize )) {
274+ fwrite (inbrace , 1 , pos - inbrace + 1 , fp );
275+ }
276+ inbrace = NULL ;
277+ }
278+ else {
279+ if (!inbrace ) {
280+ fputc (* pos , fp );
281+ }
282+ }
283+ }
284+
285+ /* Handle an unclosed brace like "{abc" */
286+ if (inbrace ) {
287+ fputs (inbrace , fp );
288+ }
289+ fputs (NEWLINE , fp );
290+ return 0 ;
291+ }
292+
293+
189294static int plain_output (FILE * fp , msgpack_object * obj , size_t alloc_size )
190295{
191296 char * buf ;
@@ -306,6 +411,9 @@ static void cb_file_flush(const void *data, size_t bytes,
306411 case FLB_OUT_FILE_FMT_PLAIN :
307412 plain_output (fp , obj , alloc_size );
308413 break ;
414+ case FLB_OUT_FILE_FMT_TEMPLATE :
415+ template_output (fp , & tm , obj , ctx );
416+ break ;
309417 }
310418 }
311419
0 commit comments