diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /extensions/source/logging | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'extensions/source/logging')
-rw-r--r-- | extensions/source/logging/consolehandler.cxx | 264 | ||||
-rw-r--r-- | extensions/source/logging/csvformatter.cxx | 320 | ||||
-rw-r--r-- | extensions/source/logging/filehandler.cxx | 359 | ||||
-rw-r--r-- | extensions/source/logging/log.component | 47 | ||||
-rw-r--r-- | extensions/source/logging/logger.cxx | 265 | ||||
-rw-r--r-- | extensions/source/logging/loggerconfig.cxx | 283 | ||||
-rw-r--r-- | extensions/source/logging/loggerconfig.hxx | 50 | ||||
-rw-r--r-- | extensions/source/logging/loghandler.cxx | 183 | ||||
-rw-r--r-- | extensions/source/logging/loghandler.hxx | 142 | ||||
-rw-r--r-- | extensions/source/logging/logrecord.cxx | 86 | ||||
-rw-r--r-- | extensions/source/logging/logrecord.hxx | 53 | ||||
-rw-r--r-- | extensions/source/logging/methodguard.hxx | 55 | ||||
-rw-r--r-- | extensions/source/logging/plaintextformatter.cxx | 154 | ||||
-rw-r--r-- | extensions/source/logging/simpletextformatter.cxx | 98 |
14 files changed, 2359 insertions, 0 deletions
diff --git a/extensions/source/logging/consolehandler.cxx b/extensions/source/logging/consolehandler.cxx new file mode 100644 index 000000000..d1455baa3 --- /dev/null +++ b/extensions/source/logging/consolehandler.cxx @@ -0,0 +1,264 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include "methodguard.hxx" +#include "loghandler.hxx" + +#include <com/sun/star/logging/XConsoleHandler.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/logging/LogLevel.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/beans/NamedValue.hpp> + +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <stdio.h> + +namespace logging +{ + using ::com::sun::star::logging::XConsoleHandler; + using ::com::sun::star::lang::XServiceInfo; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::logging::XLogFormatter; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::logging::LogRecord; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::beans::NamedValue; + + typedef ::cppu::WeakComponentImplHelper < XConsoleHandler + , XServiceInfo + > ConsoleHandler_Base; + + namespace { + + class ConsoleHandler :public ::cppu::BaseMutex + ,public ConsoleHandler_Base + { + private: + LogHandlerHelper m_aHandlerHelper; + sal_Int32 m_nThreshold; + + public: + ConsoleHandler(const Reference<XComponentContext> &context, + const css::uno::Sequence<css::uno::Any> &arguments); + virtual ~ConsoleHandler() override; + + private: + // XConsoleHandler + virtual ::sal_Int32 SAL_CALL getThreshold() override; + virtual void SAL_CALL setThreshold( ::sal_Int32 _threshold ) override; + + // XLogHandler + virtual OUString SAL_CALL getEncoding() override; + virtual void SAL_CALL setEncoding( const OUString& _encoding ) override; + virtual Reference< XLogFormatter > SAL_CALL getFormatter() override; + virtual void SAL_CALL setFormatter( const Reference< XLogFormatter >& _formatter ) override; + virtual ::sal_Int32 SAL_CALL getLevel() override; + virtual void SAL_CALL setLevel( ::sal_Int32 _level ) override; + virtual void SAL_CALL flush( ) override; + virtual sal_Bool SAL_CALL publish( const LogRecord& Record ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& _rServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + public: + typedef ComponentMethodGuard< ConsoleHandler > MethodGuard; + void enterMethod( MethodGuard::Access ); + void leaveMethod( MethodGuard::Access ); + }; + + } + + ConsoleHandler::ConsoleHandler(const Reference<XComponentContext> &context, + const css::uno::Sequence<css::uno::Any> &arguments) + :ConsoleHandler_Base( m_aMutex ) + ,m_aHandlerHelper( context, m_aMutex, rBHelper ) + ,m_nThreshold( css::logging::LogLevel::SEVERE ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !arguments.hasElements() ) + { // create() - nothing to init + m_aHandlerHelper.setIsInitialized(); + return; + } + + if ( arguments.getLength() != 1 ) + throw IllegalArgumentException( OUString(), *this, 1 ); + + Sequence< NamedValue > aSettings; + if ( !( arguments[0] >>= aSettings ) ) + throw IllegalArgumentException( OUString(), *this, 1 ); + + // createWithSettings( [in] sequence< css::beans::NamedValue > Settings ) + ::comphelper::NamedValueCollection aTypedSettings( aSettings ); + m_aHandlerHelper.initFromSettings( aTypedSettings ); + + aTypedSettings.get_ensureType( "Threshold", m_nThreshold ); + + m_aHandlerHelper.setIsInitialized(); + } + + ConsoleHandler::~ConsoleHandler() + { + if ( !rBHelper.bDisposed ) + { + acquire(); + dispose(); + } + } + + + void SAL_CALL ConsoleHandler::disposing() + { + m_aHandlerHelper.setFormatter( nullptr ); + } + + + void ConsoleHandler::enterMethod( MethodGuard::Access ) + { + m_aHandlerHelper.enterMethod(); + } + + + void ConsoleHandler::leaveMethod( MethodGuard::Access ) + { + m_aMutex.release(); + } + + + ::sal_Int32 SAL_CALL ConsoleHandler::getThreshold() + { + MethodGuard aGuard( *this ); + return m_nThreshold; + } + + + void SAL_CALL ConsoleHandler::setThreshold( ::sal_Int32 _threshold ) + { + MethodGuard aGuard( *this ); + m_nThreshold = _threshold; + } + + + OUString SAL_CALL ConsoleHandler::getEncoding() + { + MethodGuard aGuard( *this ); + OUString sEncoding; + OSL_VERIFY( m_aHandlerHelper.getEncoding( sEncoding ) ); + return sEncoding; + } + + + void SAL_CALL ConsoleHandler::setEncoding( const OUString& _rEncoding ) + { + MethodGuard aGuard( *this ); + OSL_VERIFY( m_aHandlerHelper.setEncoding( _rEncoding ) ); + } + + + Reference< XLogFormatter > SAL_CALL ConsoleHandler::getFormatter() + { + MethodGuard aGuard( *this ); + return m_aHandlerHelper.getFormatter(); + } + + + void SAL_CALL ConsoleHandler::setFormatter( const Reference< XLogFormatter >& _rxFormatter ) + { + MethodGuard aGuard( *this ); + m_aHandlerHelper.setFormatter( _rxFormatter ); + } + + + ::sal_Int32 SAL_CALL ConsoleHandler::getLevel() + { + MethodGuard aGuard( *this ); + return m_aHandlerHelper.getLevel(); + } + + + void SAL_CALL ConsoleHandler::setLevel( ::sal_Int32 _nLevel ) + { + MethodGuard aGuard( *this ); + m_aHandlerHelper.setLevel( _nLevel ); + } + + + void SAL_CALL ConsoleHandler::flush( ) + { + MethodGuard aGuard( *this ); + fflush( stdout ); + fflush( stderr ); + } + + + sal_Bool SAL_CALL ConsoleHandler::publish( const LogRecord& _rRecord ) + { + MethodGuard aGuard( *this ); + + OString sEntry; + if ( !m_aHandlerHelper.formatForPublishing( _rRecord, sEntry ) ) + return false; + + if ( _rRecord.Level >= m_nThreshold ) + fprintf( stderr, "%s\n", sEntry.getStr() ); + else + fprintf( stdout, "%s\n", sEntry.getStr() ); + + return true; + } + + OUString SAL_CALL ConsoleHandler::getImplementationName() + { + return "com.sun.star.comp.extensions.ConsoleHandler"; + } + + sal_Bool SAL_CALL ConsoleHandler::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + Sequence< OUString > SAL_CALL ConsoleHandler::getSupportedServiceNames() + { + return { "com.sun.star.logging.ConsoleHandler" }; + } + +} // namespace logging + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_extensions_ConsoleHandler( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &arguments) +{ + return cppu::acquire(new logging::ConsoleHandler(context, arguments)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/csvformatter.cxx b/extensions/source/logging/csvformatter.cxx new file mode 100644 index 000000000..8e749db42 --- /dev/null +++ b/extensions/source/logging/csvformatter.cxx @@ -0,0 +1,320 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <com/sun/star/logging/XCsvLogFormatter.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <rtl/ustrbuf.hxx> +#include <sal/macros.h> +#include <sal/types.h> + +#include <stdio.h> +#include <string_view> + +namespace logging +{ + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::logging::LogRecord; + + namespace { + + // formats for csv files as defined by RFC4180 + class CsvFormatter : public cppu::WeakImplHelper<css::logging::XCsvLogFormatter, css::lang::XServiceInfo> + { + public: + virtual OUString SAL_CALL formatMultiColumn(const Sequence< OUString>& column_data) override; + + CsvFormatter(); + + private: + // XCsvLogFormatter + virtual sal_Bool SAL_CALL getLogEventNo() override; + virtual sal_Bool SAL_CALL getLogThread() override; + virtual sal_Bool SAL_CALL getLogTimestamp() override; + virtual sal_Bool SAL_CALL getLogSource() override; + virtual Sequence< OUString > SAL_CALL getColumnnames() override; + + virtual void SAL_CALL setLogEventNo( sal_Bool log_event_no ) override; + virtual void SAL_CALL setLogThread( sal_Bool log_thread ) override; + virtual void SAL_CALL setLogTimestamp( sal_Bool log_timestamp ) override; + virtual void SAL_CALL setLogSource( sal_Bool log_source ) override; + virtual void SAL_CALL setColumnnames( const Sequence< OUString>& column_names) override; + + // XLogFormatter + virtual OUString SAL_CALL getHead( ) override; + virtual OUString SAL_CALL format( const LogRecord& Record ) override; + virtual OUString SAL_CALL getTail( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& service_name ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + private: + bool m_LogEventNo; + bool m_LogThread; + bool m_LogTimestamp; + bool m_LogSource; + bool m_MultiColumn; + css::uno::Sequence< OUString > m_Columnnames; + }; + + } +} // namespace logging + +// private helpers +namespace +{ + const sal_Unicode quote_char = '"'; + const sal_Unicode comma_char = ','; + constexpr OUStringLiteral dos_newline = u"\r\n"; + + bool needsQuoting(std::u16string_view str) + { + return str.find_first_of(u"\",\n\r") != std::u16string_view::npos; + }; + + void appendEncodedString(OUStringBuffer& buf, const OUString& str) + { + if(needsQuoting(str)) + { + // each double-quote will get replaced by two double-quotes + buf.append(quote_char); + const sal_Int32 buf_offset = buf.getLength(); + const sal_Int32 str_length = str.getLength(); + buf.append(str); + // special treatment for the last character + if(quote_char==str[str_length-1]) + buf.append(quote_char); + // iterating backwards because the index at which we insert won't be shifted + // when moving that way. + for(sal_Int32 i = str_length; i>=0; ) + { + i=str.lastIndexOf(quote_char, --i); + if(i!=-1) + buf.insert(buf_offset + i, quote_char); + } + buf.append(quote_char); + } + else + buf.append(str); + }; +} + +namespace logging +{ + CsvFormatter::CsvFormatter() + :m_LogEventNo(true), + m_LogThread(true), + m_LogTimestamp(true), + m_LogSource(false), + m_MultiColumn(false), + m_Columnnames({ "message" }) + { } + + sal_Bool CsvFormatter::getLogEventNo() + { + return m_LogEventNo; + } + + sal_Bool CsvFormatter::getLogThread() + { + return m_LogThread; + } + + sal_Bool CsvFormatter::getLogTimestamp() + { + return m_LogTimestamp; + } + + sal_Bool CsvFormatter::getLogSource() + { + return m_LogSource; + } + + Sequence< OUString > CsvFormatter::getColumnnames() + { + return m_Columnnames; + } + + void CsvFormatter::setLogEventNo(sal_Bool log_event_no) + { + m_LogEventNo = log_event_no; + } + + void CsvFormatter::setLogThread(sal_Bool log_thread) + { + m_LogThread = log_thread; + } + + void CsvFormatter::setLogTimestamp(sal_Bool log_timestamp) + { + m_LogTimestamp = log_timestamp; + } + + void CsvFormatter::setLogSource(sal_Bool log_source) + { + m_LogSource = log_source; + } + + void CsvFormatter::setColumnnames(const Sequence< OUString >& columnnames) + { + m_Columnnames = columnnames; + m_MultiColumn = (m_Columnnames.getLength()>1); + } + + OUString SAL_CALL CsvFormatter::getHead( ) + { + OUStringBuffer buf; + if(m_LogEventNo) + buf.append("event no,"); + if(m_LogThread) + buf.append("thread,"); + if(m_LogTimestamp) + buf.append("timestamp,"); + if(m_LogSource) + buf.append("class,method,"); + sal_Int32 columns = m_Columnnames.getLength(); + for(sal_Int32 i=0; i<columns; i++) + { + buf.append(m_Columnnames[i]); + buf.append(comma_char); + } + buf.setLength(buf.getLength()-1); + buf.append(dos_newline); + return buf.makeStringAndClear(); + } + + OUString SAL_CALL CsvFormatter::format( const LogRecord& record ) + { + OUStringBuffer aLogEntry; + + if(m_LogEventNo) + { + aLogEntry.append( record.SequenceNumber ); + aLogEntry.append(comma_char); + } + + if(m_LogThread) + { + aLogEntry.append( record.ThreadID ); + aLogEntry.append(comma_char); + } + + if(m_LogTimestamp) + { + if ( record.LogTime.Year < -9999 || 9999 < record.LogTime.Year + || record.LogTime.Month < 1 || 12 < record.LogTime.Month + || record.LogTime.Day < 1 || 31 < record.LogTime.Day + || 24 < record.LogTime.Hours + || 60 < record.LogTime.Minutes + || 60 < record.LogTime.Seconds + || 999999999 < record.LogTime.NanoSeconds) + { + throw css::lang::IllegalArgumentException("invalid date", static_cast<cppu::OWeakObject*>(this), 1); + } + + // ISO 8601 + char buffer[ SAL_N_ELEMENTS("-32768-65535-65535T65535:65535:65535.4294967295") ]; + const size_t buffer_size = sizeof( buffer ); + snprintf( buffer, buffer_size, "%04i-%02u-%02uT%02u:%02u:%02u.%09" SAL_PRIuUINT32, + static_cast<int>(record.LogTime.Year), + static_cast<unsigned int>(record.LogTime.Month), + static_cast<unsigned int>(record.LogTime.Day), + static_cast<unsigned int>(record.LogTime.Hours), + static_cast<unsigned int>(record.LogTime.Minutes), + static_cast<unsigned int>(record.LogTime.Seconds), + record.LogTime.NanoSeconds ); + aLogEntry.appendAscii( buffer ); + aLogEntry.append(comma_char); + } + + if(m_LogSource) + { + appendEncodedString(aLogEntry, record.SourceClassName); + aLogEntry.append(comma_char); + + appendEncodedString(aLogEntry, record.SourceMethodName); + aLogEntry.append(comma_char); + } + + // if the CsvFormatter has multiple columns set via setColumnnames(), the + // message of the record is expected to be encoded with formatMultiColumn + // if the CsvFormatter has only one column set, the message is expected not + // to be encoded + if(m_MultiColumn) + aLogEntry.append(record.Message); + else + appendEncodedString(aLogEntry, record.Message); + + aLogEntry.append( dos_newline ); + return aLogEntry.makeStringAndClear(); + } + + OUString SAL_CALL CsvFormatter::getTail( ) + { + return OUString(); + } + + OUString SAL_CALL CsvFormatter::formatMultiColumn(const Sequence< OUString>& column_data) + { + sal_Int32 columns = column_data.getLength(); + OUStringBuffer buf; + for(int i=0; i<columns; i++) + { + appendEncodedString(buf, column_data[i]); + buf.append(comma_char); + } + buf.setLength(buf.getLength()-1); + return buf.makeStringAndClear(); + } + + sal_Bool SAL_CALL CsvFormatter::supportsService( const OUString& service_name ) + { + return cppu::supportsService(this, service_name); + } + + OUString SAL_CALL CsvFormatter::getImplementationName() + { + return "com.sun.star.comp.extensions.CsvFormatter"; + } + + Sequence< OUString > SAL_CALL CsvFormatter::getSupportedServiceNames() + { + return { "com.sun.star.logging.CsvFormatter" }; + } + +} // namespace logging + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_extensions_CsvFormatter( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new logging::CsvFormatter()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/filehandler.cxx b/extensions/source/logging/filehandler.cxx new file mode 100644 index 000000000..200a3a64b --- /dev/null +++ b/extensions/source/logging/filehandler.cxx @@ -0,0 +1,359 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> +#include <sal/log.hxx> + +#include "methodguard.hxx" +#include "loghandler.hxx" + +#include <com/sun/star/logging/XLogHandler.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/util/PathSubstitution.hpp> +#include <com/sun/star/util/XStringSubstitution.hpp> + +#include <tools/diagnose_ex.h> + +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <osl/file.hxx> + +#include <memory> + +namespace logging +{ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::logging::LogRecord; + using ::com::sun::star::logging::XLogFormatter; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::logging::XLogHandler; + using ::com::sun::star::lang::XServiceInfo; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::util::PathSubstitution; + using ::com::sun::star::util::XStringSubstitution; + using ::com::sun::star::beans::NamedValue; + + typedef ::cppu::WeakComponentImplHelper < XLogHandler + , XServiceInfo + > FileHandler_Base; + + namespace { + + class FileHandler :public ::cppu::BaseMutex + ,public FileHandler_Base + { + private: + enum FileValidity + { + /// never attempted to open the file + eUnknown, + /// file is valid + eValid, + /// file is invalid + eInvalid + }; + + Reference<XComponentContext> m_xContext; + LogHandlerHelper m_aHandlerHelper; + OUString m_sFileURL; + std::unique_ptr< ::osl::File > m_pFile; + FileValidity m_eFileValidity; + + public: + FileHandler(const css::uno::Reference<XComponentContext> &context, + const css::uno::Sequence<css::uno::Any> &arguments); + virtual ~FileHandler() override; + + private: + // XLogHandler + virtual OUString SAL_CALL getEncoding() override; + virtual void SAL_CALL setEncoding( const OUString& _encoding ) override; + virtual Reference< XLogFormatter > SAL_CALL getFormatter() override; + virtual void SAL_CALL setFormatter( const Reference< XLogFormatter >& _formatter ) override; + virtual ::sal_Int32 SAL_CALL getLevel() override; + virtual void SAL_CALL setLevel( ::sal_Int32 _level ) override; + virtual void SAL_CALL flush( ) override; + virtual sal_Bool SAL_CALL publish( const LogRecord& Record ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& _rServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + public: + typedef ComponentMethodGuard< FileHandler > MethodGuard; + void enterMethod( MethodGuard::Access ); + void leaveMethod( MethodGuard::Access ); + + private: + /** prepares our output file for writing + */ + bool impl_prepareFile_nothrow(); + + /// writes the given string to our file + void impl_writeString_nothrow( const OString& _rEntry ); + + /** does string substitution on a (usually externally provided) file url + */ + void impl_doStringsubstitution_nothrow( OUString& _inout_rURL ); + }; + + } + + FileHandler::FileHandler(const css::uno::Reference<XComponentContext> &context, + const css::uno::Sequence<css::uno::Any> &arguments) + :FileHandler_Base( m_aMutex ) + ,m_xContext( context ) + ,m_aHandlerHelper( context, m_aMutex, rBHelper ) + ,m_eFileValidity( eUnknown ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( arguments.getLength() != 1 ) + throw IllegalArgumentException( OUString(), *this, 1 ); + + Sequence< NamedValue > aSettings; + if ( arguments[0] >>= m_sFileURL ) + { + // create( [in] string URL ); + impl_doStringsubstitution_nothrow( m_sFileURL ); + } + else if ( arguments[0] >>= aSettings ) + { + // createWithSettings( [in] sequence< css::beans::NamedValue > Settings ) + ::comphelper::NamedValueCollection aTypedSettings( aSettings ); + m_aHandlerHelper.initFromSettings( aTypedSettings ); + + if ( aTypedSettings.get_ensureType( "FileURL", m_sFileURL ) ) + impl_doStringsubstitution_nothrow( m_sFileURL ); + } + else + throw IllegalArgumentException( OUString(), *this, 1 ); + + m_aHandlerHelper.setIsInitialized(); + } + + FileHandler::~FileHandler() + { + if ( !rBHelper.bDisposed ) + { + acquire(); + dispose(); + } + } + + + bool FileHandler::impl_prepareFile_nothrow() + { + if ( m_eFileValidity == eUnknown ) + { + m_pFile.reset( new ::osl::File( m_sFileURL ) ); + // check whether the log file already exists + ::osl::DirectoryItem aFileItem; + if (osl::FileBase::E_None == ::osl::DirectoryItem::get(m_sFileURL, aFileItem)) + { + ::osl::FileStatus aStatus(osl_FileStatus_Mask_Validate); + if (::osl::FileBase::E_None == aFileItem.getFileStatus(aStatus)) + ::osl::File::remove(m_sFileURL); + } + + ::osl::FileBase::RC res = m_pFile->open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ); + m_eFileValidity = res == ::osl::FileBase::E_None + ? eValid + : eInvalid; + #if OSL_DEBUG_LEVEL > 0 + if ( m_eFileValidity == eInvalid ) + { + SAL_WARN( "extensions.logging", "FileHandler::impl_prepareFile_nothrow: could not open the designated log file:" + "\nURL: " << m_sFileURL + << "\nerror code: " << static_cast<sal_Int32>(res) ); + } + #endif + if ( m_eFileValidity == eValid ) + { + OString sHead; + if ( m_aHandlerHelper.getEncodedHead( sHead ) ) + impl_writeString_nothrow( sHead ); + } + } + + return m_eFileValidity == eValid; + } + + + void FileHandler::impl_writeString_nothrow( const OString& _rEntry ) + { + OSL_PRECOND(m_pFile, "FileHandler::impl_writeString_nothrow: no file!"); + + sal_uInt64 nBytesToWrite( _rEntry.getLength() ); + sal_uInt64 nBytesWritten( 0 ); + ::osl::FileBase::RC res = + m_pFile->write( _rEntry.getStr(), nBytesToWrite, nBytesWritten ); + OSL_ENSURE( ( res == ::osl::FileBase::E_None ) && ( nBytesWritten == nBytesToWrite ), + "FileHandler::impl_writeString_nothrow: could not write the log entry!" ); + } + + + void FileHandler::impl_doStringsubstitution_nothrow( OUString& _inout_rURL ) + { + try + { + Reference< XStringSubstitution > xStringSubst(PathSubstitution::create(m_xContext)); + _inout_rURL = xStringSubst->substituteVariables( _inout_rURL, true ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.logging"); + } + } + + + void SAL_CALL FileHandler::disposing() + { + if ( m_eFileValidity == eValid ) + { + OString sTail; + if ( m_aHandlerHelper.getEncodedTail( sTail ) ) + impl_writeString_nothrow( sTail ); + } + + m_pFile.reset(); + m_aHandlerHelper.setFormatter( nullptr ); + } + + + void FileHandler::enterMethod( MethodGuard::Access ) + { + m_aHandlerHelper.enterMethod(); + } + + + void FileHandler::leaveMethod( MethodGuard::Access ) + { + m_aMutex.release(); + } + + + OUString SAL_CALL FileHandler::getEncoding() + { + MethodGuard aGuard( *this ); + OUString sEncoding; + OSL_VERIFY( m_aHandlerHelper.getEncoding( sEncoding ) ); + return sEncoding; + } + + + void SAL_CALL FileHandler::setEncoding( const OUString& _rEncoding ) + { + MethodGuard aGuard( *this ); + OSL_VERIFY( m_aHandlerHelper.setEncoding( _rEncoding ) ); + } + + + Reference< XLogFormatter > SAL_CALL FileHandler::getFormatter() + { + MethodGuard aGuard( *this ); + return m_aHandlerHelper.getFormatter(); + } + + + void SAL_CALL FileHandler::setFormatter( const Reference< XLogFormatter >& _rxFormatter ) + { + MethodGuard aGuard( *this ); + m_aHandlerHelper.setFormatter( _rxFormatter ); + } + + + ::sal_Int32 SAL_CALL FileHandler::getLevel() + { + MethodGuard aGuard( *this ); + return m_aHandlerHelper.getLevel(); + } + + + void SAL_CALL FileHandler::setLevel( ::sal_Int32 _nLevel ) + { + MethodGuard aGuard( *this ); + m_aHandlerHelper.setLevel( _nLevel ); + } + + + void SAL_CALL FileHandler::flush( ) + { + MethodGuard aGuard( *this ); + if (!m_pFile) + { + OSL_PRECOND(false, "FileHandler::flush: no file!"); + return; + } + ::osl::FileBase::RC res = m_pFile->sync(); + OSL_ENSURE(res == ::osl::FileBase::E_None, "FileHandler::flush: Could not sync logfile to filesystem."); + } + + + sal_Bool SAL_CALL FileHandler::publish( const LogRecord& _rRecord ) + { + MethodGuard aGuard( *this ); + + if ( !impl_prepareFile_nothrow() ) + return false; + + OString sEntry; + if ( !m_aHandlerHelper.formatForPublishing( _rRecord, sEntry ) ) + return false; + + impl_writeString_nothrow( sEntry ); + return true; + } + + OUString SAL_CALL FileHandler::getImplementationName() + { + return "com.sun.star.comp.extensions.FileHandler"; + } + + sal_Bool SAL_CALL FileHandler::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + Sequence< OUString > SAL_CALL FileHandler::getSupportedServiceNames() + { + return { "com.sun.star.logging.FileHandler" }; + } + +} // namespace logging + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_extensions_FileHandler( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &arguments) +{ + return cppu::acquire(new logging::FileHandler(context, arguments)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/log.component b/extensions/source/logging/log.component new file mode 100644 index 000000000..ae221bb57 --- /dev/null +++ b/extensions/source/logging/log.component @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.extensions.ConsoleHandler" + constructor="com_sun_star_comp_extensions_ConsoleHandler"> + <service name="com.sun.star.logging.ConsoleHandler"/> + </implementation> + <implementation name="com.sun.star.comp.extensions.CsvFormatter" + constructor="com_sun_star_comp_extensions_CsvFormatter"> + <service name="com.sun.star.logging.CsvFormatter"/> + </implementation> + <implementation name="com.sun.star.comp.extensions.FileHandler" + constructor="com_sun_star_comp_extensions_FileHandler"> + <service name="com.sun.star.logging.FileHandler"/> + </implementation> + <implementation name="com.sun.star.comp.extensions.LoggerPool" + constructor="com_sun_star_comp_extensions_LoggerPool" + single-instance="true"> + <singleton name="com.sun.star.logging.LoggerPool"/> + </implementation> + <implementation name="com.sun.star.comp.extensions.PlainTextFormatter" + constructor="com_sun_star_comp_extensions_PlainTextFormatter"> + <service name="com.sun.star.logging.PlainTextFormatter"/> + </implementation> + <implementation name="com.sun.star.comp.extensions.SimpleTextFormatter" + constructor="com_sun_star_comp_extensions_SimpleTextFormatter"> + <service name="com.sun.star.logging.SimpleTextFormatter"/> + </implementation> +</component> diff --git a/extensions/source/logging/logger.cxx b/extensions/source/logging/logger.cxx new file mode 100644 index 000000000..322ad7ab9 --- /dev/null +++ b/extensions/source/logging/logger.cxx @@ -0,0 +1,265 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "logrecord.hxx" +#include "loggerconfig.hxx" + +#include <com/sun/star/logging/XLogger.hpp> +#include <com/sun/star/logging/LogLevel.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/logging/XLoggerPool.hpp> + +#include <cppuhelper/basemutex.hxx> +#include <comphelper/interfacecontainer2.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/weakref.hxx> +#include <map> + + +namespace logging +{ + + using ::com::sun::star::logging::XLogger; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::lang::XServiceInfo; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::WeakReference; + using ::com::sun::star::logging::XLogHandler; + using ::com::sun::star::logging::LogRecord; + + namespace { + + class EventLogger : public cppu::BaseMutex, + public cppu::WeakImplHelper<css::logging::XLogger> + { + private: + comphelper::OInterfaceContainerHelper2 m_aHandlers; + oslInterlockedCount m_nEventNumber; + + // <attributes> + sal_Int32 m_nLogLevel; + OUString m_sName; + // </attributes> + + public: + EventLogger( const Reference< XComponentContext >& _rxContext, const OUString& _rName ); + + // XLogger + virtual OUString SAL_CALL getName() override; + virtual ::sal_Int32 SAL_CALL getLevel() override; + virtual void SAL_CALL setLevel( ::sal_Int32 _level ) override; + virtual void SAL_CALL addLogHandler( const Reference< XLogHandler >& LogHandler ) override; + virtual void SAL_CALL removeLogHandler( const Reference< XLogHandler >& LogHandler ) override; + virtual sal_Bool SAL_CALL isLoggable( ::sal_Int32 _nLevel ) override; + virtual void SAL_CALL log( ::sal_Int32 Level, const OUString& Message ) override; + virtual void SAL_CALL logp( ::sal_Int32 Level, const OUString& SourceClass, const OUString& SourceMethod, const OUString& Message ) override; + + protected: + virtual ~EventLogger() override; + + private: + /** logs the given log record + */ + void impl_ts_logEvent_nothrow( const LogRecord& _rRecord ); + + /** non-threadsafe impl-version of isLoggable + */ + bool impl_nts_isLoggable_nothrow( ::sal_Int32 _nLevel ); + }; + + /** administrates a pool of XLogger instances, where a logger is keyed by its name, + and subsequent requests for a logger with the same name return the same instance. + */ + class LoggerPool : public cppu::WeakImplHelper<css::logging::XLoggerPool, XServiceInfo> + { + private: + ::osl::Mutex m_aMutex; + Reference<XComponentContext> m_xContext; + std::map< OUString, WeakReference<XLogger> > m_aLoggerMap; + + public: + explicit LoggerPool( const Reference< XComponentContext >& _rxContext ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& _rServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XLoggerPool + virtual Reference< XLogger > SAL_CALL getNamedLogger( const OUString& Name ) override; + virtual Reference< XLogger > SAL_CALL getDefaultLogger( ) override; + }; + + } + + EventLogger::EventLogger( const Reference< XComponentContext >& _rxContext, const OUString& _rName ) + :m_aHandlers( m_aMutex ) + ,m_nEventNumber( 0 ) + ,m_nLogLevel( css::logging::LogLevel::OFF ) + ,m_sName( _rName ) + { + osl_atomic_increment( &m_refCount ); + { + initializeLoggerFromConfiguration( _rxContext, this ); + } + osl_atomic_decrement( &m_refCount ); + } + + EventLogger::~EventLogger() + { + } + + bool EventLogger::impl_nts_isLoggable_nothrow( ::sal_Int32 _nLevel ) + { + if ( _nLevel < m_nLogLevel ) + return false; + + if ( !m_aHandlers.getLength() ) + return false; + + return true; + } + + void EventLogger::impl_ts_logEvent_nothrow( const LogRecord& _rRecord ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !impl_nts_isLoggable_nothrow( _rRecord.Level ) ) + return; + + m_aHandlers.forEach< XLogHandler >( + [&_rRecord] (Reference<XLogHandler> const& rxListener) { rxListener->publish(_rRecord); } ); + m_aHandlers.forEach< XLogHandler >( + [] (Reference<XLogHandler> const& rxListener) { rxListener->flush(); } ); + } + + OUString SAL_CALL EventLogger::getName() + { + return m_sName; + } + + ::sal_Int32 SAL_CALL EventLogger::getLevel() + { + ::osl::MutexGuard aGuard( m_aMutex ); + return m_nLogLevel; + } + + void SAL_CALL EventLogger::setLevel( ::sal_Int32 _level ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_nLogLevel = _level; + } + + void SAL_CALL EventLogger::addLogHandler( const Reference< XLogHandler >& _rxLogHandler ) + { + if ( _rxLogHandler.is() ) + m_aHandlers.addInterface( _rxLogHandler ); + } + + void SAL_CALL EventLogger::removeLogHandler( const Reference< XLogHandler >& _rxLogHandler ) + { + if ( _rxLogHandler.is() ) + m_aHandlers.removeInterface( _rxLogHandler ); + } + + sal_Bool SAL_CALL EventLogger::isLoggable( ::sal_Int32 _nLevel ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return impl_nts_isLoggable_nothrow( _nLevel ); + } + + void SAL_CALL EventLogger::log( ::sal_Int32 _nLevel, const OUString& _rMessage ) + { + impl_ts_logEvent_nothrow( createLogRecord( + m_sName, + _rMessage, + _nLevel, + osl_atomic_increment( &m_nEventNumber ) + ) ); + } + + void SAL_CALL EventLogger::logp( ::sal_Int32 _nLevel, const OUString& _rSourceClass, const OUString& _rSourceMethod, const OUString& _rMessage ) + { + impl_ts_logEvent_nothrow( createLogRecord( + m_sName, + _rSourceClass, + _rSourceMethod, + _rMessage, + _nLevel, + osl_atomic_increment( &m_nEventNumber ) + ) ); + } + + LoggerPool::LoggerPool( const Reference< XComponentContext >& _rxContext ) + :m_xContext( _rxContext ) + { + } + + OUString SAL_CALL LoggerPool::getImplementationName() + { + return "com.sun.star.comp.extensions.LoggerPool"; + } + + sal_Bool SAL_CALL LoggerPool::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + Sequence< OUString > SAL_CALL LoggerPool::getSupportedServiceNames() + { + return { "com.sun.star.logging.LoggerPool" }; + } + + Reference< XLogger > SAL_CALL LoggerPool::getNamedLogger( const OUString& _rName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + WeakReference< XLogger >& rLogger( m_aLoggerMap[ _rName ] ); + Reference< XLogger > xLogger( rLogger ); + if ( !xLogger.is() ) + { + // never requested before, or already dead + xLogger = new EventLogger( m_xContext, _rName ); + rLogger = xLogger; + } + + return xLogger; + } + + Reference< XLogger > SAL_CALL LoggerPool::getDefaultLogger( ) + { + return getNamedLogger( "org.openoffice.logging.DefaultLogger" ); + } + +} // namespace logging + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_extensions_LoggerPool( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new logging::LoggerPool(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/loggerconfig.cxx b/extensions/source/logging/loggerconfig.cxx new file mode 100644 index 000000000..25ef76e02 --- /dev/null +++ b/extensions/source/logging/loggerconfig.cxx @@ -0,0 +1,283 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "loggerconfig.hxx" +#include <stdio.h> +#include <string_view> + +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <com/sun/star/logging/LogLevel.hpp> +#include <com/sun/star/lang/NullPointerException.hpp> +#include <com/sun/star/lang/ServiceNotRegisteredException.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/logging/XLogHandler.hpp> +#include <com/sun/star/logging/XLogFormatter.hpp> + +#include <tools/diagnose_ex.h> +#include <osl/process.h> + +#include <cppuhelper/component_context.hxx> + + +namespace logging +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::logging::XLogger; + using ::com::sun::star::lang::XMultiServiceFactory; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Any; + using ::com::sun::star::container::XNameContainer; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::lang::XSingleServiceFactory; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::util::XChangesBatch; + using ::com::sun::star::lang::NullPointerException; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::lang::ServiceNotRegisteredException; + using ::com::sun::star::beans::NamedValue; + using ::com::sun::star::logging::XLogHandler; + using ::com::sun::star::logging::XLogFormatter; + using ::com::sun::star::container::XNameAccess; + using ::com::sun::star::uno::XComponentContext; + + namespace LogLevel = ::com::sun::star::logging::LogLevel; + + namespace + { + + typedef void (*SettingTranslation)( const Reference< XLogger >&, const OUString&, Any& ); + + + void lcl_substituteFileHandlerURLVariables_nothrow( const Reference< XLogger >& _rxLogger, OUString& _inout_rFileURL ) + { + struct Variable + { + std::u16string_view pVariablePattern; + OUString sVariableValue; + }; + + OUString sLoggerName; + try { sLoggerName = _rxLogger->getName(); } + catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("extensions.logging"); } + + TimeValue aTimeValue; + oslDateTime aDateTime; + OSL_VERIFY( osl_getSystemTime( &aTimeValue ) ); + OSL_VERIFY( osl_getDateTimeFromTimeValue( &aTimeValue, &aDateTime ) ); + + char buffer[ 30 ]; + const size_t buffer_size = sizeof( buffer ); + + snprintf( buffer, buffer_size, "%04i-%02i-%02i", + static_cast<int>(aDateTime.Year), + static_cast<int>(aDateTime.Month), + static_cast<int>(aDateTime.Day) ); + OUString sDate = OUString::createFromAscii( buffer ); + + snprintf( buffer, buffer_size, "%02i-%02i-%02i.%03i", + static_cast<int>(aDateTime.Hours), + static_cast<int>(aDateTime.Minutes), + static_cast<int>(aDateTime.Seconds), + ::sal::static_int_cast< sal_Int16 >( aDateTime.NanoSeconds / 10000000 ) ); + OUString sTime = OUString::createFromAscii( buffer ); + + OUString sDateTime = sDate + "." + sTime; + + oslProcessIdentifier aProcessId = 0; + oslProcessInfo info; + info.Size = sizeof (oslProcessInfo); + if ( osl_getProcessInfo ( nullptr, osl_Process_IDENTIFIER, &info ) == osl_Process_E_None) + aProcessId = info.Ident; + OUString aPID = OUString::number( aProcessId ); + + Variable const aVariables[] = + { + {std::u16string_view(u"$(loggername)"), sLoggerName}, + {std::u16string_view(u"$(date)"), sDate}, + {std::u16string_view(u"$(time)"), sTime}, + {std::u16string_view(u"$(datetime)"), sDateTime}, + {std::u16string_view(u"$(pid)"), aPID} + }; + + for (Variable const & aVariable : aVariables) + { + sal_Int32 nVariableIndex = _inout_rFileURL.indexOf( aVariable.pVariablePattern ); + if (nVariableIndex >= 0) + { + _inout_rFileURL = _inout_rFileURL.replaceAt( nVariableIndex, aVariable.pVariablePattern.size(), aVariable.sVariableValue ); + } + } + } + + + void lcl_transformFileHandlerSettings_nothrow( const Reference< XLogger >& _rxLogger, const OUString& _rSettingName, Any& _inout_rSettingValue ) + { + if ( _rSettingName != "FileURL" ) + // not interested in this setting + return; + + OUString sURL; + OSL_VERIFY( _inout_rSettingValue >>= sURL ); + lcl_substituteFileHandlerURLVariables_nothrow( _rxLogger, sURL ); + _inout_rSettingValue <<= sURL; + } + + + Reference< XInterface > lcl_createInstanceFromSetting_throw( + const Reference<XComponentContext>& _rContext, + const Reference< XLogger >& _rxLogger, + const Reference< XNameAccess >& _rxLoggerSettings, + const char* _pServiceNameAsciiNodeName, + const char* _pServiceSettingsAsciiNodeName, + SettingTranslation _pSettingTranslation = nullptr + ) + { + Reference< XInterface > xInstance; + + // read the settings for the to-be-created service + Reference< XNameAccess > xServiceSettingsNode( _rxLoggerSettings->getByName( + OUString::createFromAscii( _pServiceSettingsAsciiNodeName ) ), UNO_QUERY_THROW ); + + Sequence< OUString > aSettingNames( xServiceSettingsNode->getElementNames() ); + size_t nServiceSettingCount( aSettingNames.getLength() ); + Sequence< NamedValue > aSettings( nServiceSettingCount ); + if ( nServiceSettingCount ) + { + const OUString* pSettingNames = aSettingNames.getConstArray(); + const OUString* pSettingNamesEnd = aSettingNames.getConstArray() + aSettingNames.getLength(); + NamedValue* pSetting = aSettings.getArray(); + + for ( ; + pSettingNames != pSettingNamesEnd; + ++pSettingNames, ++pSetting + ) + { + pSetting->Name = *pSettingNames; + pSetting->Value = xServiceSettingsNode->getByName( *pSettingNames ); + + if ( _pSettingTranslation ) + _pSettingTranslation( _rxLogger, pSetting->Name, pSetting->Value ); + } + } + + OUString sServiceName; + _rxLoggerSettings->getByName( OUString::createFromAscii( _pServiceNameAsciiNodeName ) ) >>= sServiceName; + if ( !sServiceName.isEmpty() ) + { + bool bSuccess = false; + if ( aSettings.hasElements() ) + { + Sequence< Any > aConstructionArgs{ Any(aSettings) }; + xInstance = _rContext->getServiceManager()->createInstanceWithArgumentsAndContext(sServiceName, aConstructionArgs, _rContext); + bSuccess = xInstance.is(); + } + else + { + xInstance = _rContext->getServiceManager()->createInstanceWithContext(sServiceName, _rContext); + bSuccess = xInstance.is(); + } + + if ( !bSuccess ) + throw ServiceNotRegisteredException( sServiceName ); + } + + return xInstance; + } + } + + + void initializeLoggerFromConfiguration( const Reference<XComponentContext>& _rContext, const Reference< XLogger >& _rxLogger ) + { + try + { + if ( !_rxLogger.is() ) + throw NullPointerException(); + + Reference< XMultiServiceFactory > xConfigProvider( + css::configuration::theDefaultProvider::get(_rContext)); + + // write access to the "Settings" node (which includes settings for all loggers) + Sequence<Any> aArguments{ Any(NamedValue( + "nodepath", Any(OUString("/org.openoffice.Office.Logging/Settings")))) }; + Reference< XNameContainer > xAllSettings( xConfigProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationUpdateAccess", + aArguments + ), UNO_QUERY_THROW ); + + OUString sLoggerName( _rxLogger->getName() ); + if ( !xAllSettings->hasByName( sLoggerName ) ) + { + // no node yet for this logger. Create default settings. + Reference< XSingleServiceFactory > xNodeFactory( xAllSettings, UNO_QUERY_THROW ); + Reference< XInterface > xLoggerSettings( xNodeFactory->createInstance(), css::uno::UNO_SET_THROW ); + xAllSettings->insertByName( sLoggerName, Any( xLoggerSettings ) ); + Reference< XChangesBatch > xChanges( xAllSettings, UNO_QUERY_THROW ); + xChanges->commitChanges(); + } + + // actually read and forward the settings + Reference< XNameAccess > xLoggerSettings( xAllSettings->getByName( sLoggerName ), UNO_QUERY_THROW ); + + // the log level + sal_Int32 nLogLevel( LogLevel::OFF ); + OSL_VERIFY( xLoggerSettings->getByName("LogLevel") >>= nLogLevel ); + _rxLogger->setLevel( nLogLevel ); + + // the default handler, if any + Reference< XInterface > xUntyped( lcl_createInstanceFromSetting_throw( _rContext, _rxLogger, xLoggerSettings, "DefaultHandler", "HandlerSettings", &lcl_transformFileHandlerSettings_nothrow ) ); + if ( !xUntyped.is() ) + // no handler -> we're done + return; + Reference< XLogHandler > xHandler( xUntyped, UNO_QUERY_THROW ); + _rxLogger->addLogHandler( xHandler ); + + // The newly created handler might have an own (default) level. Ensure that it uses + // the same level as the logger. + xHandler->setLevel( nLogLevel ); + + // the default formatter for the handler + xUntyped = lcl_createInstanceFromSetting_throw( _rContext, _rxLogger, xLoggerSettings, "DefaultFormatter", "FormatterSettings" ); + if ( !xUntyped.is() ) + // no formatter -> we're done + return; + Reference< XLogFormatter > xFormatter( xUntyped, UNO_QUERY_THROW ); + xHandler->setFormatter( xFormatter ); + + // TODO: we could first create the formatter, then the handler. This would allow + // passing the formatter as value in the component context, so the handler would + // not create an own default formatter + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.logging"); + } + } + + +} // namespace logging + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/loggerconfig.hxx b/extensions/source/logging/loggerconfig.hxx new file mode 100644 index 000000000..b08628cf1 --- /dev/null +++ b/extensions/source/logging/loggerconfig.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/logging/XLogger.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + + +namespace logging +{ + + + /** initializes the given logger from the configuration + + The configuration node /org.openoffice.Office.Logging/Settings/<logger_name> + is examined for this. If it does not yet exist, it will be created. + + The function creates a default handler and a default formatter, as specified in the + configuration. + + This function is currently external to the logger instance. Perhaps it can, on the long + run, be moved to the logger implementation - not sure if it's the best place. + */ + void initializeLoggerFromConfiguration( + const css::uno::Reference<css::uno::XComponentContext>& _rContext, + const css::uno::Reference< css::logging::XLogger >& _rxLogger + ); + + +} // namespace logging + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/loghandler.cxx b/extensions/source/logging/loghandler.cxx new file mode 100644 index 000000000..afc33605b --- /dev/null +++ b/extensions/source/logging/loghandler.cxx @@ -0,0 +1,183 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "loghandler.hxx" + +#include <com/sun/star/logging/LogLevel.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/logging/PlainTextFormatter.hpp> + +#include <tools/diagnose_ex.h> +#include <rtl/tencinfo.h> + + +namespace logging +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::logging::LogRecord; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::logging::XLogFormatter; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::logging::PlainTextFormatter; + + namespace LogLevel = ::com::sun::star::logging::LogLevel; + + LogHandlerHelper::LogHandlerHelper( const Reference< XComponentContext >& _rxContext, ::osl::Mutex& _rMutex, ::cppu::OBroadcastHelper& _rBHelper ) + :m_eEncoding( RTL_TEXTENCODING_UTF8 ) + ,m_nLevel( LogLevel::SEVERE ) + ,m_xContext( _rxContext ) + ,m_rMutex( _rMutex ) + ,m_rBHelper( _rBHelper ) + ,m_bInitialized( false ) + { + } + + + void LogHandlerHelper::initFromSettings( const ::comphelper::NamedValueCollection& _rSettings ) + { + OUString sEncoding; + if ( _rSettings.get_ensureType( "Encoding", sEncoding ) ) + { + if ( !setEncoding( sEncoding ) ) + throw IllegalArgumentException(); + } + + _rSettings.get_ensureType( "Formatter", m_xFormatter ); + _rSettings.get_ensureType( "Level", m_nLevel ); + } + + + void LogHandlerHelper::enterMethod() + { + m_rMutex.acquire(); + + if ( !m_bInitialized ) + throw DisposedException("component not initialized" ); + + if ( m_rBHelper.bDisposed ) + throw DisposedException("component already disposed" ); + + // fallback settings, in case they weren't passed at construction time + if ( !getFormatter().is() ) + { + try + { + Reference< XLogFormatter > xFormatter( PlainTextFormatter::create( m_xContext ), css::uno::UNO_SET_THROW ); + setFormatter( xFormatter ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.logging"); + } + } + } + + + bool LogHandlerHelper::getEncoding( OUString& _out_rEncoding ) const + { + const char* pMimeCharset = rtl_getMimeCharsetFromTextEncoding( m_eEncoding ); + if ( pMimeCharset ) + { + _out_rEncoding = OUString::createFromAscii( pMimeCharset ); + return true; + } + _out_rEncoding.clear(); + return false; + } + + + bool LogHandlerHelper::setEncoding( std::u16string_view _rEncoding ) + { + OString sAsciiEncoding( OUStringToOString( _rEncoding, RTL_TEXTENCODING_ASCII_US ) ); + rtl_TextEncoding eEncoding = rtl_getTextEncodingFromMimeCharset( sAsciiEncoding.getStr() ); + if ( eEncoding != RTL_TEXTENCODING_DONTKNOW ) + { + m_eEncoding = eEncoding; + return true; + } + return false; + } + + + bool LogHandlerHelper::formatForPublishing( const LogRecord& _rRecord, OString& _out_rEntry ) const + { + if ( _rRecord.Level < getLevel() ) + // not to be published due to low level + return false; + + try + { + Reference< XLogFormatter > xFormatter( getFormatter(), css::uno::UNO_SET_THROW ); + OUString sEntry( xFormatter->format( _rRecord ) ); + _out_rEntry = OUStringToOString( sEntry, getTextEncoding() ); + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.logging"); + } + return false; + } + + + bool LogHandlerHelper::getEncodedHead( OString& _out_rHead ) const + { + try + { + Reference< XLogFormatter > xFormatter( getFormatter(), css::uno::UNO_SET_THROW ); + OUString sHead( xFormatter->getHead() ); + _out_rHead = OUStringToOString( sHead, getTextEncoding() ); + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.logging"); + } + return false; + } + + + bool LogHandlerHelper::getEncodedTail( OString& _out_rTail ) const + { + try + { + Reference< XLogFormatter > xFormatter( getFormatter(), css::uno::UNO_SET_THROW ); + OUString sTail( xFormatter->getTail() ); + _out_rTail = OUStringToOString( sTail, getTextEncoding() ); + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.logging"); + } + return false; + } + + +} // namespace logging + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/loghandler.hxx b/extensions/source/logging/loghandler.hxx new file mode 100644 index 000000000..02f4fb773 --- /dev/null +++ b/extensions/source/logging/loghandler.hxx @@ -0,0 +1,142 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <string_view> + +#include <com/sun/star/logging/XLogFormatter.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/logging/LogRecord.hpp> + +#include <comphelper/namedvaluecollection.hxx> +#include <cppuhelper/interfacecontainer.hxx> +#include <rtl/string.hxx> + + +namespace logging +{ + + class LogHandlerHelper + { + private: + // <attributes> + rtl_TextEncoding m_eEncoding; + sal_Int32 m_nLevel; + css::uno::Reference< css::logging::XLogFormatter > + m_xFormatter; + // <//attributes> + + css::uno::Reference< css::uno::XComponentContext > + m_xContext; + ::osl::Mutex& m_rMutex; + ::cppu::OBroadcastHelper& m_rBHelper; + bool m_bInitialized; + + public: + LogHandlerHelper( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + ::osl::Mutex& _rMutex, + ::cppu::OBroadcastHelper& _rBHelper + ); + + public: + void setIsInitialized() { m_bInitialized = true; } + + bool getEncoding( OUString& _out_rEncoding ) const; + bool setEncoding( std::u16string_view _rEncoding ); + + rtl_TextEncoding + getTextEncoding() const { return m_eEncoding; } + + const css::uno::Reference< css::logging::XLogFormatter >& + getFormatter() const { return m_xFormatter; } + void + setFormatter( const css::uno::Reference< css::logging::XLogFormatter >& _rxFormatter ) + { + m_xFormatter = _rxFormatter; + } + + sal_Int32 + getLevel() const { return m_nLevel; } + void + setLevel( const sal_Int32 _nLevel ) + { + m_nLevel = _nLevel; + } + + /** prepares implementation of a public accessible method of a log handler + + <code>enterMethod</code> does the following things: + <ul><li>It acquires the mutex given in the constructor.</li> + <li>It checks whether the component is already initialized, and throws an exception if not os.</li> + <li>It checks whether the component is already disposed, and throws an exception if not os.</li> + <li>It creates a default formatter (PlainTextFormatter), if no formatter exists at this time.</li> + </ul> + */ + void enterMethod(); + + /** formats a record for publishing it + + The method first checks whether the records log level is greater or equal our own + log level. If not, <FALSE/> is returned. + + Second, our formatter is used to create a unicode string from the log record. If an error occurs + during this, e.g. if the formatter is <NULL/> or throws an exception during formatting, + <FALSE/> is returned. + + Finally, the unicode string is encoded into a byte string, using our encoding setting. Then, + <TRUE/> is returned. + */ + bool formatForPublishing( const css::logging::LogRecord& _rRecord, OString& _out_rEntry ) const; + + /** retrieves our formatter's heading, encoded with our encoding + + @return <TRUE/> in case of success, <FALSE/> if any error occurred + */ + bool getEncodedHead( OString& _out_rHead ) const; + + /** retrieves our formatter's tail, encoded with our encoding + + @return <TRUE/> in case of success, <FALSE/> if any error occurred + */ + bool getEncodedTail( OString& _out_rTail ) const; + + /** initializes the instance from a collection of named settings + + The recognized named settings are <code>Encoding</code>, <code>Formatter</code>, and <code>Level</code>, + which initialize the respective attributes. + + Settings which are recognized are remove from the given collection. This allows + the caller to determine whether or not the collection contained any unsupported + items, and react appropriately. + + @throws IllegalArgumentException + if one of the values in the collection is of wrong type. + */ + void initFromSettings( const ::comphelper::NamedValueCollection& _rSettings ); + }; + + +} // namespace logging + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/logrecord.cxx b/extensions/source/logging/logrecord.cxx new file mode 100644 index 000000000..26f59e841 --- /dev/null +++ b/extensions/source/logging/logrecord.cxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "logrecord.hxx" + +#include <osl/time.h> +#include <osl/thread.h> +#include <osl/thread.hxx> +#include <osl/diagnose.h> + + +namespace logging +{ + + + using ::com::sun::star::logging::LogRecord; + using ::com::sun::star::util::DateTime; + + namespace + { + /** returns a string representation of the current thread + + @todo + We need a way to retrieve the current UNO thread ID as string, + which is issue #i77342# + */ + OUString getCurrentThreadID() + { + oslThreadIdentifier nThreadID( osl::Thread::getCurrentIdentifier() ); + return OUString::number( static_cast<sal_Int64>(nThreadID) ); + } + } + + + LogRecord createLogRecord( const OUString& _rLoggerName, const OUString& _rClassName, + const OUString& _rMethodName, const OUString& _rMessage, + sal_Int32 _nLogLevel, oslInterlockedCount _nEventNumber ) + { + TimeValue aTimeValue; + osl_getSystemTime( &aTimeValue ); + + oslDateTime aDateTime; + OSL_VERIFY( osl_getDateTimeFromTimeValue( &aTimeValue, &aDateTime ) ); + + DateTime aTimeStamp; + aTimeStamp.Year = aDateTime.Year; + aTimeStamp.Month = aDateTime.Month; + aTimeStamp.Day = aDateTime.Day; + aTimeStamp.Hours = aDateTime.Hours; + aTimeStamp.Minutes = aDateTime.Minutes; + aTimeStamp.Seconds = aDateTime.Seconds; + aTimeStamp.NanoSeconds = aDateTime.NanoSeconds; + + return LogRecord( + _rLoggerName, + _rClassName, + _rMethodName, + _rMessage, + aTimeStamp, + _nEventNumber, + getCurrentThreadID(), + _nLogLevel + ); + } + + +} // namespace logging + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/logrecord.hxx b/extensions/source/logging/logrecord.hxx new file mode 100644 index 000000000..ad6e350cf --- /dev/null +++ b/extensions/source/logging/logrecord.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/logging/LogRecord.hpp> + +#include <osl/interlck.h> + + +namespace logging +{ + + css::logging::LogRecord createLogRecord( + const OUString& _rLoggerName, + const OUString& _rClassName, + const OUString& _rMethodName, + const OUString& _rMessage, + sal_Int32 _nLogLevel, + oslInterlockedCount _nEventNumber + ); + + inline css::logging::LogRecord createLogRecord( + const OUString& _rLoggerName, + const OUString& _rMessage, + sal_Int32 _nLogLevel, + oslInterlockedCount _nEventNumber + ) + { + return createLogRecord( _rLoggerName, OUString(), OUString(), _rMessage, _nLogLevel, _nEventNumber ); + } + + +} // namespace logging + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/methodguard.hxx b/extensions/source/logging/methodguard.hxx new file mode 100644 index 000000000..189462eae --- /dev/null +++ b/extensions/source/logging/methodguard.hxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + + +namespace logging +{ + template < class COMPONENT > + class ComponentMethodGuard + { + private: + COMPONENT& m_rHandler; + + public: + class Access + { + private: + friend class ComponentMethodGuard; + Access() { } + }; + + public: + explicit ComponentMethodGuard( COMPONENT& _rHandler ) + :m_rHandler( _rHandler ) + { + m_rHandler.enterMethod( Access() ); + } + ~ComponentMethodGuard() + { + m_rHandler.leaveMethod( Access() ); + } + }; + + +} // namespace logging + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/plaintextformatter.cxx b/extensions/source/logging/plaintextformatter.cxx new file mode 100644 index 000000000..23392b61c --- /dev/null +++ b/extensions/source/logging/plaintextformatter.cxx @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <com/sun/star/logging/XLogFormatter.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <rtl/ustrbuf.hxx> +#include <osl/thread.h> + +#include <stdio.h> + +namespace logging +{ + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::logging::LogRecord; + using ::com::sun::star::uno::XInterface; + + namespace { + + class PlainTextFormatter : public cppu::WeakImplHelper<css::logging::XLogFormatter, css::lang::XServiceInfo> + { + public: + PlainTextFormatter(); + + private: + // XLogFormatter + virtual OUString SAL_CALL getHead( ) override; + virtual OUString SAL_CALL format( const LogRecord& Record ) override; + virtual OUString SAL_CALL getTail( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& _rServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + }; + + } + + PlainTextFormatter::PlainTextFormatter() + { + } + + OUString SAL_CALL PlainTextFormatter::getHead( ) + { + return + " event no" // column 1: the event number + " " + "thread " // column 2: the thread ID + " " + "date " // column 3: date + " " + "time " // column 4: time + " " + "(class/method:) message" // column 5: class/method/message + "\n"; + } + + + OUString SAL_CALL PlainTextFormatter::format( const LogRecord& _rRecord ) + { + char buffer[ sizeof("-32768-65535-65535 65535:65535:65535.4294967295") ]; + // reserve enough space for hypothetical max length + const int buffer_size = sizeof( buffer ); + int used = snprintf( buffer, buffer_size, "%10i", static_cast<int>(_rRecord.SequenceNumber) ); + if ( used >= buffer_size || used < 0 ) + buffer[ buffer_size - 1 ] = 0; + + OUStringBuffer aLogEntry; + aLogEntry.appendAscii( buffer ); + aLogEntry.append( " " ); + + OString sThreadID( OUStringToOString( _rRecord.ThreadID, osl_getThreadTextEncoding() ) ); + snprintf( buffer, buffer_size, "%8s", sThreadID.getStr() ); + aLogEntry.appendAscii( buffer ); + aLogEntry.append( " " ); + + snprintf( buffer, buffer_size, "%04" SAL_PRIdINT32 "-%02" SAL_PRIuUINT32 "-%02" SAL_PRIuUINT32 " %02" SAL_PRIuUINT32 ":%02" SAL_PRIuUINT32 ":%02" SAL_PRIuUINT32 ".%09" SAL_PRIuUINT32, + static_cast<sal_Int32>(_rRecord.LogTime.Year), static_cast<sal_uInt32>(_rRecord.LogTime.Month), static_cast<sal_uInt32>(_rRecord.LogTime.Day), + static_cast<sal_uInt32>(_rRecord.LogTime.Hours), static_cast<sal_uInt32>(_rRecord.LogTime.Minutes), static_cast<sal_uInt32>(_rRecord.LogTime.Seconds), _rRecord.LogTime.NanoSeconds ); + aLogEntry.appendAscii( buffer ); + aLogEntry.append( " " ); + + if ( !(_rRecord.SourceClassName.isEmpty() || _rRecord.SourceMethodName.isEmpty()) ) + { + aLogEntry.append( _rRecord.SourceClassName ); + aLogEntry.append( "::" ); + aLogEntry.append( _rRecord.SourceMethodName ); + aLogEntry.append( ": " ); + } + + aLogEntry.append( _rRecord.Message ); + aLogEntry.append( "\n" ); + + return aLogEntry.makeStringAndClear(); + } + + + OUString SAL_CALL PlainTextFormatter::getTail( ) + { + // no tail + return OUString(); + } + + sal_Bool SAL_CALL PlainTextFormatter::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + + OUString SAL_CALL PlainTextFormatter::getImplementationName() + { + return "com.sun.star.comp.extensions.PlainTextFormatter"; + } + + Sequence< OUString > SAL_CALL PlainTextFormatter::getSupportedServiceNames() + { + return { "com.sun.star.logging.PlainTextFormatter" }; + } + +} // namespace logging + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_extensions_PlainTextFormatter( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new logging::PlainTextFormatter()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/simpletextformatter.cxx b/extensions/source/logging/simpletextformatter.cxx new file mode 100644 index 000000000..b54fea5a6 --- /dev/null +++ b/extensions/source/logging/simpletextformatter.cxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <com/sun/star/logging/XLogFormatter.hpp> +#include <com/sun/star/logging/LogLevel.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> + +namespace logging +{ +using css::logging::LogRecord; +using namespace css::uno; + +namespace +{ +class SimpleTextFormatter + : public cppu::WeakImplHelper<css::logging::XLogFormatter, css::lang::XServiceInfo> +{ +public: + SimpleTextFormatter(); + +private: + // XLogFormatter + virtual OUString SAL_CALL getHead() override; + virtual OUString SAL_CALL format(const LogRecord& Record) override; + virtual OUString SAL_CALL getTail() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& _rServiceName) override; + virtual Sequence<OUString> SAL_CALL getSupportedServiceNames() override; +}; +} + +SimpleTextFormatter::SimpleTextFormatter() {} + +OUString SAL_CALL SimpleTextFormatter::getHead() { return OUString(); } + +OUString SAL_CALL SimpleTextFormatter::format(const LogRecord& _rRecord) +{ + OUString aLogEntry; + // Highlight warnings + if (_rRecord.Level == css::logging::LogLevel::SEVERE) + aLogEntry = "ERROR: "; + else if (_rRecord.Level == css::logging::LogLevel::WARNING) + aLogEntry = "WARNING: "; + + return aLogEntry + _rRecord.Message + "\n"; +} + +OUString SAL_CALL SimpleTextFormatter::getTail() { return OUString(); } + +sal_Bool SAL_CALL SimpleTextFormatter::supportsService(const OUString& _rServiceName) +{ + return cppu::supportsService(this, _rServiceName); +} + +OUString SAL_CALL SimpleTextFormatter::getImplementationName() +{ + return "com.sun.star.comp.extensions.SimpleTextFormatter"; +} + +Sequence<OUString> SAL_CALL SimpleTextFormatter::getSupportedServiceNames() +{ + return { "com.sun.star.logging.SimpleTextFormatter" }; +} + +} // namespace logging + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_extensions_SimpleTextFormatter(css::uno::XComponentContext*, + css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new logging::SimpleTextFormatter()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |