1 /*************************************************************************
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * Copyright 2000, 2010 Oracle and/or its affiliates.
5  *
6  * OpenOffice.org - a multi-platform office productivity suite
7  *
8  * This file is part of OpenOffice.org.
9  *
10  * OpenOffice.org is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License version 3
12  * only, as published by the Free Software Foundation.
13  *
14  * OpenOffice.org is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License version 3 for more details
18  * (a copy is included in the LICENSE file that accompanied this code).
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * version 3 along with OpenOffice.org.  If not, see
22  * <http://www.openoffice.org/license.html>
23  * for a copy of the LGPLv3 License.
24  *
25 ***********************************************************************/
26 
27 // MARKER(update_precomp.py): autogen include statement, do not remove
28 #include "precompiled_comphelper.hxx"
29 
30 #include <comphelper/uieventslogger.hxx>
31 #include <boost/shared_ptr.hpp>
32 #include <com/sun/star/frame/XDesktop.hpp>
33 #include <com/sun/star/frame/XTerminateListener.hpp>
34 #include <com/sun/star/lang/XEventListener.hpp>
35 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
36 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
37 #include <com/sun/star/logging/LogLevel.hpp>
38 #include <com/sun/star/logging/XCsvLogFormatter.hpp>
39 #include <com/sun/star/logging/XLogHandler.hpp>
40 #include <com/sun/star/logging/XLogger.hpp>
41 #include <com/sun/star/logging/XLoggerPool.hpp>
42 #include <com/sun/star/oooimprovement/XCoreController.hpp>
43 #include <com/sun/star/uno/Sequence.hxx>
44 #include <com/sun/star/util/XStringSubstitution.hpp>
45 #include <comphelper/configurationhelper.hxx>
46 #include <comphelper/processfactory.hxx>
47 #include <map>
48 #include <osl/file.hxx>
49 #include <osl/mutex.hxx>
50 #include <osl/time.h>
51 #include <rtl/ustrbuf.hxx>
52 
53 
54 using namespace com::sun::star::beans;
55 using namespace com::sun::star::frame;
56 using namespace com::sun::star::lang;
57 using namespace com::sun::star::logging;
58 using namespace com::sun::star::oooimprovement;
59 using namespace com::sun::star::uno;
60 using namespace com::sun::star::util;
61 using namespace cppu;
62 using namespace osl;
63 using namespace rtl;
64 using namespace std;
65 
66 
67 namespace
68 {
69     static void lcl_SetupOriginAppAbbr(map<OUString, OUString>& abbrs)
70     {
71         abbrs[OUString::createFromAscii("com.sun.star.text.TextDocument")] = OUString::createFromAscii("W"); // Writer
72         abbrs[OUString::createFromAscii("com.sun.star.sheet.SpreadsheetDocument")] = OUString::createFromAscii("C"); // Calc
73         abbrs[OUString::createFromAscii("com.sun.star.presentation.PresentationDocument")] = OUString::createFromAscii("I"); // Impress
74         abbrs[OUString::createFromAscii("com.sun.star.drawing.DrawingDocument")] = OUString::createFromAscii("D"); // Draw
75     };
76 
77     static void lcl_SetupOriginWidgetAbbr(map<OUString,OUString>& abbrs)
78     {
79         abbrs[OUString::createFromAscii("ButtonToolbarController")] = OUString::createFromAscii("0");
80         abbrs[OUString::createFromAscii("ComplexToolbarController")] = OUString::createFromAscii("1");
81         abbrs[OUString::createFromAscii("ControlMenuController")] = OUString::createFromAscii("2");
82         abbrs[OUString::createFromAscii("FontMenuController")] = OUString::createFromAscii("3");
83         abbrs[OUString::createFromAscii("FontSizeMenuController")] = OUString::createFromAscii("4");
84         abbrs[OUString::createFromAscii("FooterMenuController")] = OUString::createFromAscii("5");
85         abbrs[OUString::createFromAscii("GenericToolbarController")] = OUString::createFromAscii("6");
86         abbrs[OUString::createFromAscii("HeaderMenuController")] = OUString::createFromAscii("7");
87         abbrs[OUString::createFromAscii("LanguageSelectionMenuController")] = OUString::createFromAscii("8");
88         abbrs[OUString::createFromAscii("LangSelectionStatusbarController")] = OUString::createFromAscii("9");
89         abbrs[OUString::createFromAscii("MacrosMenuController")] = OUString::createFromAscii("10");
90         abbrs[OUString::createFromAscii("MenuBarManager")] = OUString::createFromAscii("11");
91         abbrs[OUString::createFromAscii("NewMenuController")] = OUString::createFromAscii("12");
92         abbrs[OUString::createFromAscii("ObjectMenuController")] = OUString::createFromAscii("13");
93         abbrs[OUString::createFromAscii("RecentFilesMenuController")] = OUString::createFromAscii("14");
94         abbrs[OUString::createFromAscii("ToolbarsMenuController")] = OUString::createFromAscii("15");
95         abbrs[OUString::createFromAscii("SfxToolBoxControl")] = OUString::createFromAscii("16");
96         abbrs[OUString::createFromAscii("SfxAsyncExec")] = OUString::createFromAscii("17");
97         abbrs[OUString::createFromAscii("AcceleratorExecute")] = OUString::createFromAscii("18");
98     };
99 }
100 
101 namespace comphelper
102 {
103     // declaration of implementation
104     class UiEventsLogger_Impl;
105     class UiEventsLogger_Impl : public UiEventsLogger
106     {
107         private:
108             //typedefs and friends
109             friend class UiEventsLogger;
110             typedef UiEventsLogger_Impl* ptr;
111 
112             // instance methods and data
113             UiEventsLogger_Impl();
114             void initializeLogger();
115             void logDispatch(const ::com::sun::star::util::URL& url,
116                 const Sequence<PropertyValue>& args);
117             void logRotated();
118             void logVcl(const ::rtl::OUString& parent_id,
119                 sal_Int32 window_type,
120                 const ::rtl::OUString& id,
121                 const ::rtl::OUString& method,
122                 const ::rtl::OUString& param);
123             void rotate();
124             void hotRotate();
125             void prepareLogHandler();
126             void checkIdleTimeout();
127             OUString getCurrentPath();
128             OUString getRotatedPath();
129             void disposing();
130 
131             bool m_Active;
132             TimeValue m_LastLogEventTime;
133             const OUString m_LogPath;
134             const TimeValue m_IdleTimeout;
135             sal_Int32 m_SessionLogEventCount;
136             Reference<XLogger> m_Logger;
137             Reference<XLogHandler> m_LogHandler;
138             Reference<XCsvLogFormatter> m_Formatter;
139             map<OUString, OUString> m_OriginAppAbbr;
140             map<OUString, OUString> m_OriginWidgetAbbr;
141 
142 
143             // static methods and data
144             static ptr getInstance();
145             static void prepareMutex();
146             static bool shouldActivate();
147             static bool getEnabledFromCoreController();
148             static bool getEnabledFromCfg();
149             static TimeValue getIdleTimeoutFromCfg();
150             static OUString getLogPathFromCfg();
151             static sal_Int32 findIdx(const Sequence<PropertyValue>& args, const OUString& key);
152 
153             static ptr instance;
154             static Mutex * singleton_mutex;
155             static const sal_Int32 COLUMNS;
156             static const OUString CFG_ENABLED;
157             static const OUString CFG_IDLETIMEOUT;
158             static const OUString CFG_LOGGING;
159             static const OUString CFG_LOGPATH;
160             static const OUString CFG_OOOIMPROVEMENT;
161             static const OUString ETYPE_DISPATCH;
162             static const OUString ETYPE_ROTATED;
163             static const OUString ETYPE_VCL;
164             static const OUString CSSL_CSVFORMATTER;
165             static const OUString CSSL_FILEHANDLER;
166             static const OUString CSSL_LOGGERPOOL;
167             static const OUString CSSO_CORECONTROLLER;
168             static const OUString CSST_JOBEXECUTOR;
169             static const OUString CSSU_PATHSUB;
170             static const OUString LOGGERNAME;
171             static const OUString LOGORIGINAPP;
172             static const OUString LOGORIGINWIDGET;
173             static const OUString UNKNOWN_ORIGIN;
174             static const OUString FN_CURRENTLOG;
175             static const OUString FN_ROTATEDLOG;
176             static const OUString LOGROTATE_EVENTNAME;
177             static const OUString URL_UNO;
178             static const OUString URL_SPECIAL;
179             static const OUString URL_FILE;
180     };
181 }
182 
183 namespace comphelper
184 {
185     // consts
186     const sal_Int32 UiEventsLogger_Impl::COLUMNS = 9;
187     const OUString UiEventsLogger_Impl::CFG_ENABLED = OUString::createFromAscii("EnablingAllowed");
188     const OUString UiEventsLogger_Impl::CFG_IDLETIMEOUT = OUString::createFromAscii("IdleTimeout");
189     const OUString UiEventsLogger_Impl::CFG_LOGGING = OUString::createFromAscii("/org.openoffice.Office.Logging");
190     const OUString UiEventsLogger_Impl::CFG_LOGPATH = OUString::createFromAscii("LogPath");
191     const OUString UiEventsLogger_Impl::CFG_OOOIMPROVEMENT = OUString::createFromAscii("OOoImprovement");
192 
193     const OUString UiEventsLogger_Impl::CSSL_CSVFORMATTER = OUString::createFromAscii("com.sun.star.logging.CsvFormatter");
194     const OUString UiEventsLogger_Impl::CSSL_FILEHANDLER = OUString::createFromAscii("com.sun.star.logging.FileHandler");
195     const OUString UiEventsLogger_Impl::CSSL_LOGGERPOOL = OUString::createFromAscii("com.sun.star.logging.LoggerPool");
196     const OUString UiEventsLogger_Impl::CSSO_CORECONTROLLER = OUString::createFromAscii("com.sun.star.oooimprovement.CoreController");
197     const OUString UiEventsLogger_Impl::CSSU_PATHSUB = OUString::createFromAscii("com.sun.star.util.PathSubstitution");
198 
199     const OUString UiEventsLogger_Impl::ETYPE_DISPATCH = OUString::createFromAscii("dispatch");
200     const OUString UiEventsLogger_Impl::ETYPE_ROTATED = OUString::createFromAscii("rotated");
201     const OUString UiEventsLogger_Impl::ETYPE_VCL = OUString::createFromAscii("vcl");
202 
203     const OUString UiEventsLogger_Impl::LOGGERNAME = OUString::createFromAscii("org.openoffice.oooimprovement.Core.UiEventsLogger");
204     const OUString UiEventsLogger_Impl::LOGORIGINWIDGET = OUString::createFromAscii("comphelper.UiEventsLogger.LogOriginWidget");
205     const OUString UiEventsLogger_Impl::LOGORIGINAPP = OUString::createFromAscii("comphelper.UiEventsLogger.LogOriginApp");
206 
207     const OUString UiEventsLogger_Impl::UNKNOWN_ORIGIN = OUString::createFromAscii("unknown origin");
208     const OUString UiEventsLogger_Impl::FN_CURRENTLOG = OUString::createFromAscii("Current");
209     const OUString UiEventsLogger_Impl::FN_ROTATEDLOG = OUString::createFromAscii("OOoImprove");
210     const OUString UiEventsLogger_Impl::LOGROTATE_EVENTNAME = OUString::createFromAscii("onOOoImprovementLogRotated");
211 
212     const OUString UiEventsLogger_Impl::URL_UNO = OUString::createFromAscii(".uno:");
213     const OUString UiEventsLogger_Impl::URL_SPECIAL = OUString::createFromAscii(".special:");
214     const OUString UiEventsLogger_Impl::URL_FILE = OUString::createFromAscii("file:");
215 
216 
217     // public UiEventsLogger interface
218     sal_Bool UiEventsLogger::isEnabled()
219     {
220         if ( UiEventsLogger_Impl::getEnabledFromCfg() )
221         {
222             try {
223                 UiEventsLogger_Impl::prepareMutex();
224                 Guard<Mutex> singleton_guard(UiEventsLogger_Impl::singleton_mutex);
225                 return UiEventsLogger_Impl::getInstance()->m_Active;
226             } catch(...) { return false; } // never throws
227         } // if ( )
228         return sal_False;
229     }
230 
231     sal_Int32 UiEventsLogger::getSessionLogEventCount()
232     {
233         try {
234             UiEventsLogger_Impl::prepareMutex();
235             Guard<Mutex> singleton_guard(UiEventsLogger_Impl::singleton_mutex);
236             return UiEventsLogger_Impl::getInstance()->m_SessionLogEventCount;
237         } catch(...) { return 0; } // never throws
238     }
239 
240     void UiEventsLogger::appendDispatchOrigin(
241         Sequence<PropertyValue>& args,
242         const OUString& originapp,
243         const OUString& originwidget)
244     {
245         sal_Int32 old_length = args.getLength();
246         args.realloc(old_length+2);
247         args[old_length].Name = UiEventsLogger_Impl::LOGORIGINAPP;
248         args[old_length].Value = static_cast<Any>(originapp);
249         args[old_length+1].Name = UiEventsLogger_Impl::LOGORIGINWIDGET;
250         args[old_length+1].Value = static_cast<Any>(originwidget);
251     }
252 
253     Sequence<PropertyValue> UiEventsLogger::purgeDispatchOrigin(
254         const Sequence<PropertyValue>& args)
255     {
256         Sequence<PropertyValue> result(args.getLength());
257         sal_Int32 target_idx=0;
258         for(sal_Int32 source_idx=0; source_idx<args.getLength(); source_idx++)
259             if(args[source_idx].Name != UiEventsLogger_Impl::LOGORIGINAPP
260                 && args[source_idx].Name != UiEventsLogger_Impl::LOGORIGINWIDGET)
261                 result[target_idx++] = args[source_idx];
262         result.realloc(target_idx);
263         return result;
264     }
265 
266     void UiEventsLogger::logDispatch(
267         const URL& url,
268         const Sequence<PropertyValue>& args)
269     {
270         try {
271             UiEventsLogger_Impl::prepareMutex();
272             Guard<Mutex> singleton_guard(UiEventsLogger_Impl::singleton_mutex);
273             UiEventsLogger_Impl::getInstance()->logDispatch(url, args);
274         } catch(...) { } // never throws
275     }
276 
277     void UiEventsLogger::logVcl(
278         const OUString& parent_id,
279         sal_Int32 window_type,
280         const OUString& id,
281         const OUString& method,
282         const OUString& param)
283     {
284         try {
285             UiEventsLogger_Impl::prepareMutex();
286             Guard<Mutex> singleton_guard(UiEventsLogger_Impl::singleton_mutex);
287             UiEventsLogger_Impl::getInstance()->logVcl(parent_id, window_type, id, method, param);
288         } catch(...) { } // never throws
289     }
290 
291     void UiEventsLogger::logVcl(
292         const OUString& parent_id,
293         sal_Int32 window_type,
294         const OUString& id,
295         const OUString& method,
296         sal_Int32 param)
297     {
298         OUStringBuffer buf;
299         UiEventsLogger::logVcl(parent_id, window_type, id, method, buf.append(param).makeStringAndClear());
300     }
301 
302     void UiEventsLogger::logVcl(
303         const OUString& parent_id,
304         sal_Int32 window_type,
305         const OUString& id,
306         const OUString& method)
307     {
308         OUString empty;
309         UiEventsLogger::logVcl(parent_id, window_type, id, method, empty);
310     }
311 
312     void UiEventsLogger::disposing()
313     {
314         // we dont want to create an instance just to dispose it
315         UiEventsLogger_Impl::prepareMutex();
316         Guard<Mutex> singleton_guard(UiEventsLogger_Impl::singleton_mutex);
317         if(UiEventsLogger_Impl::instance!=UiEventsLogger_Impl::ptr())
318             UiEventsLogger_Impl::getInstance()->disposing();
319     }
320 
321     void UiEventsLogger::reinit()
322     {
323         UiEventsLogger_Impl::prepareMutex();
324         Guard<Mutex> singleton_guard(UiEventsLogger_Impl::singleton_mutex);
325         if(UiEventsLogger_Impl::instance)
326         {
327             UiEventsLogger_Impl::instance->disposing();
328             delete UiEventsLogger_Impl::instance;
329             UiEventsLogger_Impl::instance = NULL;
330         }
331     }
332 
333     // private UiEventsLogger_Impl methods
334     UiEventsLogger_Impl::UiEventsLogger_Impl()
335         : m_Active(UiEventsLogger_Impl::shouldActivate())
336         , m_LogPath(UiEventsLogger_Impl::getLogPathFromCfg())
337         , m_IdleTimeout(UiEventsLogger_Impl::getIdleTimeoutFromCfg())
338         , m_SessionLogEventCount(0)
339     {
340         lcl_SetupOriginAppAbbr(m_OriginAppAbbr);
341         lcl_SetupOriginWidgetAbbr(m_OriginWidgetAbbr);
342         m_LastLogEventTime.Seconds = m_LastLogEventTime.Nanosec = 0;
343         if(m_Active) rotate();
344         if(m_Active) initializeLogger();
345     }
346 
347     void UiEventsLogger_Impl::logDispatch(
348         const URL& url,
349         const Sequence<PropertyValue>& args)
350     {
351         if(!m_Active) return;
352         if(!url.Complete.match(URL_UNO)
353             && !url.Complete.match(URL_FILE)
354             && !url.Complete.match(URL_SPECIAL))
355         {
356             return;
357         }
358         checkIdleTimeout();
359 
360         Sequence<OUString> logdata = Sequence<OUString>(COLUMNS);
361         logdata[0] = ETYPE_DISPATCH;
362         sal_Int32 originapp_idx = findIdx(args, LOGORIGINAPP);
363         if(originapp_idx!=-1)
364         {
365             OUString app;
366             args[originapp_idx].Value >>= app;
367             map<OUString, OUString>::iterator abbr_it = m_OriginAppAbbr.find(app);
368             if(abbr_it != m_OriginAppAbbr.end())
369                 app = abbr_it->second;
370             logdata[1] = app;
371         }
372         else
373             logdata[1] = UNKNOWN_ORIGIN;
374         sal_Int32 originwidget_idx = findIdx(args, LOGORIGINWIDGET);
375         if(originwidget_idx!=-1)
376         {
377             OUString widget;
378             args[originwidget_idx].Value >>= widget;
379             map<OUString, OUString>::iterator widget_it = m_OriginWidgetAbbr.find(widget);
380             if(widget_it != m_OriginWidgetAbbr.end())
381                 widget = widget_it->second;
382             logdata[2] = widget;
383         }
384         else
385             logdata[2] = UNKNOWN_ORIGIN;
386         if(url.Complete.match(URL_FILE))
387             logdata[3] = URL_FILE;
388         else
389             logdata[3] = url.Main;
390         OSL_TRACE("UiEventsLogger Logging: %s,%s,%s,%s,%s,%s,%s,%s",
391             OUStringToOString(logdata[0],RTL_TEXTENCODING_UTF8).getStr(),
392             OUStringToOString(logdata[1],RTL_TEXTENCODING_UTF8).getStr(),
393             OUStringToOString(logdata[2],RTL_TEXTENCODING_UTF8).getStr(),
394             OUStringToOString(logdata[3],RTL_TEXTENCODING_UTF8).getStr(),
395             OUStringToOString(logdata[4],RTL_TEXTENCODING_UTF8).getStr(),
396             OUStringToOString(logdata[5],RTL_TEXTENCODING_UTF8).getStr(),
397             OUStringToOString(logdata[6],RTL_TEXTENCODING_UTF8).getStr(),
398             OUStringToOString(logdata[7],RTL_TEXTENCODING_UTF8).getStr(),
399             OUStringToOString(logdata[8],RTL_TEXTENCODING_UTF8).getStr());
400         m_Logger->log(LogLevel::INFO, m_Formatter->formatMultiColumn(logdata));
401         m_SessionLogEventCount++;
402     }
403 
404     void UiEventsLogger_Impl::logRotated()
405     {
406         Sequence<OUString> logdata = Sequence<OUString>(COLUMNS);
407         logdata[0] = ETYPE_ROTATED;
408         OSL_TRACE("UiEventsLogger Logging: %s,%s,%s,%s,%s,%s,%s,%s",
409             OUStringToOString(logdata[0],RTL_TEXTENCODING_UTF8).getStr(),
410             OUStringToOString(logdata[1],RTL_TEXTENCODING_UTF8).getStr(),
411             OUStringToOString(logdata[2],RTL_TEXTENCODING_UTF8).getStr(),
412             OUStringToOString(logdata[3],RTL_TEXTENCODING_UTF8).getStr(),
413             OUStringToOString(logdata[4],RTL_TEXTENCODING_UTF8).getStr(),
414             OUStringToOString(logdata[5],RTL_TEXTENCODING_UTF8).getStr(),
415             OUStringToOString(logdata[6],RTL_TEXTENCODING_UTF8).getStr(),
416             OUStringToOString(logdata[7],RTL_TEXTENCODING_UTF8).getStr(),
417             OUStringToOString(logdata[8],RTL_TEXTENCODING_UTF8).getStr());
418         m_Logger->log(LogLevel::INFO, m_Formatter->formatMultiColumn(logdata));
419     }
420 
421     void UiEventsLogger_Impl::logVcl(
422         const OUString& parent_id,
423         sal_Int32 window_type,
424         const OUString& id,
425         const OUString& method,
426         const OUString& param)
427     {
428         if(!m_Active) return;
429         checkIdleTimeout();
430 
431         OUStringBuffer buf;
432         Sequence<OUString> logdata = Sequence<OUString>(COLUMNS);
433         logdata[0] = ETYPE_VCL;
434         logdata[4] = parent_id;
435         logdata[5] = buf.append(window_type).makeStringAndClear();
436         logdata[6] = id;
437         logdata[7] = method;
438         logdata[8] = param;
439         OSL_TRACE("UiEventsLogger Logging: %s,%s,%s,%s,%s,%s,%s,%s",
440             OUStringToOString(logdata[0],RTL_TEXTENCODING_UTF8).getStr(),
441             OUStringToOString(logdata[1],RTL_TEXTENCODING_UTF8).getStr(),
442             OUStringToOString(logdata[2],RTL_TEXTENCODING_UTF8).getStr(),
443             OUStringToOString(logdata[3],RTL_TEXTENCODING_UTF8).getStr(),
444             OUStringToOString(logdata[4],RTL_TEXTENCODING_UTF8).getStr(),
445             OUStringToOString(logdata[5],RTL_TEXTENCODING_UTF8).getStr(),
446             OUStringToOString(logdata[6],RTL_TEXTENCODING_UTF8).getStr(),
447             OUStringToOString(logdata[7],RTL_TEXTENCODING_UTF8).getStr(),
448             OUStringToOString(logdata[8],RTL_TEXTENCODING_UTF8).getStr());
449         m_Logger->log(LogLevel::INFO, m_Formatter->formatMultiColumn(logdata));
450         m_SessionLogEventCount++;
451     }
452 
453     void UiEventsLogger_Impl::rotate()
454     {
455         FileBase::RC result = File::move(getCurrentPath(), getRotatedPath());
456         if(result!=FileBase::E_None && result!=FileBase::E_NOENT)
457             m_Active = false;
458     }
459 
460     void UiEventsLogger_Impl::hotRotate()
461     {
462         logRotated();
463         m_Logger->removeLogHandler(m_LogHandler);
464         m_LogHandler = NULL;
465         rotate();
466         prepareLogHandler();
467         if(m_Formatter.is() && m_LogHandler.is() && m_Logger.is())
468         {
469             m_LogHandler->setFormatter(Reference<XLogFormatter>(m_Formatter, UNO_QUERY));
470             m_LogHandler->setLevel(LogLevel::ALL);
471             m_Logger->addLogHandler(m_LogHandler);
472         }
473         else
474             m_Active = false;
475     }
476 
477     void UiEventsLogger_Impl::prepareLogHandler()
478     {
479         Reference<XMultiServiceFactory> sm = getProcessServiceFactory();
480 
481         Sequence<Any> init_args = Sequence<Any>(1);
482         init_args[0] = static_cast<Any>(getCurrentPath());
483         Reference< XInterface > temp =
484             sm->createInstanceWithArguments(CSSL_FILEHANDLER, init_args);
485         m_LogHandler = Reference<XLogHandler>(temp, UNO_QUERY);
486     }
487 
488     void UiEventsLogger_Impl::checkIdleTimeout()
489     {
490         TimeValue now;
491         osl_getSystemTime(&now);
492         if(now.Seconds - m_LastLogEventTime.Seconds > m_IdleTimeout.Seconds && m_SessionLogEventCount>0)
493             hotRotate();
494         m_LastLogEventTime = now;
495     }
496 
497     OUString UiEventsLogger_Impl::getCurrentPath()
498     {
499         OUStringBuffer current_path(m_LogPath);
500         current_path.appendAscii("/");
501         current_path.append(FN_CURRENTLOG);
502         current_path.appendAscii(".csv");
503         return current_path.makeStringAndClear();
504     }
505 
506     OUString UiEventsLogger_Impl::getRotatedPath()
507     {
508         OUStringBuffer rotated_path(m_LogPath);
509         rotated_path.appendAscii("/");
510         rotated_path.append(FN_ROTATEDLOG);
511         rotated_path.appendAscii("-");
512         {
513             // ISO 8601
514             char tsrotated_pathfer[20];
515             oslDateTime now;
516             TimeValue now_tv;
517             osl_getSystemTime(&now_tv);
518             osl_getDateTimeFromTimeValue(&now_tv, &now);
519             const size_t rotated_pathfer_size = sizeof(tsrotated_pathfer);
520             snprintf(tsrotated_pathfer, rotated_pathfer_size, "%04i-%02i-%02iT%02i_%02i_%02i",
521                 now.Year,
522                 now.Month,
523                 now.Day,
524                 now.Hours,
525                 now.Minutes,
526                 now.Seconds);
527             rotated_path.appendAscii(tsrotated_pathfer);
528             rotated_path.appendAscii(".csv");
529         }
530         return rotated_path.makeStringAndClear();
531     }
532 
533     void UiEventsLogger_Impl::initializeLogger()
534     {
535         Reference<XMultiServiceFactory> sm = getProcessServiceFactory();
536 
537         // getting the Core Uno proxy object
538         // It will call disposing and make sure we clear all our references
539         {
540             Reference<XTerminateListener> xCore(
541                 sm->createInstance(OUString::createFromAscii("com.sun.star.oooimprovement.Core")),
542                 UNO_QUERY);
543             Reference<XDesktop> xDesktop(
544                 sm->createInstance(OUString::createFromAscii("com.sun.star.frame.Desktop")),
545                 UNO_QUERY);
546             if(!(xCore.is() && xDesktop.is()))
547             {
548                 m_Active = false;
549                 return;
550             }
551             xDesktop->addTerminateListener(xCore);
552         }
553         // getting the LoggerPool
554         Reference<XLoggerPool> pool;
555         {
556             Reference<XInterface> temp =
557                 sm->createInstance(CSSL_LOGGERPOOL);
558             pool = Reference<XLoggerPool>(temp, UNO_QUERY);
559         }
560 
561         // getting the Logger
562         m_Logger = pool->getNamedLogger(LOGGERNAME);
563 
564         // getting the FileHandler
565         prepareLogHandler();
566 
567         // getting the Formatter
568         {
569             Reference<XInterface> temp =
570                 sm->createInstance(CSSL_CSVFORMATTER);
571             m_Formatter = Reference<XCsvLogFormatter>(temp, UNO_QUERY);
572         }
573 
574         if(m_Formatter.is() && m_LogHandler.is() && m_Logger.is())
575         {
576             Sequence<OUString> columns = Sequence<OUString>(COLUMNS);
577             columns[0] = OUString::createFromAscii("eventtype");
578             columns[1] = OUString::createFromAscii("originapp");
579             columns[2] = OUString::createFromAscii("originwidget");
580             columns[3] = OUString::createFromAscii("uno url");
581             columns[4] = OUString::createFromAscii("parent id");
582             columns[5] = OUString::createFromAscii("window type");
583             columns[6] = OUString::createFromAscii("id");
584             columns[7] = OUString::createFromAscii("method");
585             columns[8] = OUString::createFromAscii("parameter");
586             m_Formatter->setColumnnames(columns);
587             m_LogHandler->setFormatter(Reference<XLogFormatter>(m_Formatter, UNO_QUERY));
588             m_Logger->setLevel(LogLevel::ALL);
589             m_LogHandler->setLevel(LogLevel::ALL);
590             m_Logger->addLogHandler(m_LogHandler);
591         }
592         else
593             m_Active = false;
594     }
595 
596     // private static UiEventsLogger_Impl
597     bool UiEventsLogger_Impl::shouldActivate()
598     {
599         return getEnabledFromCfg() && getEnabledFromCoreController();
600     }
601 
602     OUString UiEventsLogger_Impl::getLogPathFromCfg()
603     {
604         OUString result;
605         Reference<XMultiServiceFactory> sm = getProcessServiceFactory();
606 
607         ConfigurationHelper::readDirectKey(
608             sm,
609             CFG_LOGGING, CFG_OOOIMPROVEMENT, CFG_LOGPATH,
610             ConfigurationHelper::E_READONLY
611         ) >>= result;
612 
613         Reference<XStringSubstitution> path_sub(
614             sm->createInstance(CSSU_PATHSUB),
615             UNO_QUERY);
616         if(path_sub.is())
617             result = path_sub->substituteVariables(result, sal_False);
618         return result;
619     }
620 
621     TimeValue UiEventsLogger_Impl::getIdleTimeoutFromCfg()
622     {
623         sal_Int32 timeoutminutes = 360;
624         Reference<XMultiServiceFactory> sm = getProcessServiceFactory();
625 
626         ConfigurationHelper::readDirectKey(
627             sm,
628             CFG_LOGGING, CFG_OOOIMPROVEMENT, CFG_IDLETIMEOUT,
629             ConfigurationHelper::E_READONLY
630         ) >>= timeoutminutes;
631         TimeValue result;
632         result.Seconds = static_cast<sal_uInt32>(timeoutminutes)*60;
633         result.Nanosec = 0;
634         return result;
635     }
636 
637     bool UiEventsLogger_Impl::getEnabledFromCfg()
638     {
639         sal_Bool result = false;
640         Reference<XMultiServiceFactory> sm = getProcessServiceFactory();
641         ConfigurationHelper::readDirectKey(
642             sm,
643             CFG_LOGGING, CFG_OOOIMPROVEMENT, CFG_ENABLED,
644             ::comphelper::ConfigurationHelper::E_READONLY
645         ) >>= result;
646         return result;
647     }
648 
649     bool UiEventsLogger_Impl::getEnabledFromCoreController()
650     {
651         Reference<XMultiServiceFactory> sm = getProcessServiceFactory();
652         Reference<XCoreController> core_c(
653             sm->createInstance(OUString::createFromAscii("com.sun.star.oooimprovement.CoreController")),
654             UNO_QUERY);
655         if(!core_c.is()) return false;
656         return core_c->enablingUiEventsLoggerAllowed(1);
657     }
658 
659     UiEventsLogger_Impl::ptr UiEventsLogger_Impl::instance = UiEventsLogger_Impl::ptr();
660     UiEventsLogger_Impl::ptr UiEventsLogger_Impl::getInstance()
661     {
662         if(instance == NULL)
663             instance = UiEventsLogger_Impl::ptr(new UiEventsLogger_Impl());
664         return instance;
665     }
666 
667     Mutex * UiEventsLogger_Impl::singleton_mutex = NULL;
668     void UiEventsLogger_Impl::prepareMutex()
669     {
670         if(singleton_mutex == NULL)
671         {
672             Guard<Mutex> global_guard(Mutex::getGlobalMutex());
673             if(singleton_mutex == NULL)
674                 singleton_mutex = new Mutex();
675         }
676     }
677 
678     sal_Int32 UiEventsLogger_Impl::findIdx(const Sequence<PropertyValue>& args, const OUString& key)
679     {
680         for(sal_Int32 i=0; i<args.getLength(); i++)
681             if(args[i].Name == key)
682                 return i;
683         return -1;
684     }
685 
686     void UiEventsLogger_Impl::disposing()
687     {
688         m_Active = false;
689         m_Logger.clear() ;
690         m_LogHandler.clear();
691         m_Formatter.clear();
692     }
693 }
694