summaryrefslogtreecommitdiff
path: root/daemons/shaper/src/shaper_log_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemons/shaper/src/shaper_log_linux.c')
-rw-r--r--daemons/shaper/src/shaper_log_linux.c445
1 files changed, 445 insertions, 0 deletions
diff --git a/daemons/shaper/src/shaper_log_linux.c b/daemons/shaper/src/shaper_log_linux.c
new file mode 100644
index 00000000..d68a79a2
--- /dev/null
+++ b/daemons/shaper/src/shaper_log_linux.c
@@ -0,0 +1,445 @@
+/*************************************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************************************/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "platform.h"
+#include "shaper_log_queue.h"
+#include "shaper_helper_linux.h"
+
+#define SHAPER_LOG_COMPONENT "Log"
+#include "shaper_log.h"
+
+typedef struct {
+ uint8_t msg[LOG_QUEUE_MSG_SIZE];
+ int bRT; // TRUE = Details are in RT queue
+} log_queue_item_t;
+
+typedef struct {
+ char *pFormat;
+ log_rt_datatype_t dataType;
+ union {
+ struct timespec nowTS;
+ uint16_t unsignedShortVar;
+ int16_t signedShortVar;
+ uint32_t unsignedLongVar;
+ int32_t signedLongVar;
+ uint64_t unsignedLongLongVar;
+ int64_t signedLongLongVar;
+ float floatVar;
+ } data;
+ int bEnd;
+} log_rt_queue_item_t;
+
+static shaper_log_queue_t logQueue;
+static shaper_log_queue_t logRTQueue;
+
+static char msg[LOG_MSG_LEN] = "";
+static char time_msg[LOG_TIME_LEN] = "";
+static char timestamp_msg[LOG_TIMESTAMP_LEN] = "";
+static char file_msg[LOG_FILE_LEN] = "";
+static char proc_msg[LOG_PROC_LEN] = "";
+static char thread_msg[LOG_THREAD_LEN] = "";
+static char full_msg[LOG_FULL_MSG_LEN] = "";
+
+static char rt_msg[LOG_RT_MSG_LEN] = "";
+
+static int loggingThreadRunning = FALSE;
+extern void *loggingThreadFn(void *pv);
+THREAD_TYPE(loggingThread);
+THREAD_DEFINITON(loggingThread);
+
+#define THREAD_STACK_SIZE 65536
+#define loggingThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+static MUTEX_HANDLE_ALT(gLogMutex);
+#define LOG_LOCK() MUTEX_LOCK_ALT(gLogMutex)
+#define LOG_UNLOCK() MUTEX_UNLOCK_ALT(gLogMutex)
+
+void shaperLogRTRender(log_queue_item_t *pLogItem)
+{
+ if (logRTQueue) {
+ pLogItem->msg[0] = 0x00;
+ int bMore = TRUE;
+ while (bMore) {
+ shaper_log_queue_elem_t elem = shaperLogQueueTailLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem);
+
+ switch (pLogRTItem->dataType) {
+ case LOG_RT_DATATYPE_CONST_STR:
+ strcat((char *)pLogItem->msg, pLogRTItem->pFormat);
+ break;
+ case LOG_RT_DATATYPE_NOW_TS:
+ sprintf(rt_msg, "[%lu:%09lu] ", pLogRTItem->data.nowTS.tv_sec, pLogRTItem->data.nowTS.tv_nsec);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U16:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedShortVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S16:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedShortVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U32:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S32:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U64:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S64:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_FLOAT:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.floatVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ default:
+ break;
+ }
+
+ if (pLogRTItem->bEnd) {
+ if (SHAPER_LOG_EXTRA_NEWLINE)
+ strcat((char *)pLogItem->msg, "\n");
+ bMore = FALSE;
+ }
+ shaperLogQueueTailPull(logRTQueue);
+ }
+ }
+ }
+}
+
+uint32_t shaperLogGetMsg(uint8_t *pBuf, uint32_t bufSize)
+{
+ uint32_t dataLen = 0;
+ if (logQueue) {
+ shaper_log_queue_elem_t elem = shaperLogQueueTailLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem);
+
+ if (pLogItem->bRT)
+ shaperLogRTRender(pLogItem);
+
+ dataLen = strlen((const char *)pLogItem->msg);
+ if (dataLen <= bufSize)
+ memcpy(pBuf, (uint8_t *)pLogItem->msg, dataLen);
+ else
+ memcpy(pBuf, (uint8_t *)pLogItem->msg, bufSize);
+ shaperLogQueueTailPull(logQueue);
+ return dataLen;
+ }
+ }
+ return dataLen;
+}
+
+void *loggingThreadFn(void *pv)
+{
+ (void) pv;
+
+ while (loggingThreadRunning) {
+ SLEEP_MSEC(LOG_QUEUE_SLEEP_MSEC);
+ shaperLogDisplayAll();
+ }
+
+ return NULL;
+}
+
+void shaperLogDisplayAll(void)
+{
+ int more = TRUE;
+
+ while (more) {
+ more = FALSE;
+ shaper_log_queue_elem_t elem = shaperLogQueueTailLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem);
+
+ if (pLogItem->bRT)
+ shaperLogRTRender(pLogItem);
+
+ fputs((const char *)pLogItem->msg, SHAPER_LOG_OUTPUT_FD);
+ shaperLogQueueTailPull(logQueue);
+ more = TRUE;
+ }
+ }
+}
+
+void shaperLogInit(void)
+{
+ MUTEX_CREATE_ALT(gLogMutex);
+
+ logQueue = shaperLogQueueNewQueue(sizeof(log_queue_item_t), LOG_QUEUE_MSG_CNT);
+ if (!logQueue) {
+ printf("Failed to initialize logging facility\n");
+ }
+
+ logRTQueue = shaperLogQueueNewQueue(sizeof(log_rt_queue_item_t), LOG_RT_QUEUE_CNT);
+ if (!logRTQueue) {
+ printf("Failed to initialize logging RT facility\n");
+ }
+
+ // Start the logging task
+ if (SHAPER_LOG_FROM_THREAD) {
+ int errResult;
+ loggingThreadRunning = TRUE;
+ THREAD_CREATE(loggingThread, loggingThread, NULL, loggingThreadFn, NULL);
+ THREAD_CHECK_ERROR(loggingThread, "Thread / task creation failed", errResult);
+ if (errResult) {} // Already reported
+ }
+}
+
+void shaperLogExit()
+{
+ if (SHAPER_LOG_FROM_THREAD) {
+ loggingThreadRunning = FALSE;
+ THREAD_JOIN(loggingThread, NULL);
+ }
+}
+
+void shaperLogFn(
+ int level,
+ const char *tag,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line,
+ const char *fmt,
+ ...)
+{
+ if (level <= SHAPER_LOG_LEVEL) {
+ va_list args;
+ va_start(args, fmt);
+
+ LOG_LOCK();
+
+ vsprintf(msg, fmt, args);
+
+ if (SHAPER_LOG_FILE_INFO && path) {
+ char* file = strrchr(path, '/');
+ if (!file)
+ file = strrchr(path, '\\');
+ if (file)
+ file += 1;
+ else
+ file = (char*)path;
+ sprintf(file_msg, " %s:%d", file, line);
+ }
+ if (SHAPER_LOG_PROC_INFO) {
+ sprintf(proc_msg, " P:%5.5d", GET_PID());
+ }
+ if (SHAPER_LOG_THREAD_INFO) {
+ sprintf(thread_msg, " T:%lu", THREAD_SELF());
+ }
+ if (SHAPER_LOG_TIME_INFO) {
+ time_t tNow = time(NULL);
+ struct tm tmNow;
+ localtime_r(&tNow, &tmNow);
+
+ sprintf(time_msg, "%2.2d:%2.2d:%2.2d", tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec);
+ }
+ if (SHAPER_LOG_TIMESTAMP_INFO) {
+ struct timespec nowTS;
+ clock_gettime(CLOCK_REALTIME, &nowTS);
+
+ sprintf(timestamp_msg, "%lu:%09lu", nowTS.tv_sec, nowTS.tv_nsec);
+ }
+
+ // using sprintf and puts allows using static buffers rather than heap.
+ if (SHAPER_LOG_EXTRA_NEWLINE)
+ /* int32_t full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s\n", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
+ else
+ /* int32_t full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
+
+ if (!SHAPER_LOG_FROM_THREAD && !SHAPER_LOG_PULL_MODE) {
+ fputs(full_msg, SHAPER_LOG_OUTPUT_FD);
+ }
+ else {
+ if (logQueue) {
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem);
+ pLogItem->bRT = FALSE;
+ strncpy((char *)pLogItem->msg, full_msg, LOG_QUEUE_MSG_LEN);
+ shaperLogQueueHeadPush(logQueue);
+ }
+ }
+ }
+
+ va_end(args);
+
+ LOG_UNLOCK();
+ }
+}
+
+void shaperLogRT(int level, int bBegin, int bItem, int bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar)
+{
+ if (level <= SHAPER_LOG_LEVEL) {
+ if (logRTQueue) {
+ if (bBegin) {
+ LOG_LOCK();
+
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem);
+ pLogRTItem->bEnd = FALSE;
+ pLogRTItem->pFormat = NULL;
+ pLogRTItem->dataType = LOG_RT_DATATYPE_NOW_TS;
+ clock_gettime(CLOCK_REALTIME, &pLogRTItem->data.nowTS);
+ shaperLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (bItem) {
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem);
+ if (bEnd)
+ pLogRTItem->bEnd = TRUE;
+ else
+ pLogRTItem->bEnd = FALSE;
+ pLogRTItem->pFormat = pFormat;
+ pLogRTItem->dataType = dataType;
+
+ switch (pLogRTItem->dataType) {
+ case LOG_RT_DATATYPE_CONST_STR:
+ break;
+ case LOG_RT_DATATYPE_U16:
+ pLogRTItem->data.unsignedLongVar = *(uint16_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S16:
+ pLogRTItem->data.signedLongVar = *(int16_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_U32:
+ pLogRTItem->data.unsignedLongVar = *(uint32_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S32:
+ pLogRTItem->data.signedLongVar = *(int32_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_U64:
+ pLogRTItem->data.unsignedLongLongVar = *(uint64_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S64:
+ pLogRTItem->data.signedLongLongVar = *(int64_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_FLOAT:
+ pLogRTItem->data.floatVar = *(float *)pVar;
+ break;
+ default:
+ break;
+ }
+ shaperLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (!bItem && bEnd) {
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem);
+ pLogRTItem->bEnd = TRUE;
+ pLogRTItem->pFormat = NULL;
+ pLogRTItem->dataType = LOG_RT_DATATYPE_NONE;
+ shaperLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (bEnd) {
+ if (logQueue) {
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem);
+ pLogItem->bRT = TRUE;
+ if (SHAPER_LOG_FROM_THREAD) {
+ shaperLogQueueHeadPush(logQueue);
+ } else {
+ shaperLogRTRender(pLogItem);
+ fputs((const char *)pLogItem->msg, SHAPER_LOG_OUTPUT_FD);
+ shaperLogQueueHeadUnlock(logQueue);
+ }
+ }
+ }
+
+ LOG_UNLOCK();
+ }
+ }
+ }
+}
+
+void shaperLogBuffer(
+ int level,
+ const uint8_t *pData,
+ int dataLen,
+ int lineLen,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line)
+{
+ char szDataLine[ 400 ];
+ char *pszOut;
+ int i, j;
+
+ if (level > SHAPER_LOG_LEVEL) { return; }
+
+ for (i = 0; i < dataLen; i += lineLen) {
+ /* Create the hexadecimal output for the buffer. */
+ pszOut = szDataLine;
+ *pszOut++ = '\t';
+ for (j = i; j < i + lineLen; ++j) {
+ if (j < dataLen) {
+ sprintf(pszOut, "%02x ", pData[j]);
+ } else {
+ strcpy(pszOut, " ");
+ }
+ pszOut += 3;
+ }
+
+ *pszOut++ = ' ';
+ *pszOut++ = ' ';
+
+ /* Append the ASCII equivalent of each character. */
+ for (j = i; j < dataLen && j < i + lineLen; ++j) {
+ if (pData[j] >= 0x20 && pData[j] < 0x7f) {
+ *pszOut++ = (char) pData[j];
+ } else {
+ *pszOut++ = '.';
+ }
+ }
+
+ /* Display this line of text. */
+ *pszOut = '\0';
+ shaperLogFn(level, "BUFFER", company, component, path, line, "%s", szDataLine);
+ }
+}