Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "loggerconfig.hxx"
22 : #include <stdio.h>
23 :
24 : #include <com/sun/star/configuration/theDefaultProvider.hpp>
25 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
26 : #include <com/sun/star/container/XNameContainer.hpp>
27 : #include <com/sun/star/lang/XSingleServiceFactory.hpp>
28 : #include <com/sun/star/util/XChangesBatch.hpp>
29 : #include <com/sun/star/logging/LogLevel.hpp>
30 : #include <com/sun/star/lang/NullPointerException.hpp>
31 : #include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
32 : #include <com/sun/star/beans/NamedValue.hpp>
33 : #include <com/sun/star/logging/XLogHandler.hpp>
34 : #include <com/sun/star/logging/XLogFormatter.hpp>
35 :
36 : #include <tools/diagnose_ex.h>
37 : #include <osl/process.h>
38 : #include <rtl/ustrbuf.hxx>
39 :
40 : #include <cppuhelper/component_context.hxx>
41 :
42 : #include <vector>
43 : #include <sal/macros.h>
44 :
45 :
46 : namespace logging
47 : {
48 :
49 :
50 : using ::com::sun::star::uno::Reference;
51 : using ::com::sun::star::logging::XLogger;
52 : using ::com::sun::star::lang::XMultiServiceFactory;
53 : using ::com::sun::star::uno::Sequence;
54 : using ::com::sun::star::uno::Any;
55 : using ::com::sun::star::container::XNameContainer;
56 : using ::com::sun::star::uno::UNO_QUERY_THROW;
57 : using ::com::sun::star::lang::XSingleServiceFactory;
58 : using ::com::sun::star::uno::XInterface;
59 : using ::com::sun::star::util::XChangesBatch;
60 : using ::com::sun::star::uno::makeAny;
61 : using ::com::sun::star::lang::NullPointerException;
62 : using ::com::sun::star::uno::Exception;
63 : using ::com::sun::star::lang::ServiceNotRegisteredException;
64 : using ::com::sun::star::beans::NamedValue;
65 : using ::com::sun::star::logging::XLogHandler;
66 : using ::com::sun::star::logging::XLogFormatter;
67 : using ::com::sun::star::container::XNameAccess;
68 : using ::com::sun::star::uno::XComponentContext;
69 :
70 : namespace LogLevel = ::com::sun::star::logging::LogLevel;
71 :
72 : namespace
73 : {
74 :
75 : typedef void (*SettingTranslation)( const Reference< XLogger >&, const OUString&, Any& );
76 :
77 :
78 16 : void lcl_substituteFileHandlerURLVariables_nothrow( const Reference< XLogger >& _rxLogger, OUString& _inout_rFileURL )
79 : {
80 80 : struct Variable
81 : {
82 : const sal_Char* pVariablePattern;
83 : const sal_Int32 nPatternLength;
84 : rtl_TextEncoding eEncoding;
85 : const OUString sVariableValue;
86 :
87 80 : Variable( const sal_Char* _pVariablePattern, const sal_Int32 _nPatternLength, rtl_TextEncoding _eEncoding,
88 : const OUString& _rVariableValue )
89 : :pVariablePattern( _pVariablePattern )
90 : ,nPatternLength( _nPatternLength )
91 : ,eEncoding( _eEncoding )
92 80 : ,sVariableValue( _rVariableValue )
93 : {
94 80 : }
95 : };
96 :
97 16 : OUString sLoggerName;
98 16 : try { sLoggerName = _rxLogger->getName(); }
99 0 : catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
100 :
101 : TimeValue aTimeValue;
102 : oslDateTime aDateTime;
103 16 : OSL_VERIFY( osl_getSystemTime( &aTimeValue ) );
104 16 : OSL_VERIFY( osl_getDateTimeFromTimeValue( &aTimeValue, &aDateTime ) );
105 :
106 : char buffer[ 30 ];
107 16 : const size_t buffer_size = sizeof( buffer );
108 :
109 : snprintf( buffer, buffer_size, "%04i-%02i-%02i",
110 : (int)aDateTime.Year,
111 : (int)aDateTime.Month,
112 16 : (int)aDateTime.Day );
113 32 : rtl::OUString sDate = rtl::OUString::createFromAscii( buffer );
114 :
115 : snprintf( buffer, buffer_size, "%02i-%02i-%02i.%03i",
116 : (int)aDateTime.Hours,
117 : (int)aDateTime.Minutes,
118 : (int)aDateTime.Seconds,
119 16 : ::sal::static_int_cast< sal_Int16 >( aDateTime.NanoSeconds / 10000000 ) );
120 32 : rtl::OUString sTime = rtl::OUString::createFromAscii( buffer );
121 :
122 32 : rtl::OUStringBuffer aBuff;
123 16 : aBuff.append( sDate );
124 16 : aBuff.append( '.' );
125 16 : aBuff.append( sTime );
126 32 : rtl::OUString sDateTime = aBuff.makeStringAndClear();
127 :
128 16 : oslProcessIdentifier aProcessId = 0;
129 : oslProcessInfo info;
130 16 : info.Size = sizeof (oslProcessInfo);
131 16 : if ( osl_getProcessInfo ( 0, osl_Process_IDENTIFIER, &info ) == osl_Process_E_None)
132 16 : aProcessId = info.Ident;
133 32 : rtl::OUString aPID = OUString::number( aProcessId );
134 :
135 : Variable aVariables[] =
136 : {
137 : Variable( RTL_CONSTASCII_USTRINGPARAM( "$(loggername)" ), sLoggerName ),
138 : Variable( RTL_CONSTASCII_USTRINGPARAM( "$(date)" ), sDate ),
139 : Variable( RTL_CONSTASCII_USTRINGPARAM( "$(time)" ), sTime ),
140 : Variable( RTL_CONSTASCII_USTRINGPARAM( "$(datetime)" ), sDateTime ),
141 : Variable( RTL_CONSTASCII_USTRINGPARAM( "$(pid)" ), aPID )
142 32 : };
143 :
144 96 : for ( size_t i = 0; i < SAL_N_ELEMENTS( aVariables ); ++i )
145 : {
146 80 : OUString sPattern( aVariables[i].pVariablePattern, aVariables[i].nPatternLength, aVariables[i].eEncoding );
147 80 : sal_Int32 nVariableIndex = _inout_rFileURL.indexOf( sPattern );
148 80 : if ( ( nVariableIndex == 0 )
149 96 : || ( ( nVariableIndex > 0 )
150 16 : && ( sPattern[ nVariableIndex - 1 ] != '$' )
151 : )
152 : )
153 : {
154 : // found an (unescaped) variable
155 16 : _inout_rFileURL = _inout_rFileURL.replaceAt( nVariableIndex, sPattern.getLength(), aVariables[i].sVariableValue );
156 : }
157 96 : }
158 16 : }
159 :
160 :
161 16 : void lcl_transformFileHandlerSettings_nothrow( const Reference< XLogger >& _rxLogger, const OUString& _rSettingName, Any& _inout_rSettingValue )
162 : {
163 16 : if ( _rSettingName != "FileURL" )
164 : // not interested in this setting
165 16 : return;
166 :
167 16 : OUString sURL;
168 16 : OSL_VERIFY( _inout_rSettingValue >>= sURL );
169 16 : lcl_substituteFileHandlerURLVariables_nothrow( _rxLogger, sURL );
170 16 : _inout_rSettingValue <<= sURL;
171 : }
172 :
173 :
174 32 : Reference< XInterface > lcl_createInstanceFromSetting_throw(
175 : const Reference<XComponentContext>& _rContext,
176 : const Reference< XLogger >& _rxLogger,
177 : const Reference< XNameAccess >& _rxLoggerSettings,
178 : const sal_Char* _pServiceNameAsciiNodeName,
179 : const sal_Char* _pServiceSettingsAsciiNodeName,
180 : SettingTranslation _pSettingTranslation = NULL
181 : )
182 : {
183 32 : Reference< XInterface > xInstance;
184 :
185 : // read the settings for the to-be-created service
186 32 : Reference< XNameAccess > xServiceSettingsNode( _rxLoggerSettings->getByName(
187 64 : OUString::createFromAscii( _pServiceSettingsAsciiNodeName ) ), UNO_QUERY_THROW );
188 :
189 64 : Sequence< OUString > aSettingNames( xServiceSettingsNode->getElementNames() );
190 32 : size_t nServiceSettingCount( aSettingNames.getLength() );
191 64 : Sequence< NamedValue > aSettings( nServiceSettingCount );
192 32 : if ( nServiceSettingCount )
193 : {
194 16 : const OUString* pSettingNames = aSettingNames.getConstArray();
195 16 : const OUString* pSettingNamesEnd = aSettingNames.getConstArray() + aSettingNames.getLength();
196 16 : NamedValue* pSetting = aSettings.getArray();
197 :
198 32 : for ( ;
199 : pSettingNames != pSettingNamesEnd;
200 : ++pSettingNames, ++pSetting
201 : )
202 : {
203 16 : pSetting->Name = *pSettingNames;
204 16 : pSetting->Value = xServiceSettingsNode->getByName( *pSettingNames );
205 :
206 16 : if ( _pSettingTranslation )
207 16 : (_pSettingTranslation)( _rxLogger, pSetting->Name, pSetting->Value );
208 : }
209 : }
210 :
211 64 : OUString sServiceName;
212 32 : _rxLoggerSettings->getByName( OUString::createFromAscii( _pServiceNameAsciiNodeName ) ) >>= sServiceName;
213 32 : if ( !sServiceName.isEmpty() )
214 : {
215 32 : bool bSuccess = false;
216 32 : if ( aSettings.getLength() )
217 : {
218 16 : Sequence< Any > aConstructionArgs(1);
219 16 : aConstructionArgs[0] <<= aSettings;
220 16 : xInstance = _rContext->getServiceManager()->createInstanceWithArgumentsAndContext(sServiceName, aConstructionArgs, _rContext);
221 16 : bSuccess = xInstance.is();
222 : }
223 : else
224 : {
225 16 : xInstance = _rContext->getServiceManager()->createInstanceWithContext(sServiceName, _rContext);
226 16 : bSuccess = xInstance.is();
227 : }
228 :
229 32 : if ( !bSuccess )
230 0 : throw ServiceNotRegisteredException( sServiceName );
231 : }
232 :
233 64 : return xInstance;
234 : }
235 : }
236 :
237 :
238 16 : void initializeLoggerFromConfiguration( const Reference<XComponentContext>& _rContext, const Reference< XLogger >& _rxLogger )
239 : {
240 : try
241 : {
242 16 : if ( !_rxLogger.is() )
243 0 : throw NullPointerException();
244 :
245 : Reference< XMultiServiceFactory > xConfigProvider(
246 16 : com::sun::star::configuration::theDefaultProvider::get(_rContext));
247 :
248 : // write access to the "Settings" node (which includes settings for all loggers)
249 32 : Sequence< Any > aArguments(1);
250 32 : aArguments[0] <<= NamedValue(
251 : OUString( "nodepath" ),
252 : makeAny( OUString( "/org.openoffice.Office.Logging/Settings" ) )
253 16 : );
254 16 : Reference< XNameContainer > xAllSettings( xConfigProvider->createInstanceWithArguments(
255 : OUString( "com.sun.star.configuration.ConfigurationUpdateAccess" ),
256 : aArguments
257 32 : ), UNO_QUERY_THROW );
258 :
259 32 : OUString sLoggerName( _rxLogger->getName() );
260 16 : if ( !xAllSettings->hasByName( sLoggerName ) )
261 : {
262 : // no node yet for this logger. Create default settings.
263 15 : Reference< XSingleServiceFactory > xNodeFactory( xAllSettings, UNO_QUERY_THROW );
264 30 : Reference< XInterface > xLoggerSettings( xNodeFactory->createInstance(), UNO_QUERY_THROW );
265 15 : xAllSettings->insertByName( sLoggerName, makeAny( xLoggerSettings ) );
266 30 : Reference< XChangesBatch > xChanges( xAllSettings, UNO_QUERY_THROW );
267 30 : xChanges->commitChanges();
268 : }
269 :
270 : // actually read and forward the settings
271 32 : Reference< XNameAccess > xLoggerSettings( xAllSettings->getByName( sLoggerName ), UNO_QUERY_THROW );
272 :
273 : // the log level
274 16 : sal_Int32 nLogLevel( LogLevel::OFF );
275 16 : OSL_VERIFY( xLoggerSettings->getByName("LogLevel") >>= nLogLevel );
276 16 : _rxLogger->setLevel( nLogLevel );
277 :
278 : // the default handler, if any
279 32 : Reference< XInterface > xUntyped( lcl_createInstanceFromSetting_throw( _rContext, _rxLogger, xLoggerSettings, "DefaultHandler", "HandlerSettings", &lcl_transformFileHandlerSettings_nothrow ) );
280 16 : if ( !xUntyped.is() )
281 : // no handler -> we're done
282 0 : return;
283 32 : Reference< XLogHandler > xHandler( xUntyped, UNO_QUERY_THROW );
284 16 : _rxLogger->addLogHandler( xHandler );
285 :
286 : // The newly created handler might have an own (default) level. Ensure that it uses
287 : // the same level as the logger.
288 16 : xHandler->setLevel( nLogLevel );
289 :
290 : // the default formatter for the handler
291 16 : xUntyped = lcl_createInstanceFromSetting_throw( _rContext, _rxLogger, xLoggerSettings, "DefaultFormatter", "FormatterSettings" );
292 16 : if ( !xUntyped.is() )
293 : // no formatter -> we're done
294 0 : return;
295 32 : Reference< XLogFormatter > xFormatter( xUntyped, UNO_QUERY_THROW );
296 32 : xHandler->setFormatter( xFormatter );
297 :
298 : // TODO: we could first create the formatter, then the handler. This would allow
299 : // passing the formatter as value in the component context, so the handler would
300 : // not create an own default formatter
301 : }
302 0 : catch( const Exception& )
303 : {
304 : DBG_UNHANDLED_EXCEPTION();
305 : }
306 : }
307 :
308 :
309 : } // namespace logging
310 :
311 :
312 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|