Merge lp:~mshankar/epics-base/softioclogging into lp:~epics-core/epics-base/3.15

Proposed by Andrew Johnson
Status: Merged
Merged at revision: 12239
Proposed branch: lp:~mshankar/epics-base/softioclogging
Merge into: lp:~epics-core/epics-base/3.15
Diff against target: 365 lines (+245/-14)
5 files modified
documentation/RELEASE_NOTES.html (+10/-0)
src/libCom/iocsh/libComRegister.c (+10/-0)
src/libCom/log/logClient.c (+59/-13)
src/libCom/log/logClient.h (+1/-0)
src/libCom/test/epicsErrlogTest.c (+165/-1)
To merge this branch: bzr merge lp:~mshankar/epics-base/softioclogging
Reviewer Review Type Date Requested Status
Andrew Johnson Approve
Review via email: mp+72816@code.launchpad.net

Description of the change

Codeathon: Add logClientPrefix command and functionality.
This branch includes code, tests and release notes.
AppDevGuide entry also supplied separately.

To post a comment you must log in.
Revision history for this message
Andrew Johnson (anj) wrote :

A few minor things which I will correct while merging:

* This code uses C++ comments in C files (which GCC accepts, but some compilers don't).
* The test code uses status values which are not related to the code being tested as test pass/fail results.
* New release note entries go at the top of the file, not the bottom.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'documentation/RELEASE_NOTES.html'
2--- documentation/RELEASE_NOTES.html 2011-08-23 23:19:55 +0000
3+++ documentation/RELEASE_NOTES.html 2011-08-25 00:35:04 +0000
4@@ -280,5 +280,15 @@
5 Removed the 3.13 <top>/config directory and build compatibility rules and
6 variables, and various conversion documents.</p>
7
8+<h3>
9+Added support for iocLogPrefix</h3>
10+
11+<p>
12+Added a <code>iocLogPrefix</code> command to <code>ioCsh</code>. This establishes a prefix that will be
13+common to all log messages as they are sent to the iocLogServer. This lets us use the
14+"fac=&lt;<i>facility</i>&gt;" syntax for displaying the facility, process name etc. in log viewers like the
15+<code>cmlogviewer<code>.
16+</p>
17+
18 </body>
19 </html>
20
21=== modified file 'src/libCom/iocsh/libComRegister.c'
22--- src/libCom/iocsh/libComRegister.c 2010-05-03 22:26:41 +0000
23+++ src/libCom/iocsh/libComRegister.c 2011-08-25 00:35:04 +0000
24@@ -191,6 +191,15 @@
25 errlogPrintfNoConsole("%s\n", args[0].sval);
26 }
27
28+/* iocLogPrefix */
29+static const iocshArg iocLogPrefixArg0 = { "prefix",iocshArgString};
30+static const iocshArg * const iocLogPrefixArgs[1] = {&iocLogPrefixArg0};
31+static const iocshFuncDef iocLogPrefixFuncDef = {"iocLogPrefix",1,iocLogPrefixArgs};
32+static void iocLogPrefixCallFunc(const iocshArgBuf *args)
33+{
34+ iocLogPrefix(args[0].sval);
35+}
36+
37 /* epicsThreadShowAll */
38 static const iocshArg epicsThreadShowAllArg0 = { "level",iocshArgInt};
39 static const iocshArg * const epicsThreadShowAllArgs[1] = {&epicsThreadShowAllArg0};
40@@ -355,6 +364,7 @@
41 iocshRegister(&errlogInitFuncDef,errlogInitCallFunc);
42 iocshRegister(&errlogInit2FuncDef,errlogInit2CallFunc);
43 iocshRegister(&errlogFuncDef, errlogCallFunc);
44+ iocshRegister(&iocLogPrefixFuncDef, iocLogPrefixCallFunc);
45
46 iocshRegister(&epicsThreadShowAllFuncDef,epicsThreadShowAllCallFunc);
47 iocshRegister(&threadFuncDef, threadCallFunc);
48
49=== modified file 'src/libCom/log/logClient.c'
50--- src/libCom/log/logClient.c 2009-07-09 16:37:24 +0000
51+++ src/libCom/log/logClient.c 2011-08-25 00:35:04 +0000
52@@ -58,6 +58,11 @@
53 static const double LOG_SERVER_SHUTDOWN_TIMEOUT = 30.0; /* sec */
54
55 /*
56+ * The logClientPrefix stores a prefix that is sent as a prefix for all log messages.
57+ */
58+static char* logClientPrefix = NULL;
59+
60+/*
61 * logClientClose ()
62 */
63 static void logClientClose ( logClient *pClient )
64@@ -160,21 +165,13 @@
65 }
66
67 /*
68- * logClientSend ()
69+ * private method with code refactored out of logClientSend.
70+ * This method relies on the mutex being obtained on pClient->mutex (which happens in logClientSend prior to this method being called)
71 */
72-void epicsShareAPI logClientSend ( logClientId id, const char * message )
73-{
74- logClient * pClient = ( logClient * ) id;
75+static void sendLogMessageinChunks(logClient * pClient, const char * message) {
76 unsigned strSize;
77
78- if ( ! pClient || ! message ) {
79- return;
80- }
81-
82 strSize = strlen ( message );
83-
84- epicsMutexMustLock ( pClient->mutex );
85-
86 while ( strSize ) {
87 unsigned msgBufBytesLeft =
88 sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex;
89@@ -231,10 +228,31 @@
90 break;
91 }
92 }
93-
94+}
95+
96+
97+/*
98+ * logClientSend ()
99+ */
100+void epicsShareAPI logClientSend ( logClientId id, const char * message )
101+{
102+ logClient * pClient = ( logClient * ) id;
103+
104+ if ( ! pClient || ! message ) {
105+ return;
106+ }
107+
108+ epicsMutexMustLock ( pClient->mutex );
109+
110+ if(logClientPrefix) {
111+ sendLogMessageinChunks(pClient, logClientPrefix);
112+ }
113+ sendLogMessageinChunks(pClient, message);
114+
115 epicsMutexUnlock (pClient->mutex);
116 }
117
118+
119 void epicsShareAPI logClientFlush ( logClientId id )
120 {
121 logClient * pClient = ( logClient * ) id;
122@@ -553,5 +571,33 @@
123 pClient->sock==INVALID_SOCKET?"INVALID":"OK",
124 pClient->connectCount);
125 }
126-}
127+
128+ if(logClientPrefix) {
129+ printf ("log client: a log prefix has been set \"%s\"\n", logClientPrefix);
130+ }
131+}
132+
133+/*
134+ * iocLogPrefix()
135+ **/
136+void epicsShareAPI iocLogPrefix(const char* prefix)
137+{
138+ // If we have already established a log prefix, do not let the user change it
139+ // Note iocLogPrefix is expected to be set in the cmd file during initialization.
140+ // We do not anticipate changing this after it has been set
141+ if(logClientPrefix) {
142+ printf ("log client: a log prefix has already been established \"%s\". Ignoring this call \n", logClientPrefix);
143+ return;
144+ }
145+
146+ if(prefix) {
147+ unsigned prefixLen = strlen(prefix);
148+ if(prefixLen > 0) {
149+ char* localCopy = malloc(prefixLen+1);
150+ strcpy(localCopy, prefix);
151+ logClientPrefix = localCopy;
152+ }
153+ }
154+}
155+
156
157
158=== modified file 'src/libCom/log/logClient.h'
159--- src/libCom/log/logClient.h 2005-11-22 00:28:17 +0000
160+++ src/libCom/log/logClient.h 2011-08-25 00:35:04 +0000
161@@ -33,6 +33,7 @@
162 epicsShareFunc void epicsShareAPI logClientSend (logClientId id, const char *message);
163 epicsShareFunc void epicsShareAPI logClientShow (logClientId id, unsigned level);
164 epicsShareFunc void epicsShareAPI logClientFlush (logClientId id);
165+epicsShareFunc void epicsShareAPI iocLogPrefix(const char* prefix);
166
167 /* deprecated interface; retained for backward compatibility */
168 /* note: implementations are in iocLog.c, not logClient.c */
169
170=== modified file 'src/libCom/test/epicsErrlogTest.c'
171--- src/libCom/test/epicsErrlogTest.c 2011-03-01 21:03:33 +0000
172+++ src/libCom/test/epicsErrlogTest.c 2011-08-25 00:35:04 +0000
173@@ -22,6 +22,11 @@
174 #include "errlog.h"
175 #include "epicsUnitTest.h"
176 #include "testMain.h"
177+#include "iocLog.h"
178+#include "logClient.h"
179+#include "envDefs.h"
180+#include "osiSock.h"
181+#include "fdmgr.h"
182
183 #define LOGBUFSIZE 2048
184
185@@ -75,6 +80,27 @@
186 int jam;
187 } clientPvt;
188
189+static void testLogPrefix(void);
190+static void acceptNewClient( void *pParam );
191+static void readFromClient( void *pParam );
192+static void testPrefixLogandCompare( const char* logmessage);
193+
194+static void *pfdctx;
195+static SOCKET sock;
196+static SOCKET insock;
197+
198+static const char* prefixactualmsg[]= {
199+ "A message without prefix",
200+ "A message with prefix",
201+ "DONE"
202+ };
203+static const char prefixexpectedmsg[] = "A message without prefix"
204+ "fac=LI21 A message with prefix"
205+ "fac=LI21 DONE"
206+ ;
207+static char prefixmsgbuffer[1024];
208+
209+
210 static
211 void logClient(void* raw, const char* msg)
212 {
213@@ -115,7 +141,7 @@
214 char msg[256];
215 clientPvt pvt, pvt2;
216
217- testPlan(25);
218+ testPlan(35);
219
220 strcpy(msg, truncmsg);
221
222@@ -289,5 +315,143 @@
223 /* Clean up */
224 errlogRemoveListener(&logClient);
225
226+ testLogPrefix();
227+
228 return testDone();
229 }
230+/*
231+ * Tests the log prefix code
232+ * Since the log prefix is only applied to log messages as they are going out on the socket,
233+ * we need to create a server listening on a port, accept connections etc.
234+ * This code is a reduced version of the code in iocLogServer.
235+ */
236+static void testLogPrefix(void) {
237+ struct sockaddr_in serverAddr;
238+ int status;
239+ struct timeval timeout;
240+ struct sockaddr_in actualServerAddr;
241+ osiSocklen_t actualServerAddrSize;
242+
243+
244+ testDiag("Testing iocLogPrefix");
245+
246+ timeout.tv_sec = 5; /* in seconds */
247+ timeout.tv_usec = 0;
248+
249+ memset((void*)prefixmsgbuffer, 0, sizeof prefixmsgbuffer);
250+
251+ /* Clear "errlog: <n> messages were discarded" status */
252+ errlogPrintfNoConsole(".");
253+ errlogFlush();
254+
255+ sock = epicsSocketCreate(AF_INET, SOCK_STREAM, 0);
256+ testOk1(sock != INVALID_SOCKET);
257+
258+ // We listen on a an available port.
259+ memset((void *)&serverAddr, 0, sizeof serverAddr);
260+ serverAddr.sin_family = AF_INET;
261+ serverAddr.sin_port = htons(0);
262+
263+ status = bind (sock,
264+ (struct sockaddr *)&serverAddr,
265+ sizeof (serverAddr) );
266+ testOk1(status >= 0);
267+
268+ status = listen(sock, 10);
269+ testOk1(status >= 0);
270+
271+ // Determine the port that the OS chose
272+ actualServerAddrSize = sizeof actualServerAddr;
273+ memset((void *)&actualServerAddr, 0, sizeof serverAddr);
274+ status = getsockname(sock, (struct sockaddr *) &actualServerAddr, &actualServerAddrSize);
275+ testOk1(status >= 0);
276+
277+ char portstring[16];
278+ sprintf(portstring, "%d", ntohs(actualServerAddr.sin_port));
279+ testDiag("Listening on port %s", portstring);
280+
281+ // Set the EPICS environment variables for logging.
282+ epicsEnvSet ( "EPICS_IOC_LOG_INET", "localhost" );
283+ epicsEnvSet ( "EPICS_IOC_LOG_PORT", portstring );
284+
285+ pfdctx = (void *) fdmgr_init();
286+ testOk1(pfdctx != NULL);
287+
288+ status = fdmgr_add_callback(
289+ pfdctx,
290+ sock,
291+ fdi_read,
292+ acceptNewClient,
293+ &serverAddr);
294+ testOk1(status >= 0);
295+
296+ status = iocLogInit ();
297+ testOk1(status >= 0);
298+ fdmgr_pend_event(pfdctx, &timeout);
299+
300+ testPrefixLogandCompare(prefixactualmsg[0]);
301+
302+ iocLogPrefix("fac=LI21 ");
303+ testPrefixLogandCompare(prefixactualmsg[1]);
304+ testPrefixLogandCompare(prefixactualmsg[2]);
305+
306+ close(sock);
307+}
308+
309+static void testPrefixLogandCompare( const char* logmessage ) {
310+ struct timeval timeout;
311+ timeout.tv_sec = 5; /* in seconds */
312+ timeout.tv_usec = 0;
313+
314+ errlogPrintfNoConsole(logmessage);
315+ errlogFlush();
316+ iocLogFlush();
317+ fdmgr_pend_event(pfdctx, &timeout);
318+}
319+
320+static void acceptNewClient ( void *pParam )
321+{
322+ osiSocklen_t addrSize;
323+ struct sockaddr_in addr;
324+ int status;
325+
326+ addrSize = sizeof ( addr );
327+ insock = epicsSocketAccept ( sock, (struct sockaddr *)&addr, &addrSize );
328+ testOk1(insock!=INVALID_SOCKET && addrSize >= sizeof (addr) );
329+
330+ status = fdmgr_add_callback(
331+ pfdctx,
332+ insock,
333+ fdi_read,
334+ readFromClient,
335+ NULL);
336+ testOk1(status >= 0);
337+}
338+
339+static void readFromClient(void *pParam)
340+{
341+ char recvbuf[1024];
342+ int recvLength;
343+
344+ memset(&recvbuf, 0, 1024);
345+ recvLength = recv(insock,
346+ &recvbuf,
347+ 1024,
348+ 0);
349+ if (recvLength > 0) {
350+ strcat(prefixmsgbuffer, recvbuf);
351+
352+ // If we have received all of the messages.
353+ if(strstr(prefixmsgbuffer, "DONE") != NULL) {
354+ int prefixcmp = strncmp(prefixexpectedmsg, prefixmsgbuffer, strlen(prefixexpectedmsg));
355+ if(prefixcmp != 0) {
356+ printf("Expected %s\n", prefixexpectedmsg);
357+ printf("Obtained %s\n", prefixmsgbuffer);
358+ }
359+
360+ testOk1(prefixcmp == 0);
361+ }
362+ }
363+}
364+
365+

Subscribers

People subscribed via source and target branches