RC Pilot
log_manager.c
Go to the documentation of this file.
1 /**
2  * @file log_manager.c
3  */
4 
5 
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <dirent.h>
12 #include <string.h>
13 
14 #include <rc/start_stop.h>
15 #include <rc/time.h>
16 #include <rc/pthread.h>
17 
18 #include <rc_pilot_defs.h>
19 #include <thread_defs.h>
20 #include <log_manager.h>
21 
22 
23 #define MAX_LOG_FILES 500
24 #define BUF_LEN 50
25 
26 
27 uint64_t num_entries; // number of entries logged so far
28 int buffer_pos; // position in current buffer
29 int current_buf; // 0 or 1 to indicate which buffer is being filled
30 int needs_writing; // flag set to 1 if a buffer is full
31 FILE* fd; // file descriptor for the log file
32 
33 // array of two buffers so one can fill while writing the other to file
35 
36 // background thread and running flag
37 pthread_t pthread;
38 int logging_enabled; // set to 0 to exit the write_thread
39 
41 {
42  #define X(type, fmt, name) printf("%s " fmt "\n", #name, entry.name);
43  LOG_TABLE
44  #undef X
45  printf("\n");
46  return 0;
47 }
48 
49 
51 {
52  if(!logging_enabled){
53  fprintf(stderr,"ERROR: trying to log entry while logger isn't running\n");
54  return -1;
55  }
57  fprintf(stderr,"WARNING: logging buffer full, skipping log entry\n");
58  return -1;
59  }
60  // add to buffer and increment counters
61  buffer[current_buf][buffer_pos] = new;
62  buffer_pos++;
63  num_entries++;
64  // check if we've filled a buffer
65  if(buffer_pos >= BUF_LEN){
66  buffer_pos = 0; // reset buffer position to 0
67  needs_writing = 1; // flag the writer to dump to disk
68  // swap buffers
69  if(current_buf==0) current_buf=1;
70  else current_buf=0;
71  }
72  return 0;
73 }
74 
75 
77 {
78  #define X(type, fmt, name) fprintf(fd, fmt "," , entry.name);
79  LOG_TABLE
80  #undef X
81  fprintf(fd, "\n");
82  return 0;
83 }
84 
85 
86 void* __log_manager_func(__attribute__ ((unused)) void* ptr)
87 {
88  int i, buf_to_write;
89  // while logging enabled and not exiting, write full buffers to disk
90  while(rc_get_state()!=EXITING && logging_enabled){
91  if(needs_writing){
92  // buffer to be written is opposite of one currently being filled
93  if(current_buf==0) buf_to_write=1;
94  else buf_to_write=0;
95  // write the full buffer to disk;
96  for(i=0;i<BUF_LEN;i++){
97  __write_log_entry(buffer[buf_to_write][i]);
98  }
99  fflush(fd);
100  needs_writing = 0;
101  }
102  rc_usleep(1000000/LOG_MANAGER_HZ);
103  }
104 
105  // if program is exiting or logging got disabled, write out the rest of
106  // the logs that are in the buffer current being filled
107  //printf("writing out remaining log file\n");
108  for(i=0;i<buffer_pos;i++){
109  __write_log_entry(buffer[current_buf][i]);
110  }
111  fflush(fd);
112  fclose(fd);
113  //printf("log file closed\n");
114  // zero out state
115  logging_enabled = 0;
116  num_entries = 0;
117  buffer_pos = 0;
118  current_buf = 0;
119  needs_writing = 0;
120  return NULL;
121 }
122 
123 
125 {
126  int i;
127  char path[100];
128  struct stat st = {0};
129 
130  // if the thread if running, stop before starting a new log file
131  if(logging_enabled){
132  //fprintf(stderr,"ERROR: in start_log_manager, log manager already running.\n");
133  //return -1;
135  }
136 
137  // first make sure the directory exists, make it if not
138  if (stat(LOG_DIR, &st) == -1) {
139  mkdir(LOG_DIR, 0755);
140  }
141 
142  // search for existing log files to determine the next number in the series
143  for(i=1;i<=MAX_LOG_FILES+1;i++){
144  memset(&path, 0, sizeof(path));
145  sprintf(path, LOG_DIR "%d.csv", i);
146  // if file exists, move onto the next index
147  if(stat(path, &st)==0) continue;
148  else break;
149  }
150  // limit number of log files
151  if(i==MAX_LOG_FILES+1){
152  printf("ERROR: log file limit exceeded\n");
153  printf("delete old log files before continuing\n");
154  return -1;
155  }
156  // create and open new file for writing
157  fd = fopen(path, "w+");
158  if(fd == 0) {
159  printf("ERROR: can't open log file for writing\n");
160  return -1;
161  }
162  // write header
163  #define X(type, fmt, name) fprintf(fd, "%s," , #name);
164  LOG_TABLE
165  #undef X
166  fprintf(fd, "\n");
167  fflush(fd);
168 
169  // start thread
170  logging_enabled = 1;
171  num_entries = 0;
172  buffer_pos = 0;
173  current_buf = 0;
174  needs_writing = 0;
175 
176  // start logging thread
177  if(rc_pthread_create(&pthread, __log_manager_func, NULL, SCHED_FIFO, LOG_MANAGER_PRI)<0){
178  fprintf(stderr,"ERROR in start_log_manager, failed to start thread\n");
179  return -1;
180  }
181  rc_usleep(1000);
182  return 0;
183 }
184 
185 
187 {
188  // just return if not logging
189  if(logging_enabled==0) return 0;
190 
191  // disable logging so the thread can stop and start multiple times
192  // thread also exits on rc_get_state()==EXITING
193  logging_enabled=0;
194  int ret = rc_pthread_timed_join(pthread,NULL,LOG_MANAGER_TOUT);
195  if(ret==1) fprintf(stderr,"WARNING: log_manager_thread exit timeout\n");
196  else if(ret==-1) fprintf(stderr,"ERROR: failed to join log_manager thread\n");
197  return ret;
198 }
#define LOG_DIR
Definition: rc_pilot_defs.h:58
int current_buf
Definition: log_manager.c:29
int log_manager_cleanup()
Finish writing remaining data to log and close thread.
Definition: log_manager.c:186
Functions to start, stop, and interact with the log manager thread.
#define BUF_LEN
Definition: log_manager.c:24
#define LOG_MANAGER_HZ
Definition: thread_defs.h:10
Definition: log_manager.h:57
int log_manager_init()
creates a new csv log file and starts the background thread.
Definition: log_manager.c:124
int add_log_entry(log_entry_t new)
quickly add new data to local buffer
Definition: log_manager.c:50
pthread_t pthread
Definition: log_manager.c:37
#define LOG_MANAGER_TOUT
Definition: thread_defs.h:12
uint64_t num_entries
Definition: log_manager.c:27
int logging_enabled
Definition: log_manager.c:38
int needs_writing
Definition: log_manager.c:30
FILE * fd
Definition: log_manager.c:31
int __write_log_entry(log_entry_t entry)
Definition: log_manager.c:76
int buffer_pos
Definition: log_manager.c:28
#define LOG_TABLE
Definition: log_manager.h:20
void * __log_manager_func(__attribute__((unused)) void *ptr)
Definition: log_manager.c:86
#define LOG_MANAGER_PRI
Definition: thread_defs.h:11
log_entry_t buffer[2][BUF_LEN]
Definition: log_manager.c:34
int print_entry(log_entry_t entry)
Write the contents of one entry to the console.
Definition: log_manager.c:40
#define MAX_LOG_FILES
Definition: log_manager.c:23