3 * Copyright (C) 2013 BMW AG
5 * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps.
7 * Contributions are licensed to the GENIVI Alliance under one or more
8 * Contribution License Agreements.
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/.
16 * \author Alexander Wenzel <Alexander.AW.Wenzel@bmw.de> BMW 2013
18 * \file dlt-system-journal.c
19 * For further information see http://www.genivi.org/.
23 /*******************************************************************************
25 ** SRC-MODULE: dlt-system-journal.c **
31 ** AUTHOR : Alexander Wenzel Alexander.AW.Wenzel@bmw.de **
37 ** PLATFORM DEPENDANT [yes/no]: yes **
39 ** TO BE CHANGED BY USER [yes/no]: no **
41 *******************************************************************************/
42 #if defined(DLT_SYSTEMD_JOURNAL_ENABLE)
46 #include <sys/socket.h>
47 #include <netinet/in.h>
52 #include "dlt-system.h"
54 #include <systemd/sd-journal.h>
55 #include <systemd/sd-id128.h>
57 extern DltSystemThreads threads;
59 #define DLT_SYSTEM_JOURNAL_BUFFER_SIZE 256
60 #define DLT_SYSTEM_JOURNAL_BUFFER_SIZE_BIG 2048
62 DLT_IMPORT_CONTEXT(dltsystem)
63 DLT_DECLARE_CONTEXT(journalContext)
65 int journal_checkUserBufferForFreeSpace()
67 int total_size, used_size;
69 dlt_user_check_buffer(&total_size, &used_size);
71 if((total_size - used_size) < (total_size/2))
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.
83 void journal_clean_strcpy(const char* src,char* target,int max_size)
107 void journal_thread(void *v_conf)
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="";
112 char match[9+32+1] = "_BOOT_ID=";
115 uint64_t time_usecs = 0;
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" };
127 DLT_LOG(dltsystem, DLT_LOG_DEBUG,
128 DLT_STRING("dlt-system-journal, in thread."));
130 DltSystemConfiguration *conf = (DltSystemConfiguration *) v_conf;
131 DLT_REGISTER_CONTEXT(journalContext, conf->Journal.ContextId, "Journal Adapter");
133 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY/*SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_RUNTIME_ONLY*/);
135 DLT_LOG(dltsystem, DLT_LOG_ERROR,
136 DLT_STRING("dlt-system-journal, cannot open journal:"),DLT_STRING(strerror(-r)));
140 if(conf->Journal.CurrentBoot)
142 /* show only current boot entries */
143 r = sd_id128_get_boot(&boot_id);
146 DLT_LOG(dltsystem, DLT_LOG_ERROR,
147 DLT_STRING("dlt-system-journal failed to get boot id:"),DLT_STRING(strerror(-r)));
152 sd_id128_to_string(boot_id, match + 9);
153 r = sd_journal_add_match(j,match,strlen(match));
156 DLT_LOG(dltsystem, DLT_LOG_ERROR,
157 DLT_STRING("dlt-system-journal failed to get match:"),DLT_STRING(strerror(-r)));
164 if(conf->Journal.Follow)
166 /* show only last 10 entries and follow */
167 r = sd_journal_seek_tail(j);
170 DLT_LOG(dltsystem, DLT_LOG_ERROR,
171 DLT_STRING("dlt-system-journal failed to seek to tail:"),DLT_STRING(strerror(-r)));
176 r = sd_journal_previous_skip(j, 10);
179 DLT_LOG(dltsystem, DLT_LOG_ERROR,
180 DLT_STRING("dlt-system-journal failed to seek back 10 entries:"),DLT_STRING(strerror(-r)));
188 while(!threads.shutdown)
191 ret = sd_journal_next(j);
194 DLT_LOG(dltsystem, DLT_LOG_ERROR,
195 DLT_STRING("dlt-system-journal failed to get next entry:"),DLT_STRING(strerror(-r)));
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;
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);
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:");
226 snprintf(buffer_process,DLT_SYSTEM_JOURNAL_BUFFER_SIZE,"%s[%s]:",buffer_comm,buffer_pid);
228 /* map log level on demand */
229 loglevel = DLT_LOG_INFO;
230 systemd_loglevel = atoi(d_priority);
231 if(conf->Journal.MapLogLevels)
233 /* Map log levels from journal to DLT */
234 switch(systemd_loglevel)
236 case 0: /* Emergency */
238 case 2: /* Critical */
239 loglevel = DLT_LOG_FATAL;
242 loglevel = DLT_LOG_ERROR;
244 case 4: /* Warning */
246 loglevel = DLT_LOG_WARN;
248 case 6: /* Informational */
249 loglevel = DLT_LOG_INFO;
252 loglevel = DLT_LOG_DEBUG;
255 loglevel = DLT_LOG_INFO;
259 if(systemd_loglevel>=0 && systemd_loglevel<=7)
260 snprintf(buffer_priority,DLT_SYSTEM_JOURNAL_BUFFER_SIZE,"%s:",systemd_log_levels[systemd_loglevel]);
262 snprintf(buffer_priority,DLT_SYSTEM_JOURNAL_BUFFER_SIZE,"prio_unknown:");
264 /* prepare message */
265 journal_clean_strcpy(d_message,buffer_message,sizeof(buffer_message));
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));
274 sd_journal_wait(j,1000000);
277 if(journal_checkUserBufferForFreeSpace()==-1)
279 // buffer is nearly full
280 // wait 500ms for writing next entry
283 t.tv_nsec = 1000000ul*500;
291 DLT_UNREGISTER_CONTEXT(journalContext);
295 void start_systemd_journal(DltSystemConfiguration *conf)
297 DLT_LOG(dltsystem, DLT_LOG_DEBUG,
298 DLT_STRING("dlt-system-journal, start journal"));
299 static pthread_attr_t t_attr;
301 pthread_create(&pt, &t_attr, (void *)journal_thread, conf);
302 threads.threads[threads.count++] = pt;
305 #endif /* DLT_SYSTEMD_JOURNAL_ENABLE */