@@ -45,7 +45,7 @@ argparse_def(record_stream) ->
4545 long => " -format" ,
4646 short => $f ,
4747 type => {atom , [plain , json ]},
48- nargs => 1 ,
48+ default => plain ,
4949 help => " Format output acccording to <FORMAT>" }
5050 ]
5151 }.
@@ -80,20 +80,17 @@ init(#{progname := Progname}) ->
8080 {ok , State }.
8181
8282handle_call (
83- {start_record_stream , Name , Fields , _ArgMap },
83+ {start_record_stream , Name , Fields , ArgMap },
8484 From ,
8585 #? MODULE {record_streams = Streams } = State ) ->
86- Stream = #{name => Name , fields => Fields },
86+ Stream = #{name => Name , fields => Fields , arg_map => ArgMap },
87+ Streams1 = Streams #{Name => Stream },
88+ State1 = State #? MODULE {record_streams = Streams1 },
8789 gen_server :reply (From , {ok , Stream }),
8890
89- FieldNames = [atom_to_list (FieldName )
90- || #{name := FieldName } <- Fields ],
91- Header = string :join (FieldNames , " \t " ),
92- io :format (" ~ts~n " , [Header ]),
91+ {ok , State2 } = format_record_stream_start (Name , State1 ),
9392
94- Streams1 = Streams #{Name => Stream },
95- State1 = State #? MODULE {record_streams = Streams1 },
96- {noreply , State1 };
93+ {noreply , State2 };
9794handle_call (stop , _From , State ) ->
9895 {stop , normal , ok , State };
9996handle_call (_Request , _From , State ) ->
@@ -109,16 +106,12 @@ handle_cast(
109106 Help = argparse :help (ArgparseDef , Options ),
110107 io :format (" ~s~n " , [Help ]),
111108 {noreply , State };
112- handle_cast (
113- {push_new_record , Name , Record },
114- #? MODULE {record_streams = Streams } = State ) ->
115- #{fields := Fields } = maps :get (Name , Streams ),
116- Values = format_fields (Fields , Record ),
117- Line = string :join (Values , " \t " ),
118- io :format (" ~ts~n " , [Line ]),
119- {noreply , State };
120- handle_cast ({end_record_stream , _Name }, State ) ->
121- {noreply , State };
109+ handle_cast ({push_new_record , Name , Record }, State ) ->
110+ {ok , State1 } = format_record (Name , Record , State ),
111+ {noreply , State1 };
112+ handle_cast ({end_record_stream , Name }, State ) ->
113+ {ok , State1 } = format_record_stream_end (Name , State ),
114+ {noreply , State1 };
122115handle_cast (_Request , State ) ->
123116 {noreply , State }.
124117
@@ -131,13 +124,108 @@ terminate(_Reason, _State) ->
131124code_change (_OldVsn , State , _Extra ) ->
132125 {ok , State }.
133126
127+ format_record_stream_start (
128+ Name ,
129+ #? MODULE {record_streams = Streams } = State ) ->
130+ Stream = maps :get (Name , Streams ),
131+ format_record_stream_start1 (Stream , State ).
132+
133+ format_record_stream_start1 (
134+ #{name := Name , fields := Fields , arg_map := #{format := plain }} = Stream ,
135+ #? MODULE {record_streams = Streams } = State ) ->
136+ FieldNames = [atom_to_list (FieldName ) || #{name := FieldName } <- Fields ],
137+ FieldWidths = [case Field of
138+ #{type := string , name := FieldName } ->
139+ lists :max ([length (atom_to_list (FieldName )), 20 ]);
140+ #{name := FieldName } ->
141+ length (atom_to_list (FieldName ))
142+ end || Field <- Fields ],
143+ Format0 = [rabbit_misc :format (" ~~ -~b .. ts" , [Width ])
144+ || Width <- FieldWidths ],
145+ Format1 = string :join (Format0 , " " ),
146+ case isatty (standard_io ) of
147+ true ->
148+ io :format (" \033 [1m" ++ Format1 ++ " \033 [0m~n " , FieldNames );
149+ false ->
150+ io :format (Format1 ++ " ~n " , FieldNames )
151+ end ,
152+ Stream1 = Stream #{format => Format1 },
153+ Streams1 = Streams #{Name => Stream1 },
154+ State1 = State #? MODULE {record_streams = Streams1 },
155+ {ok , State1 };
156+ format_record_stream_start1 (
157+ #{name := Name , arg_map := #{format := json }} = Stream ,
158+ #? MODULE {record_streams = Streams } = State ) ->
159+ Stream1 = Stream #{emitted_fields => 0 },
160+ Streams1 = Streams #{Name => Stream1 },
161+ State1 = State #? MODULE {record_streams = Streams1 },
162+ {ok , State1 }.
163+
164+ format_record (Name , Record , #? MODULE {record_streams = Streams } = State ) ->
165+ Stream = maps :get (Name , Streams ),
166+ format_record1 (Stream , Record , State ).
167+
168+ format_record1 (
169+ #{fields := Fields , arg_map := #{format := plain },
170+ format := Format },
171+ Record ,
172+ State ) ->
173+ Values = format_fields (Fields , Record ),
174+ io :format (Format ++ " ~n " , Values ),
175+ {ok , State };
176+ format_record1 (
177+ #{fields := Fields , arg_map := #{format := json },
178+ name := Name , emitted_fields := Emitted } = Stream ,
179+ Record ,
180+ #? MODULE {record_streams = Streams } = State ) ->
181+ Fields1 = [FieldName || #{name := FieldName } <- Fields ],
182+ Struct = lists :zip (Fields1 , Record ),
183+ Json = json :encode (
184+ Struct ,
185+ fun
186+ ([{_ , _ } | _ ] = Value , Encode ) ->
187+ json :encode_key_value_list (Value , Encode );
188+ (Value , Encode ) ->
189+ json :encode_value (Value , Encode )
190+ end ),
191+ case Emitted of
192+ 0 ->
193+ io :format (" [~n ~ts " , [Json ]);
194+ _ ->
195+ io :format (" ,~n ~ts " , [Json ])
196+ end ,
197+ Stream1 = Stream #{emitted_fields => Emitted + 1 },
198+ Streams1 = Streams #{Name => Stream1 },
199+ State1 = State #? MODULE {record_streams = Streams1 },
200+ {ok , State1 }.
201+
202+ format_record_stream_end (
203+ Name ,
204+ #? MODULE {record_streams = Streams } = State ) ->
205+ Stream = maps :get (Name , Streams ),
206+ {ok , State1 } = format_record_stream_end1 (Stream , State ),
207+ #? MODULE {record_streams = Streams1 } = State1 ,
208+ Streams2 = maps :remove (Name , Streams1 ),
209+ State2 = State1 #? MODULE {record_streams = Streams2 },
210+ {ok , State2 }.
211+
212+ format_record_stream_end1 (#{arg_map := #{format := plain }}, State ) ->
213+ {ok , State };
214+ format_record_stream_end1 (#{arg_map := #{format := json }}, State ) ->
215+ io :format (" ~n ]~n " , []),
216+ {ok , State }.
217+
134218format_fields (Fields , Values ) ->
135219 format_fields (Fields , Values , []).
136220
137221format_fields ([#{type := string } | Rest1 ], [Value | Rest2 ], Acc ) ->
138222 String = io_lib :format (" ~ts " , [Value ]),
139223 Acc1 = [String | Acc ],
140224 format_fields (Rest1 , Rest2 , Acc1 );
225+ format_fields ([#{type := binary } | Rest1 ], [Value | Rest2 ], Acc ) ->
226+ String = io_lib :format (" ~-20.. ts " , [Value ]),
227+ Acc1 = [String | Acc ],
228+ format_fields (Rest1 , Rest2 , Acc1 );
141229format_fields ([#{type := integer } | Rest1 ], [Value | Rest2 ], Acc ) ->
142230 String = io_lib :format (" ~b " , [Value ]),
143231 Acc1 = [String | Acc ],
@@ -146,14 +234,18 @@ format_fields([#{type := boolean} | Rest1], [Value | Rest2], Acc) ->
146234 String = io_lib :format (" ~ts " , [if Value -> " ☑" ; true -> " ☐" end ]),
147235 Acc1 = [String | Acc ],
148236 format_fields (Rest1 , Rest2 , Acc1 );
149- format_fields ([#{type := resource } | Rest1 ], [Value | Rest2 ], Acc ) ->
150- # resource {name = Name } = Value ,
151- String = io_lib :format (" ~ts " , [Name ]),
152- Acc1 = [String | Acc ],
153- format_fields (Rest1 , Rest2 , Acc1 );
154237format_fields ([#{type := term } | Rest1 ], [Value | Rest2 ], Acc ) ->
155238 String = io_lib :format (" ~0p " , [Value ]),
156239 Acc1 = [String | Acc ],
157240 format_fields (Rest1 , Rest2 , Acc1 );
158241format_fields ([], [], Acc ) ->
159242 lists :reverse (Acc ).
243+
244+ isatty (IoDevice ) ->
245+ Opts = io :getopts (IoDevice ),
246+ case proplists :get_value (stdout , Opts ) of
247+ true ->
248+ true ;
249+ _ ->
250+ false
251+ end .
0 commit comments