Skip to content

Commit e9432b1

Browse files
committed
event_flatstore: add time-based rotation (thanks and credits to @razvancrainea)
1 parent 5123cb8 commit e9432b1

File tree

3 files changed

+196
-7
lines changed

3 files changed

+196
-7
lines changed

modules/event_flatstore/doc/event_flatstore_admin.xml

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<chapter>
44

55
<title>&adminguide;</title>
6-
6+
77
<section id="overview" xreflabel="Overview">
88
<title>Overview</title>
99
<para>
@@ -52,7 +52,7 @@
5252
<section>
5353
<title>External Libraries or Applications</title>
5454
<para>
55-
The following libraries or applications must be installed before
55+
The following libraries or applications must be installed before
5656
running &osips; with this module loaded:
5757
<itemizedlist>
5858
<listitem>
@@ -142,6 +142,60 @@ modparam("event_flatstore", "file_permissions", "664")
142142
...
143143
modparam("event_flatstore", "suppress_event_name", 1)
144144
...
145+
</programlisting>
146+
</example>
147+
</section>
148+
<section id="param_rotate_period" xreflabel="rotate_period">
149+
<title><varname>rotate_period</varname> (int)</title>
150+
<para>
151+
When used, it triggers a file auto-rotate. The period is matched
152+
against the absolute time of the machine, can be useful to trigger
153+
auto-rotate every minute, or every hour.
154+
</para>
155+
<para>
156+
<emphasis>
157+
Default value is <quote>0/OFF</quote> (the file is never auto-rotated)
158+
</emphasis>
159+
</para>
160+
<example>
161+
<title>Set <varname>rotate_period</varname> parameter</title>
162+
<programlisting format="linespecific">
163+
...
164+
modparam("event_flatstore", "rotate_period", 60) # rotate every minute
165+
modparam("event_flatstore", "rotate_period", 3660) # rotate every hour
166+
...
167+
</programlisting>
168+
</example>
169+
</section>
170+
<section id="param_suffix" xreflabel="suffix">
171+
<title><varname>suffix</varname> (string)</title>
172+
<para>
173+
Modifies the file that &osips; writes events into by
174+
appending a suffix to the the file specified in the flatstore
175+
<emphasis>socket</emphasis>.
176+
</para>
177+
<para>
178+
The suffix can contain string formats (i.e. variables mixed with
179+
strings). The path of the resulted file is evaluated when the first
180+
event is raised/written in the file after a reload happend, or when
181+
the <emphasis>rotate_period</emphasis>, if specified, triggers a rotate.
182+
</para>
183+
<para>
184+
This parameter does not affect the matching of the event socket -
185+
the matching will be done exclusively using the flatstore
186+
<emphasis>socket</emphasis> registered.
187+
</para>
188+
<para>
189+
<emphasis>
190+
Default value is <quote>""</quote> (no suffix is added)
191+
</emphasis>
192+
</para>
193+
<example>
194+
<title>Set <varname>suffix</varname> parameter</title>
195+
<programlisting format="linespecific">
196+
...
197+
modparam("event_flatstore", "suffix", "$time(%Y)")
198+
...
145199
</programlisting>
146200
</example>
147201
</section>
@@ -172,7 +226,7 @@ modparam("event_flatstore", "suppress_event_name", 1)
172226
<programlisting format="linespecific">
173227
opensips-cli -x mi evi_flat_rotate _path_to_log_file_
174228
</programlisting>
175-
</section>
229+
</section>
176230
</section>
177231
</chapter>
178232

modules/event_flatstore/event_flatstore.c

Lines changed: 138 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
#include "../../evi/evi_transport.h"
3838
#include "../../mem/shm_mem.h"
3939
#include "../../locking.h"
40+
#include "../../timer.h"
41+
#include "../../ipc.h"
4042
#include "../../ut.h"
4143

4244
static int mod_init(void);
@@ -52,6 +54,8 @@ mi_response_t *mi_rotate(const mi_params_t *params,
5254
static int flat_raise(struct sip_msg *msg, str* ev_name, evi_reply_sock *sock,
5355
evi_params_t *params, evi_async_ctx_t *async_ctx);
5456

57+
static void event_flatstore_timer(unsigned int ticks, void *param);
58+
5559
static int *opened_fds;
5660
static int *rotate_version;
5761

@@ -70,6 +74,9 @@ static int initial_capacity = FLAT_DEFAULT_MAX_FD;
7074
static int suppress_event_name = 0;
7175
static str file_permissions;
7276
static mode_t file_permissions_oct;
77+
static int file_rotate_period;
78+
static str file_suffix;
79+
static pv_elem_p file_suffix_format;
7380

7481
static const mi_export_t mi_cmds[] = {
7582
{ "evi_flat_rotate", "rotates the files the module dumps events into", 0,0,{
@@ -84,6 +91,8 @@ static const param_export_t mod_params[] = {
8491
{"delimiter",STR_PARAM, &delimiter.s},
8592
{"file_permissions", STR_PARAM, &file_permissions.s},
8693
{"suppress_event_name", INT_PARAM, &suppress_event_name},
94+
{"rotate_period", INT_PARAM, &file_rotate_period},
95+
{"suffix", STR_PARAM, &file_suffix.s},
8796
{0,0,0}
8897
};
8998

@@ -134,6 +143,20 @@ static int mod_init(void) {
134143

135144
LM_NOTICE("initializing module ...\n");
136145

146+
if (file_rotate_period && file_rotate_period < 0) {
147+
LM_WARN("\"rotate_period\" parameter needs to be a positive integer (%d)! "
148+
"Disabling auto-rotate!\n", file_rotate_period);
149+
file_rotate_period = 0;
150+
}
151+
152+
if (file_suffix.s) {
153+
file_suffix.len = strlen(file_suffix.s);
154+
if (pv_parse_format(&file_suffix, &file_suffix_format) < 0) {
155+
LM_ERR("could not parse file suffix format!\n");
156+
return -1;
157+
}
158+
}
159+
137160
if (register_event_mod(&trans_export_flat)) {
138161
LM_ERR("cannot register transport functions for SCRIPTROUTE\n");
139162
return -1;
@@ -220,6 +243,13 @@ static int mod_init(void) {
220243
for(i = 0; i < initial_capacity; i++)
221244
opened_fds[i] = -1;
222245

246+
if (file_rotate_period &&
247+
register_timer("event_flatstore", event_flatstore_timer, 0,
248+
1, TIMER_FLAG_DELAY_ON_DELAY) < 0) {
249+
LM_ERR("could not add event flatstore routine\n");
250+
return -1;
251+
}
252+
223253
return 0;
224254
}
225255

@@ -490,12 +520,67 @@ static evi_reply_sock* flat_parse(str socket){
490520
return NULL;
491521
}
492522

523+
static char *get_file_path(struct flat_file *file)
524+
{
525+
str format;
526+
char *filepath;
527+
static struct sip_msg req;
528+
529+
/* if suffix not used, the path is always the same */
530+
if (!file_suffix_format) {
531+
file->pathname = file->path.s;
532+
goto end;
533+
}
534+
535+
req.first_line.u.request.method.s= "DUMMY";
536+
req.first_line.u.request.method.len= 5;
537+
req.first_line.u.request.uri.s= "sip:[email protected]";
538+
req.first_line.u.request.uri.len= 19;
539+
req.rcv.src_ip.af = AF_INET;
540+
req.rcv.dst_ip.af = AF_INET;
541+
542+
if (pv_printf_s(&req, file_suffix_format, &format) < 0) {
543+
LM_ERR("could not print the file's format!\n");
544+
goto error;
545+
}
546+
547+
if (!file->pathname) {
548+
filepath = shm_malloc(file->path.len + format.len + 1);
549+
if (!filepath) {
550+
LM_ERR("could not allocate new file's name!\n");
551+
goto error;
552+
}
553+
/* the file path is always the same */
554+
memcpy(filepath, file->path.s, file->path.len);
555+
} else {
556+
filepath = shm_realloc(file->pathname, file->path.len + format.len + 1);
557+
if (!filepath) {
558+
LM_ERR("could not re-allocate new file's name!\n");
559+
goto error;
560+
}
561+
}
562+
memcpy(filepath + file->path.len, format.s, format.len);
563+
filepath[file->path.len + format.len] = '\0';
564+
file->pathname = filepath;
565+
goto end;
566+
567+
error:
568+
/* if there was a previous file, dump data in the same file
569+
* otherwise, in the initial path, no suffix*/
570+
if (!file->pathname)
571+
file->pathname = file->path.s;
572+
end:
573+
LM_DBG("filepath for socket [%s] is [%s]\n", file->path.s, file->pathname);
574+
return file->pathname;
575+
}
576+
493577
/* check if the local 'version' of the file descriptor asociated with entry fs
494578
is different from the global version, if it is different reopen the file
495579
*/
496580
static void rotating(struct flat_file *file){
497581
int index;
498582
int rc;
583+
char *filepath;
499584

500585
if (!file)
501586
return;
@@ -505,7 +590,14 @@ static void rotating(struct flat_file *file){
505590
index = file->file_index_process;
506591

507592
if (opened_fds[index] == -1) {
508-
opened_fds[index] = open(file->path.s,O_RDWR | O_APPEND | O_CREAT, file_permissions_oct);
593+
/* fd not opened in this process */
594+
595+
if (!file->pathname)
596+
filepath = get_file_path(file);
597+
else
598+
/* different process already filled it in */
599+
filepath = file->pathname;
600+
opened_fds[index] = open(filepath, O_RDWR | O_APPEND | O_CREAT, file_permissions_oct);
509601
if (opened_fds[index] < 0) {
510602
LM_ERR("Opening socket error\n");
511603
lock_release(global_lock);
@@ -517,9 +609,9 @@ static void rotating(struct flat_file *file){
517609

518610
lock_release(global_lock);
519611
return;
520-
}
521612

522-
if (rotate_version[index] != file->rotate_version && opened_fds[index] != -1) {
613+
} else if (rotate_version[index] != file->rotate_version) {
614+
/* fd is opened in this process */
523615

524616
/* update version */
525617
rotate_version[index] = file->rotate_version;
@@ -532,7 +624,7 @@ static void rotating(struct flat_file *file){
532624
return;
533625
}
534626

535-
opened_fds[index] = open(file->path.s,O_RDWR | O_APPEND | O_CREAT, file_permissions_oct);
627+
opened_fds[index] = open(file->pathname, O_RDWR | O_APPEND | O_CREAT, file_permissions_oct);
536628
if (opened_fds[index] < 0) {
537629
LM_ERR("Opening socket error\n");
538630
return;
@@ -708,6 +800,44 @@ static str flat_print(evi_reply_sock *sock){
708800
return fs->file->path;
709801
}
710802

803+
void event_flatstore_rotate(int sender, void *param)
804+
{
805+
/* we've been instructed to double check the versions of our sockets */
806+
struct flat_file* file;
807+
int index;
808+
809+
lock_get(global_lock);
810+
for (file = *list_files; file; file = file->next) {
811+
index = file->file_index_process;
812+
if (opened_fds[index] != -1 && rotate_version[index] != file->rotate_version) {
813+
close(opened_fds[index]);
814+
opened_fds[index] = -1; /* open it next time we have an event */
815+
file->counter_open--;
816+
}
817+
}
818+
lock_release(global_lock);
819+
}
820+
821+
static void event_flatstore_timer(unsigned int ticks, void *param)
822+
{
823+
struct flat_file* file;
824+
825+
/* we only run when ticks is multiple of file_rotate_period */
826+
if (time(NULL) % file_rotate_period != 0)
827+
return;
828+
829+
lock_get(global_lock);
830+
for (file = *list_files; file; file = file->next) {
831+
file->rotate_version++;
832+
file->pathname = get_file_path(file);
833+
LM_DBG("File %s is being rotated at %u - new file is %s\n",
834+
file->path.s, ticks, file->pathname);
835+
}
836+
/* inform everyone they need to rotate */
837+
ipc_broadcast_rpc(event_flatstore_rotate, 0);
838+
lock_release(global_lock);
839+
}
840+
711841
static void verify_delete(void) {
712842
struct flat_delete *del_it, *del_prev, *del_tmp;
713843

@@ -750,6 +880,10 @@ static void verify_delete(void) {
750880
else
751881
*list_delete = del_it->next;
752882

883+
if (del_it->file->pathname &&
884+
del_it->file->pathname != del_it->file->path.s)
885+
shm_free(del_it->file->pathname);
886+
753887
del_tmp = del_it;
754888
del_it = del_it->next;
755889
shm_free(del_tmp);

modules/event_flatstore/event_flatstore.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
struct flat_file {
3838
str path;
39+
char *pathname;
3940
unsigned int file_index_process;
4041
unsigned int counter_open;
4142
unsigned int rotate_version;

0 commit comments

Comments
 (0)