Erlang: запись таблицы мнезии в .csv по одной записи в строке

У меня есть таблица Mnesia, которая имеет следующий формат:

-record(state, {key, tuple, state, timestamp, fin_from}).

Записи выглядят следующим образом (читается с ets:tab2list(Tab)):

[{state,{80,43252,tcp,tcp_syn_received,{192,168,101,5},{192,168,101,89}},
        {80,43252,tcp,{192,168,101,5},{192,168,101,89}},
        tcp_syn_received,1463850419221,undefined},
 {state,{80,41570,tcp,tcp_syn_received,{192,168,101,5},{192,168,101,89}},
        {80,41570,tcp,{192,168,101,5},{192,168,101,89}},
        tcp_syn_received,1463850403214,undefined},
...]

Я хотел бы записать эти данные в файл .csv с одной записью в строке - предпочтительно в следующем формате:

state,80,43252,tcp,tcp_syn_received,192.168.101.5,192.168.101.89,80,43252,tcp,192.168.101.5,192.168.101.89,tcp_syn_received,1463850419221,undefined
state,80,41570,tcp,tcp_syn_received,192.168.101.5,192.168.101.89,80,41570,tcp,192.168.101.5,192.168.101.89,tcp_syn_received,1463850419221,undefined

После undefined должен быть разрыв строки. Я пробовал использовать следующий код (пока Content = ets:tab2list(states)):

do_logging_async(File, Format, Content, Append)->
F = fun() ->
    file:write_file(File, io_lib:fwrite(Format, [Content]), [Append])
end,
spawn(F).

Однако я не могу получить ничего похожего на свой результат. После этого данные следует проанализировать с помощью R.

ОБНОВЛЕНИЕ: ключ заключался в том, чтобы читать таблицу построчно и анализировать ее с помощью ~w, но не ~p. В итоге я получил следующее решение (которое дает немного другой результат, однако в нем меньше избыточных данных):

do_state_logging(File, EtsAsList) ->
% write header (columnnames)
file:write_file(File, io_lib:fwrite("~w,~w,~w,~w,~w,~w,~w,~w~n", [record,dstPort,srcPort,proto,dstIP,srcIP,state,timestamp]),[append]),
case EtsAsList of
    [] ->
        ok;
    _ ->
        F = fun({Record,_Key, 
            [P1, P2, Proto, {D_Ip_1,D_Ip_2,D_Ip_3,D_Ip_4}, {S_Ip_1,S_Ip_2,S_Ip_3,S_Ip_4}],
            State, Timestamp, _}) -> 
            file:write_file(File, io_lib:fwrite("~w,", [Record]),[append]),
            file:write_file(File, io_lib:fwrite("~w,~w,~w,", [P1,P2,Proto]),[append]),
            file:write_file(File, io_lib:fwrite("~w.~w.~w.~w,", [D_Ip_1,D_Ip_2,D_Ip_3,D_Ip_4]), [append]),
            file:write_file(File, io_lib:fwrite("~w.~w.~w.~w,", [S_Ip_1,S_Ip_2,S_Ip_3,S_Ip_4]), [append]),
            file:write_file(File, io_lib:fwrite("~w,", [State]),[append]),
            file:write_file(File, io_lib:fwrite("~w", [Timestamp]),[append]),
            file:write_file(File, ["\n"],[append]) 
        end,
        lists:foreach(F, EtsAsList)
    end,
    io:format("Finished logging of statetable to file: ~p~n" , [File]).

Спасибо ответу, который подтолкнул меня к этой идее.


person muehsi    schedule 21.05.2016    source источник
comment
Можно ли сохранить значения ets в виде списков, а не кортежей? т.е. [80,43252,tcp,tcp_syn_received,[192,168,101,5],[192,168,101,89]], [80,43252,tcp,[192,168,101,5],[192,168,101,89]], tcp_syn_received,1463850419221,undefined]. Потому что тогда будет проще сгладить и записать каждую сглаженную запись в виде строки.   -  person A. Sarid    schedule 21.05.2016
comment
Да, я смогу это сделать. Но как потом разобрать отдельные строки (и списки)?   -  person muehsi    schedule 21.05.2016


Ответы (1)


Предполагая, что вы измените значения записей ETS, чтобы они находились в списках, а не в кортежах, вы можете использовать этот код для записи таблицы ETS в файл.

do_logging_async(File, EtsAsList) ->
    F = fun({Key, Value}) -> 
        file:write_file(File, [atom_to_list(Key) ++ ","],[append]),
        write_value(File,lists:flatten(Value)),
        file:write_file(File, ["\n"],[append]) 
    end,
    lists:foreach(F,EtsAsList).


write_value(_File, []) -> ok;
write_value(File, [H|T]) ->
    case is_integer(H) of
        true -> file:write_file(File, [integer_to_list(H)],[append]);
        false -> file:write_file(File, [atom_to_list(H)],[append])
    end,
    case T=:=[] of
        true -> ok;
        false -> file:write_file(File, [","],[append])
    end,
    write_value(File,T).

do_logging_async/2 берет каждую {Key, Value} пару. Сначала он записывает Key в файл, а затем запускает write_value/2 на Value, в конце каждой пары записывает \n.

write_value/2 берет плоский список значений (предполагается, что это плоский список, содержащий только целые числа и атомы) и записывает его в файл.

person A. Sarid    schedule 21.05.2016
comment
Я адаптировал его под свой формат: do_logging_async(File, EtsAsList) -> lists:foreach(fun({state, Key, Key_no_state, State, Timestamp, _Val4}) -> %io:format("Writing during this Iteration: { Key, Key_no_state, State, Timestamp, _Val4} ~p~n",[{Key, Key_no_state, State, Timestamp, _Val4}]), file:write_file(File, [Key ++ ","],[append]),... write_value(File,lists:flatten([Timestamp])), file:write_file(File, ["\n"],[append]) end, EtsAsList). Однако пишутся только временные метки. file: write_file () return {error, badargs} .. не знаю, как продолжить .. - person muehsi; 22.05.2016
comment
Вам нужно изменить свои пары ets {Key, Value} на {state, [Key, Key_no_state, State, Timestamp, Fin_from]}, а затем просто использовать мой код как есть, и он должен работать. - person A. Sarid; 22.05.2016