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