Merge lp:~mshankar/epics-base/softioclogging into lp:~epics-core/epics-base/3.15
- softioclogging
- Merge into 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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andrew Johnson | Approve | ||
Review via email: mp+72816@code.launchpad.net |
Commit message
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.
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 | 280 | Removed the 3.13 <top>/config directory and build compatibility rules and | 280 | Removed the 3.13 <top>/config directory and build compatibility rules and |
6 | 281 | variables, and various conversion documents.</p> | 281 | variables, and various conversion documents.</p> |
7 | 282 | 282 | ||
8 | 283 | <h3> | ||
9 | 284 | Added support for iocLogPrefix</h3> | ||
10 | 285 | |||
11 | 286 | <p> | ||
12 | 287 | Added a <code>iocLogPrefix</code> command to <code>ioCsh</code>. This establishes a prefix that will be | ||
13 | 288 | common to all log messages as they are sent to the iocLogServer. This lets us use the | ||
14 | 289 | "fac=<<i>facility</i>>" syntax for displaying the facility, process name etc. in log viewers like the | ||
15 | 290 | <code>cmlogviewer<code>. | ||
16 | 291 | </p> | ||
17 | 292 | |||
18 | 283 | </body> | 293 | </body> |
19 | 284 | </html> | 294 | </html> |
20 | 285 | 295 | ||
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 | 191 | errlogPrintfNoConsole("%s\n", args[0].sval); | 191 | errlogPrintfNoConsole("%s\n", args[0].sval); |
26 | 192 | } | 192 | } |
27 | 193 | 193 | ||
28 | 194 | /* iocLogPrefix */ | ||
29 | 195 | static const iocshArg iocLogPrefixArg0 = { "prefix",iocshArgString}; | ||
30 | 196 | static const iocshArg * const iocLogPrefixArgs[1] = {&iocLogPrefixArg0}; | ||
31 | 197 | static const iocshFuncDef iocLogPrefixFuncDef = {"iocLogPrefix",1,iocLogPrefixArgs}; | ||
32 | 198 | static void iocLogPrefixCallFunc(const iocshArgBuf *args) | ||
33 | 199 | { | ||
34 | 200 | iocLogPrefix(args[0].sval); | ||
35 | 201 | } | ||
36 | 202 | |||
37 | 194 | /* epicsThreadShowAll */ | 203 | /* epicsThreadShowAll */ |
38 | 195 | static const iocshArg epicsThreadShowAllArg0 = { "level",iocshArgInt}; | 204 | static const iocshArg epicsThreadShowAllArg0 = { "level",iocshArgInt}; |
39 | 196 | static const iocshArg * const epicsThreadShowAllArgs[1] = {&epicsThreadShowAllArg0}; | 205 | static const iocshArg * const epicsThreadShowAllArgs[1] = {&epicsThreadShowAllArg0}; |
40 | @@ -355,6 +364,7 @@ | |||
41 | 355 | iocshRegister(&errlogInitFuncDef,errlogInitCallFunc); | 364 | iocshRegister(&errlogInitFuncDef,errlogInitCallFunc); |
42 | 356 | iocshRegister(&errlogInit2FuncDef,errlogInit2CallFunc); | 365 | iocshRegister(&errlogInit2FuncDef,errlogInit2CallFunc); |
43 | 357 | iocshRegister(&errlogFuncDef, errlogCallFunc); | 366 | iocshRegister(&errlogFuncDef, errlogCallFunc); |
44 | 367 | iocshRegister(&iocLogPrefixFuncDef, iocLogPrefixCallFunc); | ||
45 | 358 | 368 | ||
46 | 359 | iocshRegister(&epicsThreadShowAllFuncDef,epicsThreadShowAllCallFunc); | 369 | iocshRegister(&epicsThreadShowAllFuncDef,epicsThreadShowAllCallFunc); |
47 | 360 | iocshRegister(&threadFuncDef, threadCallFunc); | 370 | iocshRegister(&threadFuncDef, threadCallFunc); |
48 | 361 | 371 | ||
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 | 58 | static const double LOG_SERVER_SHUTDOWN_TIMEOUT = 30.0; /* sec */ | 58 | static const double LOG_SERVER_SHUTDOWN_TIMEOUT = 30.0; /* sec */ |
54 | 59 | 59 | ||
55 | 60 | /* | 60 | /* |
56 | 61 | * The logClientPrefix stores a prefix that is sent as a prefix for all log messages. | ||
57 | 62 | */ | ||
58 | 63 | static char* logClientPrefix = NULL; | ||
59 | 64 | |||
60 | 65 | /* | ||
61 | 61 | * logClientClose () | 66 | * logClientClose () |
62 | 62 | */ | 67 | */ |
63 | 63 | static void logClientClose ( logClient *pClient ) | 68 | static void logClientClose ( logClient *pClient ) |
64 | @@ -160,21 +165,13 @@ | |||
65 | 160 | } | 165 | } |
66 | 161 | 166 | ||
67 | 162 | /* | 167 | /* |
69 | 163 | * logClientSend () | 168 | * private method with code refactored out of logClientSend. |
70 | 169 | * This method relies on the mutex being obtained on pClient->mutex (which happens in logClientSend prior to this method being called) | ||
71 | 164 | */ | 170 | */ |
75 | 165 | void epicsShareAPI logClientSend ( logClientId id, const char * message ) | 171 | static void sendLogMessageinChunks(logClient * pClient, const char * message) { |
73 | 166 | { | ||
74 | 167 | logClient * pClient = ( logClient * ) id; | ||
76 | 168 | unsigned strSize; | 172 | unsigned strSize; |
77 | 169 | 173 | ||
78 | 170 | if ( ! pClient || ! message ) { | ||
79 | 171 | return; | ||
80 | 172 | } | ||
81 | 173 | |||
82 | 174 | strSize = strlen ( message ); | 174 | strSize = strlen ( message ); |
83 | 175 | |||
84 | 176 | epicsMutexMustLock ( pClient->mutex ); | ||
85 | 177 | |||
86 | 178 | while ( strSize ) { | 175 | while ( strSize ) { |
87 | 179 | unsigned msgBufBytesLeft = | 176 | unsigned msgBufBytesLeft = |
88 | 180 | sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex; | 177 | sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex; |
89 | @@ -231,10 +228,31 @@ | |||
90 | 231 | break; | 228 | break; |
91 | 232 | } | 229 | } |
92 | 233 | } | 230 | } |
94 | 234 | 231 | } | |
95 | 232 | |||
96 | 233 | |||
97 | 234 | /* | ||
98 | 235 | * logClientSend () | ||
99 | 236 | */ | ||
100 | 237 | void epicsShareAPI logClientSend ( logClientId id, const char * message ) | ||
101 | 238 | { | ||
102 | 239 | logClient * pClient = ( logClient * ) id; | ||
103 | 240 | |||
104 | 241 | if ( ! pClient || ! message ) { | ||
105 | 242 | return; | ||
106 | 243 | } | ||
107 | 244 | |||
108 | 245 | epicsMutexMustLock ( pClient->mutex ); | ||
109 | 246 | |||
110 | 247 | if(logClientPrefix) { | ||
111 | 248 | sendLogMessageinChunks(pClient, logClientPrefix); | ||
112 | 249 | } | ||
113 | 250 | sendLogMessageinChunks(pClient, message); | ||
114 | 251 | |||
115 | 235 | epicsMutexUnlock (pClient->mutex); | 252 | epicsMutexUnlock (pClient->mutex); |
116 | 236 | } | 253 | } |
117 | 237 | 254 | ||
118 | 255 | |||
119 | 238 | void epicsShareAPI logClientFlush ( logClientId id ) | 256 | void epicsShareAPI logClientFlush ( logClientId id ) |
120 | 239 | { | 257 | { |
121 | 240 | logClient * pClient = ( logClient * ) id; | 258 | logClient * pClient = ( logClient * ) id; |
122 | @@ -553,5 +571,33 @@ | |||
123 | 553 | pClient->sock==INVALID_SOCKET?"INVALID":"OK", | 571 | pClient->sock==INVALID_SOCKET?"INVALID":"OK", |
124 | 554 | pClient->connectCount); | 572 | pClient->connectCount); |
125 | 555 | } | 573 | } |
127 | 556 | } | 574 | |
128 | 575 | if(logClientPrefix) { | ||
129 | 576 | printf ("log client: a log prefix has been set \"%s\"\n", logClientPrefix); | ||
130 | 577 | } | ||
131 | 578 | } | ||
132 | 579 | |||
133 | 580 | /* | ||
134 | 581 | * iocLogPrefix() | ||
135 | 582 | **/ | ||
136 | 583 | void epicsShareAPI iocLogPrefix(const char* prefix) | ||
137 | 584 | { | ||
138 | 585 | // If we have already established a log prefix, do not let the user change it | ||
139 | 586 | // Note iocLogPrefix is expected to be set in the cmd file during initialization. | ||
140 | 587 | // We do not anticipate changing this after it has been set | ||
141 | 588 | if(logClientPrefix) { | ||
142 | 589 | printf ("log client: a log prefix has already been established \"%s\". Ignoring this call \n", logClientPrefix); | ||
143 | 590 | return; | ||
144 | 591 | } | ||
145 | 592 | |||
146 | 593 | if(prefix) { | ||
147 | 594 | unsigned prefixLen = strlen(prefix); | ||
148 | 595 | if(prefixLen > 0) { | ||
149 | 596 | char* localCopy = malloc(prefixLen+1); | ||
150 | 597 | strcpy(localCopy, prefix); | ||
151 | 598 | logClientPrefix = localCopy; | ||
152 | 599 | } | ||
153 | 600 | } | ||
154 | 601 | } | ||
155 | 602 | |||
156 | 557 | 603 | ||
157 | 558 | 604 | ||
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 | 33 | epicsShareFunc void epicsShareAPI logClientSend (logClientId id, const char *message); | 33 | epicsShareFunc void epicsShareAPI logClientSend (logClientId id, const char *message); |
163 | 34 | epicsShareFunc void epicsShareAPI logClientShow (logClientId id, unsigned level); | 34 | epicsShareFunc void epicsShareAPI logClientShow (logClientId id, unsigned level); |
164 | 35 | epicsShareFunc void epicsShareAPI logClientFlush (logClientId id); | 35 | epicsShareFunc void epicsShareAPI logClientFlush (logClientId id); |
165 | 36 | epicsShareFunc void epicsShareAPI iocLogPrefix(const char* prefix); | ||
166 | 36 | 37 | ||
167 | 37 | /* deprecated interface; retained for backward compatibility */ | 38 | /* deprecated interface; retained for backward compatibility */ |
168 | 38 | /* note: implementations are in iocLog.c, not logClient.c */ | 39 | /* note: implementations are in iocLog.c, not logClient.c */ |
169 | 39 | 40 | ||
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 | 22 | #include "errlog.h" | 22 | #include "errlog.h" |
175 | 23 | #include "epicsUnitTest.h" | 23 | #include "epicsUnitTest.h" |
176 | 24 | #include "testMain.h" | 24 | #include "testMain.h" |
177 | 25 | #include "iocLog.h" | ||
178 | 26 | #include "logClient.h" | ||
179 | 27 | #include "envDefs.h" | ||
180 | 28 | #include "osiSock.h" | ||
181 | 29 | #include "fdmgr.h" | ||
182 | 25 | 30 | ||
183 | 26 | #define LOGBUFSIZE 2048 | 31 | #define LOGBUFSIZE 2048 |
184 | 27 | 32 | ||
185 | @@ -75,6 +80,27 @@ | |||
186 | 75 | int jam; | 80 | int jam; |
187 | 76 | } clientPvt; | 81 | } clientPvt; |
188 | 77 | 82 | ||
189 | 83 | static void testLogPrefix(void); | ||
190 | 84 | static void acceptNewClient( void *pParam ); | ||
191 | 85 | static void readFromClient( void *pParam ); | ||
192 | 86 | static void testPrefixLogandCompare( const char* logmessage); | ||
193 | 87 | |||
194 | 88 | static void *pfdctx; | ||
195 | 89 | static SOCKET sock; | ||
196 | 90 | static SOCKET insock; | ||
197 | 91 | |||
198 | 92 | static const char* prefixactualmsg[]= { | ||
199 | 93 | "A message without prefix", | ||
200 | 94 | "A message with prefix", | ||
201 | 95 | "DONE" | ||
202 | 96 | }; | ||
203 | 97 | static const char prefixexpectedmsg[] = "A message without prefix" | ||
204 | 98 | "fac=LI21 A message with prefix" | ||
205 | 99 | "fac=LI21 DONE" | ||
206 | 100 | ; | ||
207 | 101 | static char prefixmsgbuffer[1024]; | ||
208 | 102 | |||
209 | 103 | |||
210 | 78 | static | 104 | static |
211 | 79 | void logClient(void* raw, const char* msg) | 105 | void logClient(void* raw, const char* msg) |
212 | 80 | { | 106 | { |
213 | @@ -115,7 +141,7 @@ | |||
214 | 115 | char msg[256]; | 141 | char msg[256]; |
215 | 116 | clientPvt pvt, pvt2; | 142 | clientPvt pvt, pvt2; |
216 | 117 | 143 | ||
218 | 118 | testPlan(25); | 144 | testPlan(35); |
219 | 119 | 145 | ||
220 | 120 | strcpy(msg, truncmsg); | 146 | strcpy(msg, truncmsg); |
221 | 121 | 147 | ||
222 | @@ -289,5 +315,143 @@ | |||
223 | 289 | /* Clean up */ | 315 | /* Clean up */ |
224 | 290 | errlogRemoveListener(&logClient); | 316 | errlogRemoveListener(&logClient); |
225 | 291 | 317 | ||
226 | 318 | testLogPrefix(); | ||
227 | 319 | |||
228 | 292 | return testDone(); | 320 | return testDone(); |
229 | 293 | } | 321 | } |
230 | 322 | /* | ||
231 | 323 | * Tests the log prefix code | ||
232 | 324 | * Since the log prefix is only applied to log messages as they are going out on the socket, | ||
233 | 325 | * we need to create a server listening on a port, accept connections etc. | ||
234 | 326 | * This code is a reduced version of the code in iocLogServer. | ||
235 | 327 | */ | ||
236 | 328 | static void testLogPrefix(void) { | ||
237 | 329 | struct sockaddr_in serverAddr; | ||
238 | 330 | int status; | ||
239 | 331 | struct timeval timeout; | ||
240 | 332 | struct sockaddr_in actualServerAddr; | ||
241 | 333 | osiSocklen_t actualServerAddrSize; | ||
242 | 334 | |||
243 | 335 | |||
244 | 336 | testDiag("Testing iocLogPrefix"); | ||
245 | 337 | |||
246 | 338 | timeout.tv_sec = 5; /* in seconds */ | ||
247 | 339 | timeout.tv_usec = 0; | ||
248 | 340 | |||
249 | 341 | memset((void*)prefixmsgbuffer, 0, sizeof prefixmsgbuffer); | ||
250 | 342 | |||
251 | 343 | /* Clear "errlog: <n> messages were discarded" status */ | ||
252 | 344 | errlogPrintfNoConsole("."); | ||
253 | 345 | errlogFlush(); | ||
254 | 346 | |||
255 | 347 | sock = epicsSocketCreate(AF_INET, SOCK_STREAM, 0); | ||
256 | 348 | testOk1(sock != INVALID_SOCKET); | ||
257 | 349 | |||
258 | 350 | // We listen on a an available port. | ||
259 | 351 | memset((void *)&serverAddr, 0, sizeof serverAddr); | ||
260 | 352 | serverAddr.sin_family = AF_INET; | ||
261 | 353 | serverAddr.sin_port = htons(0); | ||
262 | 354 | |||
263 | 355 | status = bind (sock, | ||
264 | 356 | (struct sockaddr *)&serverAddr, | ||
265 | 357 | sizeof (serverAddr) ); | ||
266 | 358 | testOk1(status >= 0); | ||
267 | 359 | |||
268 | 360 | status = listen(sock, 10); | ||
269 | 361 | testOk1(status >= 0); | ||
270 | 362 | |||
271 | 363 | // Determine the port that the OS chose | ||
272 | 364 | actualServerAddrSize = sizeof actualServerAddr; | ||
273 | 365 | memset((void *)&actualServerAddr, 0, sizeof serverAddr); | ||
274 | 366 | status = getsockname(sock, (struct sockaddr *) &actualServerAddr, &actualServerAddrSize); | ||
275 | 367 | testOk1(status >= 0); | ||
276 | 368 | |||
277 | 369 | char portstring[16]; | ||
278 | 370 | sprintf(portstring, "%d", ntohs(actualServerAddr.sin_port)); | ||
279 | 371 | testDiag("Listening on port %s", portstring); | ||
280 | 372 | |||
281 | 373 | // Set the EPICS environment variables for logging. | ||
282 | 374 | epicsEnvSet ( "EPICS_IOC_LOG_INET", "localhost" ); | ||
283 | 375 | epicsEnvSet ( "EPICS_IOC_LOG_PORT", portstring ); | ||
284 | 376 | |||
285 | 377 | pfdctx = (void *) fdmgr_init(); | ||
286 | 378 | testOk1(pfdctx != NULL); | ||
287 | 379 | |||
288 | 380 | status = fdmgr_add_callback( | ||
289 | 381 | pfdctx, | ||
290 | 382 | sock, | ||
291 | 383 | fdi_read, | ||
292 | 384 | acceptNewClient, | ||
293 | 385 | &serverAddr); | ||
294 | 386 | testOk1(status >= 0); | ||
295 | 387 | |||
296 | 388 | status = iocLogInit (); | ||
297 | 389 | testOk1(status >= 0); | ||
298 | 390 | fdmgr_pend_event(pfdctx, &timeout); | ||
299 | 391 | |||
300 | 392 | testPrefixLogandCompare(prefixactualmsg[0]); | ||
301 | 393 | |||
302 | 394 | iocLogPrefix("fac=LI21 "); | ||
303 | 395 | testPrefixLogandCompare(prefixactualmsg[1]); | ||
304 | 396 | testPrefixLogandCompare(prefixactualmsg[2]); | ||
305 | 397 | |||
306 | 398 | close(sock); | ||
307 | 399 | } | ||
308 | 400 | |||
309 | 401 | static void testPrefixLogandCompare( const char* logmessage ) { | ||
310 | 402 | struct timeval timeout; | ||
311 | 403 | timeout.tv_sec = 5; /* in seconds */ | ||
312 | 404 | timeout.tv_usec = 0; | ||
313 | 405 | |||
314 | 406 | errlogPrintfNoConsole(logmessage); | ||
315 | 407 | errlogFlush(); | ||
316 | 408 | iocLogFlush(); | ||
317 | 409 | fdmgr_pend_event(pfdctx, &timeout); | ||
318 | 410 | } | ||
319 | 411 | |||
320 | 412 | static void acceptNewClient ( void *pParam ) | ||
321 | 413 | { | ||
322 | 414 | osiSocklen_t addrSize; | ||
323 | 415 | struct sockaddr_in addr; | ||
324 | 416 | int status; | ||
325 | 417 | |||
326 | 418 | addrSize = sizeof ( addr ); | ||
327 | 419 | insock = epicsSocketAccept ( sock, (struct sockaddr *)&addr, &addrSize ); | ||
328 | 420 | testOk1(insock!=INVALID_SOCKET && addrSize >= sizeof (addr) ); | ||
329 | 421 | |||
330 | 422 | status = fdmgr_add_callback( | ||
331 | 423 | pfdctx, | ||
332 | 424 | insock, | ||
333 | 425 | fdi_read, | ||
334 | 426 | readFromClient, | ||
335 | 427 | NULL); | ||
336 | 428 | testOk1(status >= 0); | ||
337 | 429 | } | ||
338 | 430 | |||
339 | 431 | static void readFromClient(void *pParam) | ||
340 | 432 | { | ||
341 | 433 | char recvbuf[1024]; | ||
342 | 434 | int recvLength; | ||
343 | 435 | |||
344 | 436 | memset(&recvbuf, 0, 1024); | ||
345 | 437 | recvLength = recv(insock, | ||
346 | 438 | &recvbuf, | ||
347 | 439 | 1024, | ||
348 | 440 | 0); | ||
349 | 441 | if (recvLength > 0) { | ||
350 | 442 | strcat(prefixmsgbuffer, recvbuf); | ||
351 | 443 | |||
352 | 444 | // If we have received all of the messages. | ||
353 | 445 | if(strstr(prefixmsgbuffer, "DONE") != NULL) { | ||
354 | 446 | int prefixcmp = strncmp(prefixexpectedmsg, prefixmsgbuffer, strlen(prefixexpectedmsg)); | ||
355 | 447 | if(prefixcmp != 0) { | ||
356 | 448 | printf("Expected %s\n", prefixexpectedmsg); | ||
357 | 449 | printf("Obtained %s\n", prefixmsgbuffer); | ||
358 | 450 | } | ||
359 | 451 | |||
360 | 452 | testOk1(prefixcmp == 0); | ||
361 | 453 | } | ||
362 | 454 | } | ||
363 | 455 | } | ||
364 | 456 | |||
365 | 457 |
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.