Commit | Line | Data |
---|---|---|
c8c75648 SK |
1 | -module(life_observer). |
2 | -behaviour(gen_event). | |
3 | ||
4 | ||
5 | %% API | |
6 | -export([start_link/2 | |
7 | ,register_with_logger/0 | |
8 | ,add_handler/2 | |
9 | ,delete_handler/0 | |
c04c5832 | 10 | ,log_generation/4 |
c8c75648 SK |
11 | ]). |
12 | ||
13 | %% Callbacks | |
14 | -export([init/1 | |
15 | ,terminate/2 | |
16 | ,code_change/3 | |
17 | ,handle_event/2 | |
18 | ,handle_call/2 | |
19 | ,handle_info/2 | |
20 | ]). | |
21 | ||
22 | ||
23 | -define(EVENT_MGR_REF, ?MODULE). | |
24 | -define(HANDLER, ?MODULE). | |
25 | ||
26 | -define(PATH_DIR__DATA, "data"). | |
27 | -define(CSV_DELIMITER, ","). | |
28 | ||
29 | ||
30 | -record(state, {log_file :: file:io_device()}). | |
31 | ||
32 | ||
33 | %% ============================================================================ | |
34 | %% API | |
35 | %% ============================================================================ | |
36 | ||
37 | start_link(X, Y) -> | |
38 | EventMgrName = {local, ?EVENT_MGR_REF}, | |
39 | {ok, PID} = gen_event:start_link(EventMgrName), | |
40 | ok = add_handler(X, Y), | |
41 | {ok, PID}. | |
42 | ||
43 | ||
44 | register_with_logger() -> | |
45 | error_logger:add_report_handler(?HANDLER). | |
46 | ||
47 | ||
48 | add_handler(X, Y) -> | |
49 | Args = [X, Y], | |
50 | gen_event:add_handler(?EVENT_MGR_REF, ?HANDLER, Args). | |
51 | ||
52 | ||
53 | delete_handler() -> | |
54 | Args = [], | |
55 | gen_event:delete_handler(?EVENT_MGR_REF, ?HANDLER, Args). | |
56 | ||
57 | ||
c04c5832 SK |
58 | log_generation(GenID, GenDuration, Dead, Alive) -> |
59 | Event = {generation, GenID, GenDuration, Dead, Alive}, | |
c8c75648 SK |
60 | gen_event:notify(?EVENT_MGR_REF, Event). |
61 | ||
62 | ||
63 | %% ============================================================================ | |
64 | %% Callbacks (unused) | |
65 | %% ============================================================================ | |
66 | ||
67 | code_change(_Old, State, _Other) -> {ok, State}. | |
68 | handle_call(_Request, State) -> Reply = ok, {ok, Reply, State}. | |
69 | handle_info(_Info, State) -> {ok, State}. | |
70 | ||
71 | ||
72 | %% ============================================================================ | |
73 | %% Callbacks | |
74 | %% ============================================================================ | |
75 | ||
76 | init([X, Y]) -> | |
77 | N = X * Y, | |
78 | {{Year, Month, Day}, {Hour, Min, Sec}} = calendar:local_time(), | |
79 | DateTime = lists:flatten(io_lib:format( | |
80 | "~4.10.0B-~2.10.0B-~2.10.0B--~2.10.0B:~2.10.0B:~2.10.0B", | |
81 | [Year, Month, Day, Hour, Min, Sec] | |
82 | )), | |
83 | ||
84 | FileNameComponents = [DateTime | [integer_to_list(I) || I <- [N, X, Y]]], | |
85 | FileName = string:join(FileNameComponents, "--") ++ ".csv", | |
86 | FilePath = filename:join(?PATH_DIR__DATA, FileName), | |
87 | ||
88 | ok = validate_makedir(file:make_dir(?PATH_DIR__DATA)), | |
89 | {ok, LogFile} = file:open(FilePath, write), | |
90 | ||
c04c5832 | 91 | CSVHeaders = ["Generation", "Duration", "Dead", "Alive"], |
c8c75648 SK |
92 | ok = do_write(LogFile, list_to_csvline(CSVHeaders)), |
93 | ||
94 | {ok, #state{log_file=LogFile}}. | |
95 | ||
96 | ||
97 | terminate(_Reason, #state{log_file=LogFile}=State) -> | |
98 | file:close(LogFile), | |
99 | {ok, State}. | |
100 | ||
101 | ||
c04c5832 | 102 | handle_event({generation, GenID, GenDuration, Dead, Alive}, |
c8c75648 SK |
103 | #state{log_file=LogFile}=State) -> |
104 | ||
c04c5832 SK |
105 | Values = [integer_to_list(GenID) |
106 | ,float_to_string(GenDuration) | |
107 | ,integer_to_list(Dead) | |
108 | ,integer_to_list(Alive) | |
109 | ], | |
c8c75648 SK |
110 | ok = do_write(LogFile, list_to_csvline(Values)), |
111 | {ok, State}. | |
112 | ||
113 | ||
114 | %% ============================================================================ | |
115 | %% Internal | |
116 | %% ============================================================================ | |
117 | ||
118 | validate_makedir(ok) -> ok; | |
119 | validate_makedir({error, eexist}) -> ok; | |
120 | validate_makedir(Other) -> Other. | |
121 | ||
122 | ||
123 | do_write(File, Line) -> | |
124 | ok = io:format(File, "~s~n", [Line]). | |
125 | ||
126 | ||
127 | list_to_csvline(List) -> | |
128 | string:join(List, ?CSV_DELIMITER). | |
c04c5832 SK |
129 | |
130 | ||
131 | float_to_string(Float) -> | |
132 | io_lib:format("~f", [Float]). |