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_extensions.hxx" 29 30 #include "log_module.hxx" 31 32 #include <stdio.h> 33 #include <string> 34 35 /** === begin UNO includes === **/ 36 #ifndef _COM_SUN_STAR_LOGGING_XLOGFORMATTER_HPP_ 37 #include <com/sun/star/logging/XCsvLogFormatter.hpp> 38 #endif 39 #ifndef _COM_SUN_STAR_LOGGING_XLOGFORMATTER_HPP_ 40 #include <com/sun/star/logging/XLogFormatter.hpp> 41 #endif 42 #ifndef _COM_SUN_STAR_UNO_XCOMPONENTCONTEXT_HPP_ 43 #include <com/sun/star/uno/XComponentContext.hpp> 44 #endif 45 #ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_ 46 #include <com/sun/star/lang/XServiceInfo.hpp> 47 #endif 48 /** === end UNO includes === **/ 49 50 #include <comphelper/componentcontext.hxx> 51 52 #include <cppuhelper/implbase2.hxx> 53 54 #include <rtl/ustrbuf.hxx> 55 56 #include <osl/thread.h> 57 58 namespace logging 59 { 60 61 /** === begin UNO using === **/ 62 using ::com::sun::star::logging::XCsvLogFormatter; 63 using ::com::sun::star::logging::XLogFormatter; 64 using ::com::sun::star::uno::XComponentContext; 65 using ::com::sun::star::uno::Reference; 66 using ::com::sun::star::uno::Sequence; 67 using ::com::sun::star::lang::XServiceInfo; 68 using ::com::sun::star::uno::RuntimeException; 69 using ::com::sun::star::logging::LogRecord; 70 using ::com::sun::star::uno::XInterface; 71 /** === end UNO using === **/ 72 73 //= CsvFormatter - declaration 74 //= formats for csv files as defined by RFC4180 75 typedef ::cppu::WeakImplHelper2 < XCsvLogFormatter 76 , XServiceInfo 77 > CsvFormatter_Base; 78 class CsvFormatter : public CsvFormatter_Base 79 { 80 public: 81 virtual ::rtl::OUString SAL_CALL formatMultiColumn(const Sequence< ::rtl::OUString>& column_data) throw (RuntimeException); 82 83 // XServiceInfo - static version 84 static ::rtl::OUString SAL_CALL getImplementationName_static(); 85 static Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static(); 86 static Reference< XInterface > Create( const Reference< XComponentContext >& context ); 87 88 protected: 89 CsvFormatter( const Reference< XComponentContext >& context ); 90 virtual ~CsvFormatter(); 91 92 // XCsvLogFormatter 93 virtual ::sal_Bool SAL_CALL getLogEventNo() throw (RuntimeException); 94 virtual ::sal_Bool SAL_CALL getLogThread() throw (RuntimeException); 95 virtual ::sal_Bool SAL_CALL getLogTimestamp() throw (RuntimeException); 96 virtual ::sal_Bool SAL_CALL getLogSource() throw (RuntimeException); 97 virtual Sequence< ::rtl::OUString > SAL_CALL getColumnnames() throw (RuntimeException); 98 99 virtual void SAL_CALL setLogEventNo( ::sal_Bool log_event_no ) throw (RuntimeException); 100 virtual void SAL_CALL setLogThread( ::sal_Bool log_thread ) throw (RuntimeException); 101 virtual void SAL_CALL setLogTimestamp( ::sal_Bool log_timestamp ) throw (RuntimeException); 102 virtual void SAL_CALL setLogSource( ::sal_Bool log_source ) throw (RuntimeException); 103 virtual void SAL_CALL setColumnnames( const Sequence< ::rtl::OUString>& column_names) throw (RuntimeException); 104 105 // XLogFormatter 106 virtual ::rtl::OUString SAL_CALL getHead( ) throw (RuntimeException); 107 virtual ::rtl::OUString SAL_CALL format( const LogRecord& Record ) throw (RuntimeException); 108 virtual ::rtl::OUString SAL_CALL getTail( ) throw (RuntimeException); 109 110 // XServiceInfo 111 virtual ::rtl::OUString SAL_CALL getImplementationName() throw(RuntimeException); 112 virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& service_name ) throw(RuntimeException); 113 virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw(RuntimeException); 114 115 private: 116 ::comphelper::ComponentContext m_aContext; 117 ::sal_Bool m_LogEventNo; 118 ::sal_Bool m_LogThread; 119 ::sal_Bool m_LogTimestamp; 120 ::sal_Bool m_LogSource; 121 ::sal_Bool m_MultiColumn; 122 ::com::sun::star::uno::Sequence< ::rtl::OUString > m_Columnnames; 123 }; 124 } // namespace logging 125 126 //= private helpers 127 namespace 128 { 129 const sal_Unicode quote_char = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"")).toChar(); 130 const sal_Unicode comma_char = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(",")).toChar(); 131 const ::rtl::OUString dos_newline = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\r\n")); 132 133 inline bool needsQuoting(const ::rtl::OUString& str) 134 { 135 static const ::rtl::OUString quote_trigger_chars = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("\",\n\r")); 136 sal_Int32 len = str.getLength(); 137 for(sal_Int32 i=0; i<len; i++) 138 if(quote_trigger_chars.indexOf(str[i])!=-1) 139 return true; 140 return false; 141 }; 142 143 inline void appendEncodedString(::rtl::OUStringBuffer& buf, const ::rtl::OUString& str) 144 { 145 if(needsQuoting(str)) 146 { 147 // each double-quote will get replaced by two double-quotes 148 buf.append(quote_char); 149 const sal_Int32 buf_offset = buf.getLength(); 150 const sal_Int32 str_length = str.getLength(); 151 buf.append(str); 152 // special treatment for the last character 153 if(quote_char==str[str_length-1]) 154 buf.append(quote_char); 155 // iterating backwards because the index at which we insert wont be shifted 156 // when moving that way. 157 for(sal_Int32 i = str_length; i>=0; ) 158 { 159 i=str.lastIndexOf(quote_char, --i); 160 if(i!=-1) 161 buf.insert(buf_offset + i, quote_char); 162 } 163 buf.append(quote_char); 164 } 165 else 166 buf.append(str); 167 }; 168 169 ::com::sun::star::uno::Sequence< ::rtl::OUString> initialColumns() 170 { 171 com::sun::star::uno::Sequence< ::rtl::OUString> result = ::com::sun::star::uno::Sequence< ::rtl::OUString>(1); 172 result[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("message")); 173 return result; 174 }; 175 } 176 177 //= CsvFormatter - implementation 178 namespace logging 179 { 180 CsvFormatter::CsvFormatter( const Reference< XComponentContext >& context ) 181 :m_aContext( context ), 182 m_LogEventNo(true), 183 m_LogThread(true), 184 m_LogTimestamp(true), 185 m_LogSource(false), 186 m_MultiColumn(false), 187 m_Columnnames(initialColumns()) 188 { } 189 190 CsvFormatter::~CsvFormatter() 191 { } 192 193 ::sal_Bool CsvFormatter::getLogEventNo() throw (RuntimeException) 194 { 195 return m_LogEventNo; 196 } 197 198 ::sal_Bool CsvFormatter::getLogThread() throw (RuntimeException) 199 { 200 return m_LogThread; 201 } 202 203 ::sal_Bool CsvFormatter::getLogTimestamp() throw (RuntimeException) 204 { 205 return m_LogTimestamp; 206 } 207 208 ::sal_Bool CsvFormatter::getLogSource() throw (RuntimeException) 209 { 210 return m_LogSource; 211 } 212 213 Sequence< ::rtl::OUString > CsvFormatter::getColumnnames() throw (RuntimeException) 214 { 215 return m_Columnnames; 216 } 217 218 void CsvFormatter::setLogEventNo(::sal_Bool log_event_no) throw (RuntimeException) 219 { 220 m_LogEventNo = log_event_no; 221 } 222 223 void CsvFormatter::setLogThread(::sal_Bool log_thread) throw (RuntimeException) 224 { 225 m_LogThread = log_thread; 226 } 227 228 void CsvFormatter::setLogTimestamp(::sal_Bool log_timestamp) throw (RuntimeException) 229 { 230 m_LogTimestamp = log_timestamp; 231 } 232 233 void CsvFormatter::setLogSource(::sal_Bool log_source) throw (RuntimeException) 234 { 235 m_LogSource = log_source; 236 } 237 238 void CsvFormatter::setColumnnames(const Sequence< ::rtl::OUString >& columnnames) throw (RuntimeException) 239 { 240 m_Columnnames = Sequence< ::rtl::OUString>(columnnames); 241 m_MultiColumn = (m_Columnnames.getLength()>1); 242 } 243 244 ::rtl::OUString SAL_CALL CsvFormatter::getHead( ) throw (RuntimeException) 245 { 246 ::rtl::OUStringBuffer buf; 247 if(m_LogEventNo) 248 buf.appendAscii("event no,"); 249 if(m_LogThread) 250 buf.appendAscii("thread,"); 251 if(m_LogTimestamp) 252 buf.appendAscii("timestamp,"); 253 if(m_LogSource) 254 buf.appendAscii("class,method,"); 255 sal_Int32 columns = m_Columnnames.getLength(); 256 for(sal_Int32 i=0; i<columns; i++) 257 { 258 buf.append(m_Columnnames[i]); 259 buf.append(comma_char); 260 } 261 buf.setLength(buf.getLength()-1); 262 buf.append(dos_newline); 263 return buf.makeStringAndClear(); 264 } 265 266 ::rtl::OUString SAL_CALL CsvFormatter::format( const LogRecord& record ) throw (RuntimeException) 267 { 268 ::rtl::OUStringBuffer aLogEntry; 269 270 if(m_LogEventNo) 271 { 272 aLogEntry.append( record.SequenceNumber ); 273 aLogEntry.append(comma_char); 274 } 275 276 if(m_LogThread) 277 { 278 aLogEntry.append( record.ThreadID ); 279 aLogEntry.append(comma_char); 280 } 281 282 if(m_LogTimestamp) 283 { 284 // ISO 8601 285 char buffer[ 30 ]; 286 const size_t buffer_size = sizeof( buffer ); 287 snprintf( buffer, buffer_size, "%04i-%02i-%02iT%02i:%02i:%02i.%02i", 288 (int)record.LogTime.Year, 289 (int)record.LogTime.Month, 290 (int)record.LogTime.Day, 291 (int)record.LogTime.Hours, 292 (int)record.LogTime.Minutes, 293 (int)record.LogTime.Seconds, 294 (int)record.LogTime.HundredthSeconds ); 295 aLogEntry.appendAscii( buffer ); 296 aLogEntry.append(comma_char); 297 } 298 299 if(m_LogSource) 300 { 301 appendEncodedString(aLogEntry, record.SourceClassName); 302 aLogEntry.append(comma_char); 303 304 appendEncodedString(aLogEntry, record.SourceMethodName); 305 aLogEntry.append(comma_char); 306 } 307 308 // if the CsvFormatter has multiple columns set via setColumnnames(), the 309 // message of the record is expected to be encoded with formatMultiColumn 310 // if the CsvFormatter has only one column set, the message is expected not 311 // to be encoded 312 if(m_MultiColumn) 313 aLogEntry.append(record.Message); 314 else 315 appendEncodedString(aLogEntry, record.Message); 316 317 aLogEntry.append( dos_newline ); 318 return aLogEntry.makeStringAndClear(); 319 } 320 321 ::rtl::OUString SAL_CALL CsvFormatter::getTail( ) throw (RuntimeException) 322 { 323 return ::rtl::OUString(); 324 } 325 326 ::rtl::OUString SAL_CALL CsvFormatter::formatMultiColumn(const Sequence< ::rtl::OUString>& column_data) throw (RuntimeException) 327 { 328 sal_Int32 columns = column_data.getLength(); 329 ::rtl::OUStringBuffer buf; 330 for(int i=0; i<columns; i++) 331 { 332 appendEncodedString(buf, column_data[i]); 333 buf.append(comma_char); 334 } 335 buf.setLength(buf.getLength()-1); 336 return buf.makeStringAndClear(); 337 } 338 339 ::sal_Bool SAL_CALL CsvFormatter::supportsService( const ::rtl::OUString& service_name ) throw(RuntimeException) 340 { 341 const Sequence< ::rtl::OUString > aServiceNames( getSupportedServiceNames() ); 342 for ( const ::rtl::OUString* pServiceNames = aServiceNames.getConstArray(); 343 pServiceNames != aServiceNames.getConstArray() + aServiceNames.getLength(); 344 ++pServiceNames 345 ) 346 if ( service_name == *pServiceNames ) 347 return sal_True; 348 return sal_False; 349 } 350 351 ::rtl::OUString SAL_CALL CsvFormatter::getImplementationName() throw(RuntimeException) 352 { 353 return getImplementationName_static(); 354 } 355 356 Sequence< ::rtl::OUString > SAL_CALL CsvFormatter::getSupportedServiceNames() throw(RuntimeException) 357 { 358 return getSupportedServiceNames_static(); 359 } 360 361 ::rtl::OUString SAL_CALL CsvFormatter::getImplementationName_static() 362 { 363 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.extensions.CsvFormatter" ) ); 364 } 365 366 Sequence< ::rtl::OUString > SAL_CALL CsvFormatter::getSupportedServiceNames_static() 367 { 368 Sequence< ::rtl::OUString > aServiceNames(1); 369 aServiceNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.logging.CsvFormatter" ) ); 370 return aServiceNames; 371 } 372 373 Reference< XInterface > CsvFormatter::Create( const Reference< XComponentContext >& context ) 374 { 375 return *( new CsvFormatter( context ) ); 376 } 377 378 void createRegistryInfo_CsvFormatter() 379 { 380 static OAutoRegistration< CsvFormatter > aAutoRegistration; 381 } 382 } // namespace logging 383