52938761dbd92aa7e5f17a51c8170710a7da265d
[profile/ivi/dlt-daemon.git] / src / system / dlt-system-journal.c
1 /**
2  * @licence app begin@
3  * Copyright (C) 2013  BMW AG
4  *
5  * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps.
6  *
7  * Contributions are licensed to the GENIVI Alliance under one or more
8  * Contribution License Agreements.
9  *
10  * \copyright
11  * This Source Code Form is subject to the terms of the
12  * Mozilla Public License, v. 2.0. If a  copy of the MPL was not distributed with
13  * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
14  *
15  *
16  * \author Alexander Wenzel <Alexander.AW.Wenzel@bmw.de> BMW 2013
17  *
18  * \file dlt-system-journal.c
19  * For further information see http://www.genivi.org/.
20  * @licence end@
21  */
22
23 /*******************************************************************************
24 **                                                                            **
25 **  SRC-MODULE: dlt-system-journal.c                                          **
26 **                                                                            **
27 **  TARGET    : linux                                                         **
28 **                                                                            **
29 **  PROJECT   : DLT                                                           **
30 **                                                                            **
31 **  AUTHOR    : Alexander Wenzel Alexander.AW.Wenzel@bmw.de                   **
32 **                                                                            **
33 **  PURPOSE   :                                                               **
34 **                                                                            **
35 **  REMARKS   :                                                               **
36 **                                                                            **
37 **  PLATFORM DEPENDANT [yes/no]: yes                                          **
38 **                                                                            **
39 **  TO BE CHANGED BY USER [yes/no]: no                                        **
40 **                                                                            **
41 *******************************************************************************/
42 #if defined(DLT_SYSTEMD_JOURNAL_ENABLE)
43
44 #include <pthread.h>
45 #include <unistd.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <strings.h>
49 #include <errno.h>
50 #include <stdlib.h>
51
52 #include "dlt-system.h"
53
54 #include <systemd/sd-journal.h>
55 #include <systemd/sd-id128.h>
56
57 extern DltSystemThreads threads;
58
59 #define DLT_SYSTEM_JOURNAL_BUFFER_SIZE 256
60 #define DLT_SYSTEM_JOURNAL_BUFFER_SIZE_BIG 2048
61
62 DLT_IMPORT_CONTEXT(dltsystem)
63 DLT_DECLARE_CONTEXT(journalContext)
64
65 int journal_checkUserBufferForFreeSpace()
66 {
67         int total_size, used_size;
68
69         dlt_user_check_buffer(&total_size, &used_size);
70
71         if((total_size - used_size) < (total_size/2))
72         {
73                 return -1;
74         }
75         return 1;
76 }
77
78 /* 
79  * Copy a string and remove characters, which cannot be displayed.
80  * If max_size is reached a null character is added as last character.
81  * 
82  */
83 void journal_clean_strcpy(const char* src,char* target,int max_size)
84 {
85         if(max_size<1)
86                 return;
87         while(*src!=0)
88         {
89                 if(max_size>1)
90                 {
91                         if(*src>31)
92                         {
93                                 *target=*src;
94                                 target++;
95                                 max_size--;
96                         }
97                 }
98                 else
99                 {
100                         *target=0;
101                         return;                 
102                 }
103                 src++;
104         }
105 }
106
107 void journal_thread(void *v_conf)
108 {
109         int r,r_comm,r_pid,r_priority,r_message,r_transport;
110         char *d_comm="",*d_pid="",*d_priority="",*d_message="",*d_transport="";
111         sd_journal *j;
112         char match[9+32+1] = "_BOOT_ID=";
113         sd_id128_t boot_id;
114         size_t l;
115         uint64_t time_usecs = 0;
116         int ret;
117         struct tm * timeinfo;
118         char buffer_time[DLT_SYSTEM_JOURNAL_BUFFER_SIZE],
119              buffer_process[DLT_SYSTEM_JOURNAL_BUFFER_SIZE],
120              buffer_priority[DLT_SYSTEM_JOURNAL_BUFFER_SIZE],
121              buffer_pid[DLT_SYSTEM_JOURNAL_BUFFER_SIZE],
122              buffer_comm[DLT_SYSTEM_JOURNAL_BUFFER_SIZE],
123              buffer_message[DLT_SYSTEM_JOURNAL_BUFFER_SIZE_BIG];
124         int loglevel,systemd_loglevel;
125         char* systemd_log_levels[] = { "Emergency","Alert","Critical","Error","Warning","Notice","Informational","Debug" };
126         
127         DLT_LOG(dltsystem, DLT_LOG_DEBUG,
128                         DLT_STRING("dlt-system-journal, in thread."));
129
130         DltSystemConfiguration *conf = (DltSystemConfiguration *) v_conf;
131         DLT_REGISTER_CONTEXT(journalContext, conf->Journal.ContextId, "Journal Adapter");
132
133         r = sd_journal_open(&j,  SD_JOURNAL_LOCAL_ONLY/*SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_RUNTIME_ONLY*/);
134         if (r < 0) {
135                         DLT_LOG(dltsystem, DLT_LOG_ERROR,
136                                         DLT_STRING("dlt-system-journal, cannot open journal:"),DLT_STRING(strerror(-r)));
137                         return;
138         }
139                         
140         if(conf->Journal.CurrentBoot)
141         {
142                 /* show only current boot entries */
143                 r = sd_id128_get_boot(&boot_id);
144                 if(r<0)
145                 {
146                                 DLT_LOG(dltsystem, DLT_LOG_ERROR,
147                                                 DLT_STRING("dlt-system-journal failed to get boot id:"),DLT_STRING(strerror(-r)));
148                                 sd_journal_close(j);
149                                 return;
150                         
151                 }
152                 sd_id128_to_string(boot_id, match + 9);
153                 r = sd_journal_add_match(j,match,strlen(match));
154                 if(r<0)
155                 {
156                                 DLT_LOG(dltsystem, DLT_LOG_ERROR,
157                                                 DLT_STRING("dlt-system-journal failed to get match:"),DLT_STRING(strerror(-r)));
158                                 sd_journal_close(j);
159                                 return;
160                         
161                 }
162         }       
163
164         if(conf->Journal.Follow)
165         {
166                 /* show only last 10 entries and follow */
167         r = sd_journal_seek_tail(j);
168                 if(r<0)
169                 {
170                                 DLT_LOG(dltsystem, DLT_LOG_ERROR,
171                                                 DLT_STRING("dlt-system-journal failed to seek to tail:"),DLT_STRING(strerror(-r)));
172                                 sd_journal_close(j);
173                                 return;
174                         
175                 }
176         r = sd_journal_previous_skip(j, 10);
177                 if(r<0)
178                 {
179                                 DLT_LOG(dltsystem, DLT_LOG_ERROR,
180                                                 DLT_STRING("dlt-system-journal failed to seek back 10 entries:"),DLT_STRING(strerror(-r)));
181                                 sd_journal_close(j);
182                                 return;
183                         
184                 }
185         
186         }
187         
188         while(!threads.shutdown)
189         {                       
190
191                 ret = sd_journal_next(j);
192                 if(r<0)
193                 {
194                                 DLT_LOG(dltsystem, DLT_LOG_ERROR,
195                                                 DLT_STRING("dlt-system-journal failed to get next entry:"),DLT_STRING(strerror(-r)));
196                                 sd_journal_close(j);
197                                 return;
198                         
199                 }
200                 else if(ret>0)
201                 {
202                         /* get all data from current journal entry */
203                         sd_journal_get_realtime_usec(j, &time_usecs);
204                         r_comm = sd_journal_get_data(j, "_COMM",(const void **) &d_comm, &l);
205                         r_pid = sd_journal_get_data(j, "_PID",(const void **) &d_pid, &l);
206                         r_priority = sd_journal_get_data(j, "PRIORITY",(const void **) &d_priority, &l);
207                         r_message = sd_journal_get_data(j, "MESSAGE",(const void **) &d_message, &l);
208                         r_transport = sd_journal_get_data(j, "_TRANSPORT",(const void **) &d_transport, &l);
209                         if(r_comm>=0 && strlen(d_comm)>6)                       d_comm +=6;
210                         if(r_pid>=0 && strlen(d_pid)>5)                         d_pid +=5;
211                         if(r_priority>=0 && strlen(d_priority)>9)       d_priority +=9;
212                         if(r_message>=0 && strlen(d_message)>8)         d_message +=8;
213                         if(r_transport>=0 && strlen(d_transport)>11) d_transport +=11;
214                         
215                         /* prepare time string */
216                         time_usecs /=1000000;
217                         timeinfo = localtime ((const time_t*)(&(time_usecs)));
218             strftime (buffer_time,sizeof(buffer_time),"%Y/%m/%d %H:%M:%S",timeinfo);
219
220                         /* prepare process string */
221                         journal_clean_strcpy(d_pid,buffer_pid,sizeof(buffer_pid));
222                         journal_clean_strcpy(d_comm,buffer_comm,sizeof(buffer_comm));
223                         if(strcmp(d_transport,"kernel")==0)
224                                 snprintf(buffer_process,DLT_SYSTEM_JOURNAL_BUFFER_SIZE,"kernel:");
225                         else
226                                 snprintf(buffer_process,DLT_SYSTEM_JOURNAL_BUFFER_SIZE,"%s[%s]:",buffer_comm,buffer_pid);
227
228                         /* map log level on demand */
229                         loglevel = DLT_LOG_INFO;
230                         systemd_loglevel = atoi(d_priority);
231                         if(conf->Journal.MapLogLevels)
232                         {
233                                 /* Map log levels from journal to DLT */
234                                 switch(systemd_loglevel)
235                                 {
236                                         case 0: /* Emergency */
237                                         case 1: /* Alert */
238                                         case 2: /* Critical */
239                                                 loglevel = DLT_LOG_FATAL;
240                                                 break;
241                                         case 3: /* Error */
242                                                 loglevel = DLT_LOG_ERROR;
243                                                 break;
244                                         case 4: /* Warning */
245                                         case 5: /* Notice */
246                                                 loglevel = DLT_LOG_WARN;
247                                                 break;
248                                         case 6: /* Informational */
249                                                 loglevel = DLT_LOG_INFO;
250                                                 break;
251                                         case 7: /* Debug */
252                                                 loglevel = DLT_LOG_DEBUG;
253                                                 break;
254                                         default:
255                                                 loglevel = DLT_LOG_INFO;
256                                                 break;
257                                 }
258                         }                       
259                         if(systemd_loglevel>=0 && systemd_loglevel<=7)
260                                 snprintf(buffer_priority,DLT_SYSTEM_JOURNAL_BUFFER_SIZE,"%s:",systemd_log_levels[systemd_loglevel]);
261                         else
262                                 snprintf(buffer_priority,DLT_SYSTEM_JOURNAL_BUFFER_SIZE,"prio_unknown:");
263                         
264                         /* prepare message */
265                         journal_clean_strcpy(d_message,buffer_message,sizeof(buffer_message));
266                         
267                         /* write log entry */
268                         DLT_LOG(journalContext, loglevel,
269                                                 DLT_STRING(buffer_time),DLT_STRING(buffer_process),DLT_STRING(buffer_priority),DLT_STRING(buffer_message));
270
271                 }
272                 else
273                 {
274                         sd_journal_wait(j,1000000);                     
275                 }
276                 
277                 if(journal_checkUserBufferForFreeSpace()==-1)
278                 {
279                         // buffer is nearly full
280                         // wait 500ms for writing next entry
281                         struct timespec t;
282                         t.tv_sec = 0;
283                         t.tv_nsec = 1000000ul*500;
284                         nanosleep(&t, NULL);
285                 }
286
287         }
288
289     sd_journal_close(j);
290
291         DLT_UNREGISTER_CONTEXT(journalContext);
292
293 }
294
295 void start_systemd_journal(DltSystemConfiguration *conf)
296 {
297         DLT_LOG(dltsystem, DLT_LOG_DEBUG,
298                         DLT_STRING("dlt-system-journal, start journal"));
299         static pthread_attr_t t_attr;
300         static pthread_t pt;
301         pthread_create(&pt, &t_attr, (void *)journal_thread, conf);
302         threads.threads[threads.count++] = pt;
303 }
304
305 #endif /* DLT_SYSTEMD_JOURNAL_ENABLE */