Merged Murali Shankar's iocLogPrefix changes.
Adjusted a few things during the merge.
This commit is contained in:
@@ -15,6 +15,16 @@ EPICS Base 3.15.0.x releases are not intended for use in production systems.</p>
|
||||
<h2 align="center">Changes between 3.14.x and 3.15.0.x</h2>
|
||||
<!-- Insert new items immediately below here ... -->
|
||||
|
||||
<h3>
|
||||
Added support for iocLogPrefix</h3>
|
||||
|
||||
<p>
|
||||
Added a <code>iocLogPrefix</code> command to <code>iocsh</code>. This adds a
|
||||
prefix to all messages from this IOC (or other log client) as they get sent to the
|
||||
iocLogServer. This lets sites use the "fac=<<i>facility</i>>" syntax for
|
||||
displaying the facility, process name etc. in log viewers like the
|
||||
<code>cmlogviewer<code>.</p>
|
||||
|
||||
<h3>
|
||||
Reworked the epicsEvent C & C++ APIs</h3>
|
||||
|
||||
|
||||
@@ -191,6 +191,15 @@ static void errlogCallFunc(const iocshArgBuf *args)
|
||||
errlogPrintfNoConsole("%s\n", args[0].sval);
|
||||
}
|
||||
|
||||
/* iocLogPrefix */
|
||||
static const iocshArg iocLogPrefixArg0 = { "prefix",iocshArgString};
|
||||
static const iocshArg * const iocLogPrefixArgs[1] = {&iocLogPrefixArg0};
|
||||
static const iocshFuncDef iocLogPrefixFuncDef = {"iocLogPrefix",1,iocLogPrefixArgs};
|
||||
static void iocLogPrefixCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
iocLogPrefix(args[0].sval);
|
||||
}
|
||||
|
||||
/* epicsThreadShowAll */
|
||||
static const iocshArg epicsThreadShowAllArg0 = { "level",iocshArgInt};
|
||||
static const iocshArg * const epicsThreadShowAllArgs[1] = {&epicsThreadShowAllArg0};
|
||||
@@ -355,6 +364,7 @@ void epicsShareAPI libComRegister(void)
|
||||
iocshRegister(&errlogInitFuncDef,errlogInitCallFunc);
|
||||
iocshRegister(&errlogInit2FuncDef,errlogInit2CallFunc);
|
||||
iocshRegister(&errlogFuncDef, errlogCallFunc);
|
||||
iocshRegister(&iocLogPrefixFuncDef, iocLogPrefixCallFunc);
|
||||
|
||||
iocshRegister(&epicsThreadShowAllFuncDef,epicsThreadShowAllCallFunc);
|
||||
iocshRegister(&threadFuncDef, threadCallFunc);
|
||||
|
||||
@@ -57,6 +57,11 @@ static const double LOG_RESTART_DELAY = 5.0; /* sec */
|
||||
static const double LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT = 5.0; /* sec */
|
||||
static const double LOG_SERVER_SHUTDOWN_TIMEOUT = 30.0; /* sec */
|
||||
|
||||
/*
|
||||
* If set using iocLogPrefix() this string is prepended to all log messages:
|
||||
*/
|
||||
static char* logClientPrefix = NULL;
|
||||
|
||||
/*
|
||||
* logClientClose ()
|
||||
*/
|
||||
@@ -159,22 +164,13 @@ static void logClientDestroy (logClientId id)
|
||||
free ( pClient );
|
||||
}
|
||||
|
||||
/*
|
||||
* logClientSend ()
|
||||
/*
|
||||
* This method requires the pClient->mutex be owned already.
|
||||
*/
|
||||
void epicsShareAPI logClientSend ( logClientId id, const char * message )
|
||||
{
|
||||
logClient * pClient = ( logClient * ) id;
|
||||
static void sendMessageChunk(logClient * pClient, const char * message) {
|
||||
unsigned strSize;
|
||||
|
||||
if ( ! pClient || ! message ) {
|
||||
return;
|
||||
}
|
||||
|
||||
strSize = strlen ( message );
|
||||
|
||||
epicsMutexMustLock ( pClient->mutex );
|
||||
|
||||
while ( strSize ) {
|
||||
unsigned msgBufBytesLeft =
|
||||
sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex;
|
||||
@@ -231,10 +227,31 @@ void epicsShareAPI logClientSend ( logClientId id, const char * message )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* logClientSend ()
|
||||
*/
|
||||
void epicsShareAPI logClientSend ( logClientId id, const char * message )
|
||||
{
|
||||
logClient * pClient = ( logClient * ) id;
|
||||
|
||||
if ( ! pClient || ! message ) {
|
||||
return;
|
||||
}
|
||||
|
||||
epicsMutexMustLock ( pClient->mutex );
|
||||
|
||||
if (logClientPrefix) {
|
||||
sendMessageChunk(pClient, logClientPrefix);
|
||||
}
|
||||
sendMessageChunk(pClient, message);
|
||||
|
||||
epicsMutexUnlock (pClient->mutex);
|
||||
}
|
||||
|
||||
|
||||
void epicsShareAPI logClientFlush ( logClientId id )
|
||||
{
|
||||
logClient * pClient = ( logClient * ) id;
|
||||
@@ -553,5 +570,36 @@ void epicsShareAPI logClientShow (logClientId id, unsigned level)
|
||||
pClient->sock==INVALID_SOCKET?"INVALID":"OK",
|
||||
pClient->connectCount);
|
||||
}
|
||||
|
||||
if (logClientPrefix) {
|
||||
printf ("log client: prefix is \"%s\"\n", logClientPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* iocLogPrefix()
|
||||
*/
|
||||
void epicsShareAPI iocLogPrefix(const char * prefix)
|
||||
{
|
||||
|
||||
/* If we have already established a log prefix, don't let the user change
|
||||
* it. The iocLogPrefix command is expected to be run from the IOC startup
|
||||
* script during initialization; the prefix can't be changed once it has
|
||||
* been set.
|
||||
*/
|
||||
|
||||
if (logClientPrefix) {
|
||||
printf ("iocLogPrefix: The prefix was already set to \"%s\" "
|
||||
"and can't be changed.\n", logClientPrefix);
|
||||
return;
|
||||
}
|
||||
|
||||
if (prefix) {
|
||||
unsigned prefixLen = strlen(prefix);
|
||||
if (prefixLen > 0) {
|
||||
char * localCopy = malloc(prefixLen+1);
|
||||
strcpy(localCopy, prefix);
|
||||
logClientPrefix = localCopy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ epicsShareFunc logClientId epicsShareAPI logClientCreate (
|
||||
epicsShareFunc void epicsShareAPI logClientSend (logClientId id, const char *message);
|
||||
epicsShareFunc void epicsShareAPI logClientShow (logClientId id, unsigned level);
|
||||
epicsShareFunc void epicsShareAPI logClientFlush (logClientId id);
|
||||
epicsShareFunc void epicsShareAPI iocLogPrefix(const char* prefix);
|
||||
|
||||
/* deprecated interface; retained for backward compatibility */
|
||||
/* note: implementations are in iocLog.c, not logClient.c */
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
#include "errlog.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
#include "iocLog.h"
|
||||
#include "logClient.h"
|
||||
#include "envDefs.h"
|
||||
#include "osiSock.h"
|
||||
#include "fdmgr.h"
|
||||
|
||||
#define LOGBUFSIZE 2048
|
||||
|
||||
@@ -75,6 +80,28 @@ typedef struct {
|
||||
int jam;
|
||||
} clientPvt;
|
||||
|
||||
static void testLogPrefix(void);
|
||||
static void acceptNewClient( void *pParam );
|
||||
static void readFromClient( void *pParam );
|
||||
static void testPrefixLogandCompare( const char* logmessage);
|
||||
|
||||
static void *pfdctx;
|
||||
static SOCKET sock;
|
||||
static SOCKET insock;
|
||||
|
||||
static const char* prefixactualmsg[]= {
|
||||
"A message without prefix",
|
||||
"A message with prefix",
|
||||
"DONE"
|
||||
};
|
||||
static const char *prefixstring = "fac=LI21 ";
|
||||
static const char prefixexpectedmsg[] = "A message without prefix"
|
||||
"fac=LI21 A message with prefix"
|
||||
"fac=LI21 DONE"
|
||||
;
|
||||
static char prefixmsgbuffer[1024];
|
||||
|
||||
|
||||
static
|
||||
void logClient(void* raw, const char* msg)
|
||||
{
|
||||
@@ -115,7 +142,7 @@ MAIN(epicsErrlogTest)
|
||||
char msg[256];
|
||||
clientPvt pvt, pvt2;
|
||||
|
||||
testPlan(25);
|
||||
testPlan(29);
|
||||
|
||||
strcpy(msg, truncmsg);
|
||||
|
||||
@@ -143,7 +170,7 @@ MAIN(epicsErrlogTest)
|
||||
pvt.expect = "Testing";
|
||||
pvt.checkLen = strlen(pvt.expect);
|
||||
|
||||
errlogPrintfNoConsole(pvt.expect);
|
||||
errlogPrintfNoConsole("%s", pvt.expect);
|
||||
errlogFlush();
|
||||
|
||||
testOk1(pvt.count == 1);
|
||||
@@ -153,7 +180,7 @@ MAIN(epicsErrlogTest)
|
||||
pvt2.expect = pvt.expect = "Testing2";
|
||||
pvt2.checkLen = pvt.checkLen = strlen(pvt.expect);
|
||||
|
||||
errlogPrintfNoConsole(pvt.expect);
|
||||
errlogPrintfNoConsole("%s", pvt.expect);
|
||||
errlogFlush();
|
||||
|
||||
testOk1(pvt.count == 2);
|
||||
@@ -165,7 +192,7 @@ MAIN(epicsErrlogTest)
|
||||
pvt2.expect = "Testing3";
|
||||
pvt2.checkLen = strlen(pvt2.expect);
|
||||
|
||||
errlogPrintfNoConsole(pvt2.expect);
|
||||
errlogPrintfNoConsole("%s", pvt2.expect);
|
||||
errlogFlush();
|
||||
|
||||
testOk1(pvt.count == 2);
|
||||
@@ -227,7 +254,7 @@ MAIN(epicsErrlogTest)
|
||||
pvt.jam = 1;
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
errlogPrintfNoConsole(msg);
|
||||
errlogPrintfNoConsole("%s", msg);
|
||||
}
|
||||
|
||||
epicsEventSignal(pvt.jammer);
|
||||
@@ -258,7 +285,7 @@ MAIN(epicsErrlogTest)
|
||||
testDiag("Filling with %d messages of size %d", (int) N, (int) mlen);
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
errlogPrintfNoConsole(msg);
|
||||
errlogPrintfNoConsole("%s", msg);
|
||||
}
|
||||
epicsThreadSleep(0.1); /* should really be a second Event */
|
||||
|
||||
@@ -273,10 +300,10 @@ MAIN(epicsErrlogTest)
|
||||
testOk1(pvt.count == 2);
|
||||
|
||||
/* The buffer has space for 1 more message: sizeof(msgNode) + 256 bytes */
|
||||
errlogPrintfNoConsole(msg); /* Use up that space */
|
||||
errlogPrintfNoConsole("%s", msg); /* Use up that space */
|
||||
|
||||
testDiag("Overflow the buffer");
|
||||
errlogPrintfNoConsole(msg);
|
||||
errlogPrintfNoConsole("%s", msg);
|
||||
|
||||
testOk1(pvt.count == 2);
|
||||
|
||||
@@ -289,5 +316,143 @@ MAIN(epicsErrlogTest)
|
||||
/* Clean up */
|
||||
errlogRemoveListener(&logClient);
|
||||
|
||||
testLogPrefix();
|
||||
|
||||
return testDone();
|
||||
}
|
||||
/*
|
||||
* Tests the log prefix code
|
||||
* The prefix is only applied to log messages as they go out to the socket,
|
||||
* so we need to create a server listening on a port, accept connections etc.
|
||||
* This code is a reduced version of the code in iocLogServer.
|
||||
*/
|
||||
static void testLogPrefix(void) {
|
||||
struct sockaddr_in serverAddr;
|
||||
int status;
|
||||
struct timeval timeout;
|
||||
struct sockaddr_in actualServerAddr;
|
||||
osiSocklen_t actualServerAddrSize;
|
||||
char portstring[16];
|
||||
|
||||
|
||||
testDiag("Testing iocLogPrefix");
|
||||
|
||||
timeout.tv_sec = 5; /* in seconds */
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
memset((void*)prefixmsgbuffer, 0, sizeof prefixmsgbuffer);
|
||||
|
||||
/* Clear "errlog: <n> messages were discarded" status */
|
||||
errlogPrintfNoConsole(".");
|
||||
errlogFlush();
|
||||
|
||||
sock = epicsSocketCreate(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
testAbort("epicsSocketCreate failed.");
|
||||
}
|
||||
|
||||
/* We listen on a an available port. */
|
||||
memset((void *)&serverAddr, 0, sizeof serverAddr);
|
||||
serverAddr.sin_family = AF_INET;
|
||||
serverAddr.sin_port = htons(0);
|
||||
|
||||
status = bind (sock, (struct sockaddr *)&serverAddr,
|
||||
sizeof (serverAddr) );
|
||||
if (status < 0) {
|
||||
testAbort("bind failed; all ports in use?");
|
||||
}
|
||||
|
||||
status = listen(sock, 10);
|
||||
if (status < 0) {
|
||||
testAbort("listen failed!");
|
||||
}
|
||||
|
||||
/* Determine the port that the OS chose */
|
||||
actualServerAddrSize = sizeof actualServerAddr;
|
||||
memset((void *)&actualServerAddr, 0, sizeof serverAddr);
|
||||
status = getsockname(sock, (struct sockaddr *) &actualServerAddr,
|
||||
&actualServerAddrSize);
|
||||
if (status < 0) {
|
||||
testAbort("Can't find port number!");
|
||||
}
|
||||
|
||||
sprintf(portstring, "%d", ntohs(actualServerAddr.sin_port));
|
||||
testDiag("Listening on port %s", portstring);
|
||||
|
||||
/* Set the EPICS environment variables for logging. */
|
||||
epicsEnvSet ( "EPICS_IOC_LOG_INET", "localhost" );
|
||||
epicsEnvSet ( "EPICS_IOC_LOG_PORT", portstring );
|
||||
|
||||
pfdctx = (void *) fdmgr_init();
|
||||
if (status < 0) {
|
||||
testAbort("fdmgr_init failed!");
|
||||
}
|
||||
|
||||
status = fdmgr_add_callback(pfdctx, sock, fdi_read,
|
||||
acceptNewClient, &serverAddr);
|
||||
|
||||
if (status < 0) {
|
||||
testAbort("fdmgr_add_callback failed!");
|
||||
}
|
||||
|
||||
testOk1(iocLogInit() == 0);
|
||||
fdmgr_pend_event(pfdctx, &timeout);
|
||||
|
||||
testPrefixLogandCompare(prefixactualmsg[0]);
|
||||
|
||||
iocLogPrefix(prefixstring);
|
||||
testPrefixLogandCompare(prefixactualmsg[1]);
|
||||
testPrefixLogandCompare(prefixactualmsg[2]);
|
||||
close(sock);
|
||||
}
|
||||
|
||||
static void testPrefixLogandCompare( const char* logmessage ) {
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 5; /* in seconds */
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
errlogPrintfNoConsole("%s", logmessage);
|
||||
errlogFlush();
|
||||
iocLogFlush();
|
||||
fdmgr_pend_event(pfdctx, &timeout);
|
||||
}
|
||||
|
||||
static void acceptNewClient ( void *pParam )
|
||||
{
|
||||
osiSocklen_t addrSize;
|
||||
struct sockaddr_in addr;
|
||||
int status;
|
||||
|
||||
addrSize = sizeof ( addr );
|
||||
insock = epicsSocketAccept ( sock, (struct sockaddr *)&addr, &addrSize );
|
||||
testOk(insock != INVALID_SOCKET && addrSize >= sizeof (addr),
|
||||
"Accepted new client");
|
||||
|
||||
status = fdmgr_add_callback(pfdctx, insock, fdi_read,
|
||||
readFromClient, NULL);
|
||||
|
||||
testOk(status >= 0, "Client read configured");
|
||||
}
|
||||
|
||||
static void readFromClient(void *pParam)
|
||||
{
|
||||
char recvbuf[1024];
|
||||
int recvLength;
|
||||
|
||||
memset(&recvbuf, 0, 1024);
|
||||
recvLength = recv(insock, &recvbuf, 1024, 0);
|
||||
if (recvLength > 0) {
|
||||
strcat(prefixmsgbuffer, recvbuf);
|
||||
|
||||
/* If we have received all of the messages. */
|
||||
if (strstr(prefixmsgbuffer, "DONE") != NULL) {
|
||||
size_t msglen = strlen(prefixexpectedmsg);
|
||||
int prefixcmp = strncmp(prefixexpectedmsg, prefixmsgbuffer, msglen);
|
||||
|
||||
if (!testOk(prefixcmp == 0, "prefix matches")) {
|
||||
testDiag("Expected '%s'\n", prefixexpectedmsg);
|
||||
testDiag("Obtained '%s'\n", prefixmsgbuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user