1 /*******************************************************************************
2 ################################################################################
3 # Copyright (c) [2017-2019] [Radisys] #
5 # Licensed under the Apache License, Version 2.0 (the "License"); #
6 # you may not use this file except in compliance with the License. #
7 # You may obtain a copy of the License at #
9 # http://www.apache.org/licenses/LICENSE-2.0 #
11 # Unless required by applicable law or agreed to in writing, software #
12 # distributed under the License is distributed on an "AS IS" BASIS, #
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
14 # See the License for the specific language governing permissions and #
15 # limitations under the License. #
16 ################################################################################
17 *******************************************************************************/
19 /********************************************************************20**
21 Name: Radisys Logging Framework
23 Desc: This file contains logging framework implementation.
26 *********************************************************************21*/
27 ///////////////////////////////////////////////////////////////////////////////
28 // @ description: This is source file contains the implementaion of binary log
29 // postprocessor and has ability to connect to remote node and print live logs.
30 ///////////////////////////////////////////////////////////////////////////////
41 #include <sys/socket.h>
42 #include <netinet/in.h>
45 #include <arpa/inet.h>
51 #include <sys/types.h>
52 #include <arpa/inet.h>
53 #include "rl_interface.h"
58 namespace cmdlinearg {
60 std::string g_sFileDb; /* File DB */
61 std::string g_sLogDb; /* Log DB */
62 std::string g_sOutFile; /* Output file */
63 std::string g_sBinLogFile; /* Input binary log file */
76 static struct option long_options[] =
78 {"port", required_argument, 0, 'p'},
79 {"logdb", required_argument, 0, 'l'},
80 {"ofile", required_argument, 0, 'o'},
81 {"blog", required_argument, 0, 'b'},
82 {"ipaddr", required_argument, 0, 'i'},
86 std::map<unsigned short, std::string> g_mFileInfo;
87 std::map<LOGID, LOG_INFO> g_mLogInfo;
92 void readCmdLineArgs(int argc,char **argv);
93 void printLogTime(LOGTIME & ltime);
96 void logHexDump(ARGDATA & log);
97 bool invalidLogId(LOGID logId);
98 void openLogFile(const char* file);
99 void logLevN(LOGDATA & log, LOG_INFO & logInfo, const char* fmtStr, ...);
100 void logLevS(LOGDATA & log, LOG_INFO & logInfo, const char* fmtStr, const char *logStr);
101 void logString(ARGDATA & log);
102 void logIntArg(ARG4DATA* log);
103 void logArgSpl(SPL_ARGDATA* log);
104 void processLogs(int fd, bool (*fpReadLog)(int, ARGDATA &));
106 bool readRemoteLogs(int sockfd, ARGDATA & log);
107 bool readFileLogs(int fd, ARGDATA & log);
108 int openBinLogFile();
109 int connectToLogServer();
111 ///////////////////////////////////////////////////////////////////////////////////////////////////
112 // @arg[in] argc - Number of arguments
113 // @arg[in] argv - Command line arguments
114 // This is main functions, which calls a function to parse command line arguments. Then it loads
115 // log metadata into memory. And then based on if its remote logging or binary log file parsing
116 // passes apropriate function pointer to read and convert logs.
117 ///////////////////////////////////////////////////////////////////////////////////////////////////
118 int main(int argc, char* argv[])
120 readCmdLineArgs(argc, argv);
123 if( !cmdlinearg::g_sBinLogFile.empty() )
125 if( !cmdlinearg::g_sOutFile.empty() )
127 openLogFile(cmdlinearg::g_sOutFile.c_str());
129 processLogs(openBinLogFile(), readFileLogs);
134 if( cmdlinearg::g_port != 0 ) {
136 if( !cmdlinearg::g_sOutFile.empty() ) {
137 openLogFile(cmdlinearg::g_sOutFile.c_str());
141 processLogs(connectToLogServer(), readRemoteLogs);
148 ///////////////////////////////////////////////////////////////////////////////////////////////////
149 // @param[in] file - Input log file name
150 // This function opens the log file in write mode.
151 ///////////////////////////////////////////////////////////////////////////////////////////////////
152 void openLogFile(const char* file)
154 g_fp = fopen(file, "w+");
158 fprintf(stderr, "Failed to open log file %s\n", file);
162 fprintf(stderr, "Log Output will be written in %s\n", file);
165 uint32_t swap_uint32( uint32_t val )
167 val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF );
168 return (val << 16) | (val >> 16);
172 unsigned long EndianSwap32(unsigned long x)
175 y += (x & 0x000000FF)<<24;
176 y += (x & 0xFF000000)>>24;
177 y += (x & 0x0000FF00)<<8;
178 y += (x & 0x00FF0000)>>8;
182 void print_hex(const char* str, const U8 *p, int len)
184 fprintf(stderr, "%s HEX \n", str);
185 for(int i=0; i<len; i++ ) fprintf(stderr, "%d ", p[i]);
186 fprintf(stderr, "\n");
190 ///////////////////////////////////////////////////////////////////////////////////////////////////
191 // This function open the log file in binary mode and checks if file header is correct or not.
192 // It also sets the environment variable for given time zone in log file, so that time information
193 // is converted to correct time zone times.
194 ///////////////////////////////////////////////////////////////////////////////////////////////////
197 int fd = open(cmdlinearg::g_sBinLogFile.c_str(), O_RDONLY );
200 fprintf(stderr, "Failed to open log file %s\n", cmdlinearg::g_sBinLogFile.c_str());
206 int len = read(fd, (void*)&fileHdr, sizeof(FILE_HEADER));
208 if( fileHdr.END_MARKER != 0xFFFF ) {
209 fprintf(stderr, "Invalid file header\n");
213 fprintf(stderr, "FILE ENDIAN: %s\n", fileHdr.endianType == big_endian ? "BIG ENDIAN" : "LITTLE ENDIAN");
214 fprintf(stderr, "TIME ZONE: %s\n", fileHdr.szTimeZone);
216 setenv("TZ", fileHdr.szTimeZone, 1);
219 if( fileHdr.endianType == big_endian ) {
221 g_basetimeSec = fileHdr.time_sec;
225 ///////////////////////////////////////////////////////////////////////////////////////////////////
226 // This function connects to remote application which is using binary logging framework. If
227 // connection is failed log application exits.
228 ///////////////////////////////////////////////////////////////////////////////////////////////////
229 int connectToLogServer()
232 struct addrinfo hints;
233 struct addrinfo *res = NULL;
234 struct addrinfo *result = NULL;
238 struct sockaddr_in serv_addr;
239 struct sockaddr_in6 serv_addr6;
240 void *sockServAddr = NULL;
241 int ai_family = AF_UNSPEC;
244 /* ccpu00147898 fixes */
245 memset(&hints, 0, sizeof(hints));
246 memset((void*)&serv_addr, 0, sizeof(serv_addr));
247 memset((void*)&serv_addr6, 0, sizeof(serv_addr6));
248 hints.ai_family = PF_UNSPEC;
249 hints.ai_socktype = SOCK_STREAM;
250 hints.ai_flags |= AI_CANONNAME;
252 errcode = getaddrinfo(cmdlinearg::g_ipAddr.c_str(), NULL, &hints, &res);
255 perror ("getaddrinfo");
262 inet_ntop(res->ai_family, res->ai_addr->sa_data, addrstr, 100);
264 switch(res->ai_family)
267 ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
268 serv_addr.sin_addr = ((struct sockaddr_in *) res->ai_addr)->sin_addr;
269 sockServAddr = &serv_addr;
270 ai_family = res->ai_family;
271 serv_addr.sin_family = res->ai_family;
272 serv_addr.sin_port = htons(cmdlinearg::g_port);
273 size = sizeof(serv_addr);
276 ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
277 sockServAddr = &serv_addr6;
278 /* Copy IPv6 address(16bytes) into the destination */
279 memcpy((unsigned char*)serv_addr6.sin6_addr.s6_addr, (unsigned char *)
280 &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr, 16);
281 ai_family = res->ai_family;
282 serv_addr6.sin6_family = res->ai_family;
283 serv_addr6.sin6_port = htons(cmdlinearg::g_port);
284 size = sizeof(serv_addr6);
293 inet_ntop(res->ai_family, ptr, addrstr, 100);
294 printf ("IPv%d address: %s (%s)\n", res->ai_family == PF_INET6 ? 6 : 4,
295 addrstr, res->ai_canonname);
300 if(sockServAddr == NULL || size == 0)
302 fprintf(stderr, "Not able to parse server address\n");
306 if( (sockfd = socket(ai_family, SOCK_STREAM,0)) < 0 ) {
307 fprintf(stderr, "Failed to create socket\n");
311 if( connect(sockfd, (const sockaddr*)sockServAddr, size) < 0 ) {
312 perror("ERROR Connecting");
318 freeaddrinfo(result);
323 ///////////////////////////////////////////////////////////////////////////////////////////////////
324 // @param[in] sockfd - Socket file descriptor
325 // @paramp[in] log - Log data buffer
326 // This function reads the log header and remaining log from socket descriptor. Will return false
327 // if socket operation fails.
328 ///////////////////////////////////////////////////////////////////////////////////////////////////
329 bool readRemoteLogs(int sockfd, ARGDATA & log)
333 while( (len = recv(sockfd, (void*)&log.logData, RLOG_FIXED_LENGTH_BUFFER_SIZE, MSG_WAITALL)) == 0 );
342 ///////////////////////////////////////////////////////////////////////////////////////////////////
343 // @param[in] fd - input file descriptor
344 // @param[out] log - Log header
345 // This function will read the log header and returns success if able to read.
346 ///////////////////////////////////////////////////////////////////////////////////////////////////
347 bool readFileLogs(int fd, ARGDATA & log)
349 int len = read(fd, (void*)&log.logData, sizeof(LOGDATA));
355 #ifdef RLOG_MULTI_CIRCULAR_BUFFER
356 if( log.logData.len && read(fd, (void*)log.buf, log.logData.len) <= 0 ) {
360 U16 size = RLOG_FIXED_LENGTH_BUFFER_SIZE - sizeof(LOGDATA);
361 // if( log.logData.len && read(fd, (void*)log.buf, size) <= 0 ) {
362 if( read(fd, (void*)log.buf, size) <= 0 ) {
370 ///////////////////////////////////////////////////////////////////////////////////////////////////
371 // @param[in] log1 - LOG
372 // @param[in] log2 - Second Log
373 // This function compares the TTI of two consecutive logs.
374 ///////////////////////////////////////////////////////////////////////////////////////////////////
375 bool cmp_tti(ARGDATA & log1, ARGDATA & log2)
377 return log2.logData.logTime.ms_tti > log1.logData.logTime.ms_tti ? true : false;
380 ///////////////////////////////////////////////////////////////////////////////////////////////////
381 // @param[in] log - Log data
382 // This function calculates the time based on TTI & time reference associated with it. And thne
383 // calls the function to print logs in aprpriate text format.
384 ///////////////////////////////////////////////////////////////////////////////////////////////////
385 void printLog(ARGDATA & log)
388 if( invalidLogId(log.logData.logId) )
391 switch( log.logData.argType )
394 logIntArg((ARG4DATA*)&log);
406 logArgSpl((SPL_ARGDATA*)&log);
411 ///////////////////////////////////////////////////////////////////////////////////////////////////
412 // @param[in] fd - File or socket descriptor
413 // @param[in] fpReadLog - Function pointer which reads either file or socket based log
414 // This function reads the binary log file and does sorting of logs based on TTI and then calls the
415 // function to print it
416 ///////////////////////////////////////////////////////////////////////////////////////////////////
417 void processLogs(int fd, bool (*fpReadLog)(int, ARGDATA &))
420 bool bSortingRequired = false, bStartBuffering = false;
421 std::list<ARGDATA> logList;
423 while((*fpReadLog)(fd, log))
425 if( log.logData.logId == L_TIME_DELIMITER )
427 bStartBuffering = (bStartBuffering == false) ? true : false;
428 if( bStartBuffering == true ) {
429 bSortingRequired = true;
434 if( bStartBuffering ) {
435 logList.push_back(log);
439 if( bSortingRequired ) {
440 logList.sort(cmp_tti);
441 std::for_each(logList.begin(), logList.end(), printLog);
443 bSortingRequired = false;
444 bStartBuffering = false;
451 /* connection was closed due to some error, but we still have some logs */
452 if( bStartBuffering && !logList.empty() )
454 logList.sort(cmp_tti);
455 std::for_each(logList.begin(), logList.end(), printLog);
462 ///////////////////////////////////////////////////////////////////////////////////////////////////
463 // @param[in] log - LOG Data
464 // This function convert binary log with integer data type into text format.
465 ///////////////////////////////////////////////////////////////////////////////////////////////////
466 void logIntArg(ARG4DATA* log)
469 // printf("LOG ARG: INT, LEVEL: %s\n", g_logStr[log->logData.logLevel]);
472 LOG_INFO & logInfo = g_mLogInfo[log->logData.logId];
473 logLevN(log->logData,logInfo,logInfo.logStr.c_str(),log->arg1,log->arg2,log->arg3,log->arg4);
476 ///////////////////////////////////////////////////////////////////////////////////////////////////
477 // @param[in] log - LOG Data
478 // This function converts binary log containg string into text format.
479 ///////////////////////////////////////////////////////////////////////////////////////////////////
480 void logString(ARGDATA & log)
483 // printf("LOG ID %ld LOG ARG STRING, LEVEL: %s\n", log.logData.logId, g_logStr[log.logData.logLevel]);
486 LOG_INFO & logInfo = g_mLogInfo[log.logData.logId];
487 logLevS(log.logData, logInfo, logInfo.logStr.c_str(), log.buf);
490 ///////////////////////////////////////////////////////////////////////////////////////////////////
491 // @param[in] log - LOG Data
492 // This function converts binary log containg hex dump into readable text format.
493 ///////////////////////////////////////////////////////////////////////////////////////////////////
494 void logHexDump(ARGDATA & log)
497 // printf("LOG ARG HEX, LEVEL: %s\n", g_logStr[log.logData.logLevel]);
500 LOG_INFO & logInfo = g_mLogInfo[log.logData.logId];
502 char szHex[MAX_LOG_BUF_SIZE*3];
503 hextostr(szHex, log.buf, log.logData.len);
505 logLevN(log.logData, logInfo, logInfo.logStr.c_str(), szHex);
508 ///////////////////////////////////////////////////////////////////////////////////////////////////
509 // @param[in] log - LOG Data
510 // @param[in] logInfo - Log information structure reference
511 // @param[in] fmtStr - Formatted string
512 // This function prints log into console or log file.
513 ///////////////////////////////////////////////////////////////////////////////////////////////////
514 void logLevN(LOGDATA & log, LOG_INFO & logInfo, const char* fmtStr, ...)
517 const char* file = logInfo.file.c_str();
519 printLogTime(log.logTime);
520 fprintf(g_fp, "[%s]%s:%d\n%s:", logInfo.modName.c_str(), file, logInfo.lineno, g_logStr[log.logLevel]);
522 va_start(argList,fmtStr);
523 vfprintf(g_fp, fmtStr, argList);
527 ///////////////////////////////////////////////////////////////////////////////////////////////////
528 // @param[in] log - LOG Data
529 // @param[in] logInfo - Log information structure reference
530 // @param[in] fmtStr - Formatted string
531 // This function prints string log into console or log file.
532 ///////////////////////////////////////////////////////////////////////////////////////////////////
533 void logLevS(LOGDATA & log, LOG_INFO & logInfo, const char* fmtStr, const char* logStr)
535 const char* file = logInfo.file.c_str();
536 std::string argStr(logStr, log.len);
537 printLogTime(log.logTime);
538 fprintf(g_fp, "[%s]%s:%d\n%s:", logInfo.modName.c_str(), file, logInfo.lineno, g_logStr[log.logLevel]);
539 fprintf(g_fp, fmtStr, argStr.c_str());
542 ///////////////////////////////////////////////////////////////////////////////////////////////////
543 // @param[in] log - LOG Data
544 // @param[in] logInfo - Log information structure reference
545 // @param[in] fmtStr - Formatted string
546 // This function prints log into console or log file.
547 ///////////////////////////////////////////////////////////////////////////////////////////////////
548 void logLevSpl(SPL_ARGDATA* log, LOG_INFO & logInfo, const char* fmtStr, ...)
551 const char* file = logInfo.file.c_str();
553 printLogTime(log->logData.logTime);
554 fprintf(g_fp, "[%s]%s:%d\n%s:%s:%d:", logInfo.modName.c_str(), file, logInfo.lineno, g_logStr[log->logData.logLevel], g_splStr[log->splEnum], log->splArg);
556 va_start(argList,fmtStr);
557 vfprintf(g_fp, fmtStr, argList);
561 ///////////////////////////////////////////////////////////////////////////////////////////////////
562 // @param[in] log - LOG Data
563 // This function converts binary log with special arguments into text format.
564 ///////////////////////////////////////////////////////////////////////////////////////////////////
565 void logArgSpl(SPL_ARGDATA* log)
568 // printf("LOG ARG SPL, LEVEL: %s\n", g_logStr[log->logData.logLevel]);
570 LOG_INFO & logInfo = g_mLogInfo[log->logData.logId];
571 const char* file = logInfo.file.c_str();
573 logLevSpl(log, logInfo, logInfo.logStr.c_str(),log->arg1, log->arg2, log->arg3, log->arg4);
576 ///////////////////////////////////////////////////////////////////////////////////////////////////
577 // @param[in] ltime - Log time
578 // This function prints log time using standard c formating function fprintf
579 ///////////////////////////////////////////////////////////////////////////////////////////////////
580 void printLogTime(LOGTIME & ltime)
584 U32 secElapsedFromBeg;
588 ttiNum = ltime.ms_tti;
589 secElapsedFromBeg = ttiNum/1000;
590 miliseconds = ttiNum%1000;
591 curTimeSec = g_basetimeSec + secElapsedFromBeg;
593 /* Obtain the time of day, and convert it to a tm struct. --*/
594 tm = localtime (&curTimeSec);
598 fprintf(g_fp,"[%d-%d-%d %d:%d:%d.%03d]", tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900,
599 tm->tm_hour, tm->tm_min,tm->tm_sec,miliseconds);
603 ///////////////////////////////////////////////////////////////////////////////////////////////////
604 // @param[in] logId - Log id which is unique to each log
605 // This function checks if the given log id is valid based on the logdb information loaded into
607 ///////////////////////////////////////////////////////////////////////////////////////////////////
608 bool invalidLogId(LOGID logId)
610 /* if this is a time reference this is valid log */
611 if( g_mLogInfo.find(logId) == g_mLogInfo.end() )
613 if(logId != L_TIME_REFERENCE)
615 fprintf(stderr, "Invalid log id %d\n",logId);
622 ///////////////////////////////////////////////////////////////////////////////////////////////////
623 // This function parse and reads the logdb file. Extracts the information and stores into map data
625 ///////////////////////////////////////////////////////////////////////////////////////////////////
628 std::ifstream logdb(cmdlinearg::g_sLogDb.c_str());
630 if(logdb.is_open() == false) {
631 fprintf(stderr, "Failed to open file %s\n", cmdlinearg::g_sLogDb.c_str());
635 LOGID logId; LOG_INFO logInfo;
637 std::string & lstr = logInfo.logStr;
639 while( getline(logdb, line) )
641 std::istringstream iss(line);
642 int pos = 0, newpos=0;
644 logId = atol( line.substr(pos, newpos=line.find(';', pos)).c_str() );
647 logInfo.lineno = atol( line.substr(pos, (newpos=line.find(';', pos)) - pos).c_str() );
650 logInfo.modName = line.substr(pos, (newpos=line.find(';', pos)) - pos);
653 logInfo.file = line.substr(pos, (newpos=line.find('\"', pos)) - pos);
655 pos=line.find('\"',newpos+1) + 1;
656 logInfo.logStr = line.substr(pos, (newpos=line.find_last_of("\"", pos)) - pos);
657 lstr.erase(std::remove(lstr.begin(),lstr.end(),'\"')++,lstr.end());
661 std::cout << "LOG Id:" << logId << " FILE:" << logInfo.file << " lineno:" << logInfo.lineno;
662 std::cout << " MOD Name: " << logInfo.modName << std::endl;
663 std::cout << "LOG STR:[" << logInfo.logStr << "]" << std::endl;
666 logInfo.logStr+= "\n\n";
668 g_mLogInfo[logId] = logInfo;
673 logInfo.file = "NULL";
675 logInfo.modName = "RLOG";
676 logInfo.logStr = RLOG_SEGFAULT_STR;
677 g_mLogInfo[L_SIGSEGV] = logInfo;
681 ///////////////////////////////////////////////////////////////////////////////////////////////////
682 // @arg[in] argc - Number of arguments
683 // @arg[in] argv - Command line arguments
684 // This function parses the command line input parameters.
685 ///////////////////////////////////////////////////////////////////////////////////////////////////
686 void readCmdLineArgs(int argc,char **argv)
688 using namespace cmdlinearg;
689 /* getopt_long stores the option index here */
690 int c, option_index = 0;
692 while( (c = getopt_long(argc, argv, "p:f:l:o:b:i:", long_options,&option_index)) != -1 )
697 std::cout<<"option -p with value = " << optarg << std::endl;
698 cmdlinearg::g_port = atoi(optarg);
701 std::cout<<"option -f with value = "<< optarg << std::endl;
702 cmdlinearg::g_sFileDb = optarg;
705 std::cout<<"option -l with value = "<< optarg << std::endl;
706 cmdlinearg::g_sLogDb = optarg;
709 std::cout<<"option -o with value = " << optarg << std::endl;
710 cmdlinearg::g_sOutFile = optarg;
713 std::cout<<"option -b with value = " << optarg << std::endl;
714 cmdlinearg::g_sBinLogFile = optarg;
717 std::cout<<"option -i with value = " << optarg << std::endl;
718 cmdlinearg::g_ipAddr = optarg;
721 std::cout << "Invalid arguments" << std::endl;
726 // if( g_port == 0 && g_sBinLogFile.empty() )
731 ///////////////////////////////////////////////////////////////////////////////////////////////////
732 // This functin prints the binary log application usage.
733 ///////////////////////////////////////////////////////////////////////////////////////////////////
736 printf("Usage: postproc [-f <filedb> ] [-l <logdb>] [-b <binlog> | -p <port> ] [-o <outfile>] \n");
737 printf("\t[--filedb | -p <input file db > ]\n");
738 printf("\t[--logdb | -l <input log db > ]\n");
739 printf("\t[--binlog | -b <input binary log file> ]\n");
740 printf("\t[--ofile | -o <output text log file> ]\n");
741 printf("\t[--port | -p <port number> ]\n");
745 /**********************************************************************
747 **********************************************************************/