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