|
1 // Flogger.cpp |
|
2 // |
|
3 // Copyright (c) 2006 - 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "Eclipse Public License v1.0" |
|
6 // which accompanies this distribution, and is available |
|
7 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 // |
|
9 // Initial Contributors: |
|
10 // Accenture - Initial contribution |
|
11 // |
|
12 |
|
13 #include <e32base.h> |
|
14 #include <fshell/clogger.h> |
|
15 #include "cliserv.h" |
|
16 |
|
17 // This file is shared between building shims for traditional flogger and comms debug util |
|
18 // Bits specific to one or the other are guarded with __CDU__ |
|
19 |
|
20 #ifdef __CDU__ |
|
21 |
|
22 #define __FLOG_SUPPRESS_REL_WARNING |
|
23 #define __FLOG_ACTIVE |
|
24 #include <comms-infras/commsdebugutility.h> |
|
25 #define iPtr ((RClogger*)iLoggerBody) |
|
26 #define Connected() (iPtr && iPtr->Handle()) |
|
27 #define DoClose() { if (iPtr) { iPtr->Close(); delete iPtr; iLoggerBody = NULL; } } |
|
28 |
|
29 #else |
|
30 |
|
31 #include <flogger.h> |
|
32 #define iPtr (*((RClogger**)&iFormatter)) |
|
33 #define Connected() (iPtr && iPtr->Handle()) |
|
34 #define DoClose() { if (iPtr) { iPtr->Close(); delete iPtr; } } |
|
35 |
|
36 #endif |
|
37 |
|
38 #define iClogger (*iPtr) |
|
39 #define FlogPtr(clogPtr) ((RFloggerClogger*)clogPtr) |
|
40 |
|
41 // declares RClogger* clogger |
|
42 #define CheckConnected(aDir, aPath) \ |
|
43 RClogger _cloggerHandle; \ |
|
44 RClogger* clogger = &_cloggerHandle; \ |
|
45 GetTls(clogger, ETrue, &aDir, &aPath, ETrue, NULL); \ |
|
46 if (!clogger) return |
|
47 |
|
48 #define CheckConnected8(aDir, aPath) \ |
|
49 RClogger _cloggerHandle; \ |
|
50 RClogger* clogger = &_cloggerHandle; \ |
|
51 GetTls(clogger, ETrue, &aDir, &aPath, EFalse, NULL); \ |
|
52 if (!clogger) return |
|
53 |
|
54 /* |
|
55 #define GetTlsOrConnect(aTag) \ |
|
56 RClogger _cloggerHandle; \ |
|
57 RClogger* clogger = &_cloggerHandle; \ |
|
58 TInt err; \ |
|
59 TBool isHandle = GetTls(clogger, ETrue, &aTag, &err) |
|
60 */ |
|
61 |
|
62 #define GetTlsOrNull() \ |
|
63 RClogger _cloggerHandle; \ |
|
64 RClogger* clogger = &_cloggerHandle; \ |
|
65 TBool isHandle = ::GetTls(clogger, EFalse, &KNullDesC, &KNullDesC, ETrue, NULL) |
|
66 |
|
67 #define KDontAllocateWhileLogging 0x20000000 |
|
68 |
|
69 static TBool GetTls(RClogger*& aClogger, TBool aAutoConnect, const TAny* aTag, const TAny* aSubTag, TBool aWide, TInt* aError); |
|
70 |
|
71 // Need these because flogger has a single-argument overload that doesn't have a format applied over it, and clogger doesn't |
|
72 _LIT8(KEsc8, "%S"); |
|
73 _LIT(KEsc, "%S"); |
|
74 |
|
75 #define iBody (*(RCloggerBody*)&iPimpl) |
|
76 |
|
77 #ifdef _DEBUG |
|
78 // Close the session after every call in debug builds, to avoid heap-check and handle-check failures |
|
79 #define STATICCLOSE() RFloggerClogger::FloggerStaticClose() |
|
80 #else |
|
81 #define STATICCLOSE() |
|
82 #endif |
|
83 |
|
84 class RFloggerClogger : public RClogger |
|
85 { |
|
86 public: |
|
87 TUint& Flags() |
|
88 { |
|
89 return iFlags; |
|
90 } |
|
91 |
|
92 TInt FloggerConnect(const TDesC& aDir, const TDesC& aName) |
|
93 { |
|
94 TAny* arg1 = NULL; |
|
95 TInt err = Reserved(0xF10C10, arg1, NULL); // Does the connect |
|
96 if (!err) |
|
97 { |
|
98 err = DoSetTags(aDir, aName); |
|
99 } |
|
100 return err; |
|
101 } |
|
102 |
|
103 TInt FloggerConnect(const TDesC8& aDir, const TDesC8& aName) |
|
104 { |
|
105 TAny* arg1 = NULL; |
|
106 TInt err = Reserved(0xF10C10, arg1, NULL); // Does the connect |
|
107 if (!err) |
|
108 { |
|
109 err = DoSetTags8(aDir, aName); |
|
110 } |
|
111 return err; |
|
112 } |
|
113 |
|
114 TInt DoSetTags(const TDesC& aDir, const TDesC& aName) |
|
115 { |
|
116 //TPtrC name(aName); |
|
117 //_LIT(KDotTxt, ".txt"); |
|
118 //_LIT(KDotLog, ".log"); |
|
119 //if (name.Right(KDotTxt().Length()) == KDotTxt) name.Set(name.Left(name.Length()-KDotTxt().Length())); |
|
120 //else if (name.Right(KDotLog().Length()) == KDotLog) name.Set(name.Left(name.Length()-KDotLog().Length())); |
|
121 TPckg<TUint32> enabledPkg(iEnabled); |
|
122 TInt result = SendReceive(ESetTag, TIpcArgs(&aDir, &aName, &enabledPkg)); |
|
123 if (result >= 0) |
|
124 { |
|
125 iSequence = result; |
|
126 return KErrNone; |
|
127 } |
|
128 else |
|
129 { |
|
130 return result; |
|
131 } |
|
132 } |
|
133 |
|
134 TInt DoSetTags8(const TDesC8& aDir, const TDesC8& aName) |
|
135 { |
|
136 //TPtrC8 name(aName); |
|
137 //_LIT8(KDotTxt, ".txt"); |
|
138 //_LIT8(KDotLog, ".log"); |
|
139 //if (name.Right(KDotTxt().Length()) == KDotTxt) name.Set(name.Left(name.Length()-KDotTxt().Length())); |
|
140 //else if (name.Right(KDotLog().Length()) == KDotLog) name.Set(name.Left(name.Length()-KDotLog().Length())); |
|
141 TPckg<TUint32> enabledPkg(iEnabled); |
|
142 TInt result = SendReceive(ESetTag8, TIpcArgs(&aDir, &aName, &enabledPkg)); |
|
143 if (result >= 0) |
|
144 { |
|
145 iSequence = result; |
|
146 return KErrNone; |
|
147 } |
|
148 else |
|
149 { |
|
150 return result; |
|
151 } |
|
152 } |
|
153 |
|
154 static void FloggerStaticClose() |
|
155 { |
|
156 GetTlsOrNull(); |
|
157 if (clogger) |
|
158 { |
|
159 clogger->Close(); |
|
160 if (!isHandle) |
|
161 { |
|
162 delete clogger; |
|
163 } |
|
164 Dll::SetTls(NULL); |
|
165 Dll::FreeTls(); |
|
166 } |
|
167 } |
|
168 |
|
169 void HexDump16(const TDesC16& aHeader, const TDesC8& aData) |
|
170 { |
|
171 SendReceive(2002, TIpcArgs(&aHeader, &aData, User::NTickCount(), RClogger::EAllEnabled)); |
|
172 } |
|
173 }; |
|
174 |
|
175 static TBool GetTls(RClogger*& aClogger, TBool aAutoConnect, const TAny* aTag, const TAny* aSubTag, TBool aWide, TInt* aError) |
|
176 { |
|
177 TAny* tls = Dll::Tls(); |
|
178 if ((TUint)tls & 1) |
|
179 { |
|
180 // Then it's a handle |
|
181 aClogger->SetHandle((TInt)((TUint)tls >> 1)); |
|
182 return ETrue; |
|
183 } |
|
184 else if (tls) |
|
185 { |
|
186 // Then it's a pointer |
|
187 aClogger = (RClogger*)tls; |
|
188 return EFalse; |
|
189 } |
|
190 else if (aAutoConnect) |
|
191 { |
|
192 //TInt err = aClogger->Connect(aTag ? *aTag : KNullDesC); |
|
193 TInt err; |
|
194 if (aWide) |
|
195 { |
|
196 err = FlogPtr(aClogger)->FloggerConnect(*(const TDesC*)aTag, *(const TDesC*)aSubTag); |
|
197 } |
|
198 else |
|
199 { |
|
200 err = FlogPtr(aClogger)->FloggerConnect(*(const TDesC8*)aTag, *(const TDesC8*)aSubTag); |
|
201 } |
|
202 |
|
203 if (err) |
|
204 { |
|
205 if (aError) *aError = err; |
|
206 aClogger = NULL; |
|
207 return ETrue; |
|
208 } |
|
209 if ((aClogger->Handle() & 0x80000000) != 0) |
|
210 { |
|
211 __ASSERT_DEBUG(EFalse, User::Panic(_L("HandleTooBig"), 0)); |
|
212 err = KErrOverflow; |
|
213 } |
|
214 |
|
215 if (!err) |
|
216 { |
|
217 err = Dll::SetTls((TAny*) ((aClogger->Handle() << 1) | 1)); |
|
218 } |
|
219 |
|
220 if (err) |
|
221 { |
|
222 aClogger->Close(); |
|
223 if (aError) *aError = err; |
|
224 aClogger = NULL; |
|
225 } |
|
226 return ETrue; |
|
227 } |
|
228 else |
|
229 { |
|
230 aClogger = NULL; |
|
231 return ETrue; |
|
232 } |
|
233 } |
|
234 |
|
235 EXPORT_C RFileLogger::RFileLogger() |
|
236 { |
|
237 Mem::FillZ(this, sizeof(RFileLogger)); |
|
238 } |
|
239 |
|
240 EXPORT_C RFileLogger::~RFileLogger() |
|
241 { |
|
242 } |
|
243 |
|
244 EXPORT_C TVersion RFileLogger::Version() const |
|
245 { |
|
246 return TVersion(1, 0, 20); |
|
247 } |
|
248 |
|
249 EXPORT_C TInt RFileLogger::Connect() |
|
250 { |
|
251 if (Connected()) |
|
252 { |
|
253 return KErrAlreadyExists; |
|
254 } |
|
255 |
|
256 #ifdef __CDU__ |
|
257 iLoggerBody = (RFileLoggerBody*)new RClogger(); |
|
258 if (!iLoggerBody) return KErrNoMemory; |
|
259 #else |
|
260 iPtr = new RClogger(); |
|
261 if (!iPtr) return KErrNoMemory; |
|
262 #endif |
|
263 |
|
264 TInt err = iClogger.Connect(); |
|
265 /* |
|
266 #ifdef _DEBUG |
|
267 if (!err) |
|
268 { |
|
269 // Don't cache client buffers in debug mode (so we will pass UDEB heap check macros) |
|
270 FlogPtr(iPtr)->Flags() &= ~RClogger::ECacheClientBuffers; |
|
271 } |
|
272 #endif |
|
273 */ |
|
274 |
|
275 #if !defined(__CDU__) && defined(_DEBUG) |
|
276 if (err == KErrNone) |
|
277 { |
|
278 SetHandle(iClogger.Handle()); // We do this so that when Close() is called, it cleans up the clogger interface. And we do that because we can't override Close(), and if the session doesn't get closed somehow, we'll fail CONE's handle check in debug builds |
|
279 } |
|
280 #endif |
|
281 if (!err) |
|
282 { |
|
283 iClogger.SetLogBehaviour(0 /*RClogger::EMonitorTagState*/); // Don't set EUseHeapBuffer because then we won't be thread-safe |
|
284 } |
|
285 else |
|
286 { |
|
287 DoClose(); |
|
288 } |
|
289 return err; |
|
290 } |
|
291 |
|
292 EXPORT_C void RFileLogger::SetDateAndTime(TBool /*aUseDate*/, TBool /*aUseTime*/) |
|
293 { |
|
294 // Has no real meaning in clogger |
|
295 } |
|
296 |
|
297 EXPORT_C void RFileLogger::CreateLog(const TDesC& aDir, const TDesC& aName, TFileLoggingMode /*aMode*/) |
|
298 { |
|
299 TInt err; |
|
300 if (Connected()) |
|
301 { |
|
302 err = FlogPtr(&iClogger)->DoSetTags(aDir, aName); |
|
303 } |
|
304 else |
|
305 { |
|
306 err = KErrNotFound; |
|
307 } |
|
308 #ifdef __CDU__ |
|
309 if (err) {} //Like CDU, ignore errors in legacy methods. This construction shuts up RVCT |
|
310 #else |
|
311 iLastError = err; |
|
312 #endif |
|
313 |
|
314 } |
|
315 |
|
316 EXPORT_C void RFileLogger::CloseLog() |
|
317 { |
|
318 // Has no meaning in clogger terms |
|
319 } |
|
320 |
|
321 EXPORT_C void RFileLogger::Write(const TDesC16& aText) |
|
322 { |
|
323 if (!Connected()) return; // Be compatible with CDU and flogger in terms of not crashing |
|
324 iClogger.Log(RClogger::EAllEnabled, KEsc, &aText); |
|
325 } |
|
326 |
|
327 EXPORT_C void RFileLogger::WriteFormat(TRefByValue<const TDesC16> aFmt,...) |
|
328 { |
|
329 if (!Connected()) return; // Be compatible with CDU and flogger in terms of not crashing |
|
330 VA_LIST args; |
|
331 VA_START(args, aFmt); |
|
332 iClogger.LogList(RClogger::EAllEnabled, aFmt, args); |
|
333 VA_END(args); |
|
334 } |
|
335 |
|
336 EXPORT_C void RFileLogger::WriteFormat(TRefByValue<const TDesC16> aFmt, VA_LIST& aList) |
|
337 { |
|
338 if (!Connected()) return; // Be compatible with CDU and flogger in terms of not crashing |
|
339 iClogger.LogList(RClogger::EAllEnabled, aFmt, aList); |
|
340 } |
|
341 |
|
342 EXPORT_C void RFileLogger::Write(const TDesC8& aText) |
|
343 { |
|
344 if (!Connected()) return; // Be compatible with CDU and flogger in terms of not crashing |
|
345 iClogger.Log(RClogger::EAllEnabled, KEsc8, &aText); |
|
346 } |
|
347 |
|
348 EXPORT_C void RFileLogger::WriteFormat(TRefByValue<const TDesC8> aFmt,...) |
|
349 { |
|
350 if (!Connected()) return; // Be compatible with CDU and flogger in terms of not crashing |
|
351 VA_LIST args; |
|
352 VA_START(args, aFmt); |
|
353 iClogger.LogList(RClogger::EAllEnabled, aFmt, args); |
|
354 VA_END(args); |
|
355 } |
|
356 |
|
357 EXPORT_C void RFileLogger::WriteFormat(TRefByValue<const TDesC8> aFmt, VA_LIST& aList) |
|
358 { |
|
359 if (!Connected()) return; // Be compatible with CDU and flogger in terms of not crashing |
|
360 iClogger.LogList(RClogger::EAllEnabled, aFmt, aList); |
|
361 } |
|
362 |
|
363 EXPORT_C void RFileLogger::HexDump(const TText* aHeader, const TText* /*aMargin*/, const TUint8* aPtr, TInt aLen) |
|
364 { |
|
365 if (!Connected()) return; // Be compatible with CDU and flogger in terms of not crashing |
|
366 TPtrC16 header; |
|
367 if (aHeader) |
|
368 { |
|
369 header.Set(aHeader, User::StringLength(aHeader)); |
|
370 } |
|
371 const TPtrC8 data(aPtr, aLen); |
|
372 FlogPtr(iPtr)->HexDump16(header, data); |
|
373 } |
|
374 |
|
375 EXPORT_C TInt RFileLogger::LastError() const |
|
376 { |
|
377 #ifdef __CDU__ |
|
378 return KErrNone; |
|
379 #else |
|
380 return iLastError; |
|
381 #endif |
|
382 } |
|
383 |
|
384 EXPORT_C TBool RFileLogger::LogValid() const |
|
385 { |
|
386 return ETrue; |
|
387 } |
|
388 |
|
389 // The static functions |
|
390 EXPORT_C void RFileLogger::Write(const TDesC& aDir, const TDesC& aName, TFileLoggingMode /*aMode*/, const TDesC16& aText) |
|
391 { |
|
392 CheckConnected(aDir, aName); |
|
393 clogger->Log(KEsc, &aText); |
|
394 |
|
395 STATICCLOSE(); |
|
396 } |
|
397 |
|
398 EXPORT_C void RFileLogger::WriteFormat(const TDesC& aDir, const TDesC& aName, TFileLoggingMode /*aMode*/, TRefByValue<const TDesC16> aFmt,...) |
|
399 { |
|
400 CheckConnected(aDir, aName); |
|
401 VA_LIST args; |
|
402 VA_START(args, aFmt); |
|
403 clogger->LogList(aFmt, args); |
|
404 VA_END(args); |
|
405 |
|
406 STATICCLOSE(); |
|
407 } |
|
408 |
|
409 EXPORT_C void RFileLogger::WriteFormat(const TDesC& aDir, const TDesC& aName, TFileLoggingMode /*aMode*/, TRefByValue<const TDesC16> aFmt, VA_LIST& aList) |
|
410 { |
|
411 CheckConnected(aDir, aName); |
|
412 clogger->LogList(aFmt, aList); |
|
413 |
|
414 STATICCLOSE(); |
|
415 } |
|
416 |
|
417 EXPORT_C void RFileLogger::Write(const TDesC& aDir, const TDesC& aName, TFileLoggingMode /*aMode*/, const TDesC8& aText) |
|
418 { |
|
419 CheckConnected(aDir, aName); |
|
420 clogger->Log(KEsc8, &aText); |
|
421 |
|
422 STATICCLOSE(); |
|
423 } |
|
424 |
|
425 EXPORT_C void RFileLogger::WriteFormat(const TDesC& aDir, const TDesC& aName, TFileLoggingMode /*aMode*/, TRefByValue<const TDesC8> aFmt,...) |
|
426 { |
|
427 CheckConnected(aDir, aName); |
|
428 VA_LIST args; |
|
429 VA_START(args, aFmt); |
|
430 clogger->LogList(aFmt, args); |
|
431 VA_END(args); |
|
432 |
|
433 STATICCLOSE(); |
|
434 } |
|
435 |
|
436 EXPORT_C void RFileLogger::WriteFormat(const TDesC& aDir, const TDesC& aName, TFileLoggingMode /*aMode*/, TRefByValue<const TDesC8> aFmt, VA_LIST& aList) |
|
437 { |
|
438 CheckConnected(aDir, aName); |
|
439 clogger->LogList(aFmt, aList); |
|
440 |
|
441 STATICCLOSE(); |
|
442 } |
|
443 |
|
444 EXPORT_C void RFileLogger::HexDump(const TDesC& aDir, const TDesC& aName, TFileLoggingMode /*aMode*/, const TText* aHeader, const TText* /*aMargin*/, const TUint8* aPtr, TInt aLen) |
|
445 { |
|
446 CheckConnected(aDir, aName); |
|
447 const TPtrC16 header(aHeader); |
|
448 const TPtrC8 data(aPtr, aLen); |
|
449 |
|
450 FlogPtr(clogger)->HexDump16(header, data); |
|
451 } |
|
452 |
|
453 // Boring stuff |
|
454 |
|
455 #ifndef __CDU__ |
|
456 |
|
457 TLogFormatter::TLogFormatter() {} |
|
458 TLogFile::TLogFile() {} |
|
459 void TLogFormatter8Overflow::Overflow(TDes8& /*aDes*/) {} |
|
460 void TLogFormatter16Overflow::Overflow(TDes16& /*aDes*/) {} |
|
461 EXPORT_C TInt FLogger::Run(FLogger::TSignal& /*aSignal*/) |
|
462 { |
|
463 return KErrNotSupported; |
|
464 } |
|
465 |
|
466 #endif |
|
467 |
|
468 #ifdef __CDU__ |
|
469 |
|
470 // Some functions new in CDU |
|
471 |
|
472 EXPORT_C void RFileLogger::Close() |
|
473 { |
|
474 DoClose(); |
|
475 } |
|
476 |
|
477 EXPORT_C void ClientRunStubOrdinal1() |
|
478 { |
|
479 } |
|
480 |
|
481 EXPORT_C TInt RFileLogger::ClearLog() |
|
482 { |
|
483 if (!Connected()) return KErrNone; // Be compatible with CDU and flogger in terms of not crashing |
|
484 return iClogger.Rotate(); // Close enough |
|
485 } |
|
486 |
|
487 EXPORT_C TInt RFileLogger::SetLogTags(const TDesC8& aSubsystem, const TDesC8& aComponent) |
|
488 { |
|
489 return FlogPtr(iPtr)->DoSetTags8(aSubsystem, aComponent); |
|
490 } |
|
491 |
|
492 EXPORT_C void RFileLogger::__DbgShutDownServer() |
|
493 { |
|
494 // Why bother supporting this? |
|
495 } |
|
496 |
|
497 EXPORT_C void RFileLogger::__DbgSetHeapFailure(TInt /*aFailAfter*/) |
|
498 { |
|
499 // See above... |
|
500 } |
|
501 |
|
502 EXPORT_C void RFileLogger::WriteBinary(const TDesC8& aData) |
|
503 { |
|
504 if (!Connected()) return; // Be compatible with CDU and flogger in terms of not crashing |
|
505 iClogger.Log(KEsc8, &aData); |
|
506 } |
|
507 |
|
508 EXPORT_C void RFileLogger::HexDump(const TDesC8& aSubsystem, const TDesC8& aComponent, const TDesC8& aData, const TDesC8& aHeader) |
|
509 { |
|
510 CheckConnected8(aSubsystem, aComponent); |
|
511 |
|
512 clogger->HexDump(aHeader, aData); |
|
513 } |
|
514 |
|
515 EXPORT_C void RFileLogger::HexDump(const TDesC8& aData, const TDesC8& aHeader) |
|
516 { |
|
517 if (!Connected()) return; // Be compatible with CDU and flogger in terms of not crashing |
|
518 iClogger.HexDump(aHeader, aData); |
|
519 } |
|
520 |
|
521 EXPORT_C TInt RFileLogger::Handle() const |
|
522 { |
|
523 return iClogger.Handle(); |
|
524 } |
|
525 |
|
526 EXPORT_C TInt RFileLogger::Share() |
|
527 { |
|
528 return iClogger.ShareAuto(); |
|
529 } |
|
530 |
|
531 EXPORT_C void RFileLogger::Write(const TDesC8& aSubsystem, const TDesC8& aComponent, const TDesC8& aText) |
|
532 { |
|
533 CheckConnected8(aSubsystem, aComponent); |
|
534 clogger->Log(KEsc8, &aText); |
|
535 } |
|
536 |
|
537 EXPORT_C void RFileLogger::Write(const TDesC8& aSubsystem, const TDesC8& aComponent, const TDesC& aText) |
|
538 { |
|
539 CheckConnected8(aSubsystem, aComponent); |
|
540 clogger->Log(KEsc, &aText); |
|
541 } |
|
542 |
|
543 EXPORT_C void RFileLogger::WriteFormat(const TDesC8& aSubsystem, const TDesC8& aComponent, TRefByValue<const TDesC16> aFmt, ...) |
|
544 { |
|
545 CheckConnected8(aSubsystem, aComponent); |
|
546 VA_LIST args; |
|
547 VA_START(args, aFmt); |
|
548 clogger->LogList(aFmt, args); |
|
549 VA_END(args); |
|
550 |
|
551 STATICCLOSE(); |
|
552 } |
|
553 |
|
554 EXPORT_C void RFileLogger::WriteFormat(const TDesC8& aSubsystem, const TDesC8& aComponent, TRefByValue<const TDesC8> aFmt, ...) |
|
555 { |
|
556 CheckConnected8(aSubsystem, aComponent); |
|
557 VA_LIST args; |
|
558 VA_START(args, aFmt); |
|
559 clogger->LogList(aFmt, args); |
|
560 VA_END(args); |
|
561 |
|
562 STATICCLOSE(); |
|
563 } |
|
564 |
|
565 EXPORT_C void RFileLogger::WriteFormat(const TDesC8& aSubsystem, const TDesC8& aComponent, const TRefByValue<const TDesC8> aFmt, VA_LIST& aList) |
|
566 { |
|
567 CheckConnected8(aSubsystem, aComponent); |
|
568 clogger->LogList(aFmt, aList); |
|
569 |
|
570 STATICCLOSE(); |
|
571 } |
|
572 |
|
573 EXPORT_C void RFileLogger::WriteFormat(const TDesC8& aSubsystem, const TDesC8& aComponent, const TRefByValue<const TDesC16> aFmt, VA_LIST& aList) |
|
574 { |
|
575 CheckConnected8(aSubsystem, aComponent); |
|
576 clogger->LogList(aFmt, aList); |
|
577 |
|
578 STATICCLOSE(); |
|
579 } |
|
580 |
|
581 #endif |