bump product version to 4.1.6.2
[LibreOffice.git] / extensions / source / logging / csvformatter.cxx
blob16d28106f661b25b7741ed7f19e7176d6fbb42a6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "log_module.hxx"
23 #include <stdio.h>
24 #include <string>
26 #include <com/sun/star/logging/XCsvLogFormatter.hpp>
27 #include <com/sun/star/logging/XLogFormatter.hpp>
28 #include <com/sun/star/uno/XComponentContext.hpp>
29 #include <com/sun/star/lang/XServiceInfo.hpp>
31 #include <comphelper/componentcontext.hxx>
33 #include <cppuhelper/implbase2.hxx>
35 #include <rtl/ustrbuf.hxx>
37 #include <osl/thread.h>
39 namespace logging
42 using ::com::sun::star::logging::XCsvLogFormatter;
43 using ::com::sun::star::logging::XLogFormatter;
44 using ::com::sun::star::uno::XComponentContext;
45 using ::com::sun::star::uno::Reference;
46 using ::com::sun::star::uno::Sequence;
47 using ::com::sun::star::lang::XServiceInfo;
48 using ::com::sun::star::uno::RuntimeException;
49 using ::com::sun::star::logging::LogRecord;
50 using ::com::sun::star::uno::XInterface;
52 //= CsvFormatter - declaration
53 //= formats for csv files as defined by RFC4180
54 typedef ::cppu::WeakImplHelper2 < XCsvLogFormatter
55 , XServiceInfo
56 > CsvFormatter_Base;
57 class CsvFormatter : public CsvFormatter_Base
59 public:
60 virtual OUString SAL_CALL formatMultiColumn(const Sequence< OUString>& column_data) throw (RuntimeException);
62 // XServiceInfo - static version
63 static OUString SAL_CALL getImplementationName_static();
64 static Sequence< OUString > SAL_CALL getSupportedServiceNames_static();
65 static Reference< XInterface > Create( const Reference< XComponentContext >& context );
67 protected:
68 CsvFormatter( const Reference< XComponentContext >& context );
69 virtual ~CsvFormatter();
71 // XCsvLogFormatter
72 virtual ::sal_Bool SAL_CALL getLogEventNo() throw (RuntimeException);
73 virtual ::sal_Bool SAL_CALL getLogThread() throw (RuntimeException);
74 virtual ::sal_Bool SAL_CALL getLogTimestamp() throw (RuntimeException);
75 virtual ::sal_Bool SAL_CALL getLogSource() throw (RuntimeException);
76 virtual Sequence< OUString > SAL_CALL getColumnnames() throw (RuntimeException);
78 virtual void SAL_CALL setLogEventNo( ::sal_Bool log_event_no ) throw (RuntimeException);
79 virtual void SAL_CALL setLogThread( ::sal_Bool log_thread ) throw (RuntimeException);
80 virtual void SAL_CALL setLogTimestamp( ::sal_Bool log_timestamp ) throw (RuntimeException);
81 virtual void SAL_CALL setLogSource( ::sal_Bool log_source ) throw (RuntimeException);
82 virtual void SAL_CALL setColumnnames( const Sequence< OUString>& column_names) throw (RuntimeException);
84 // XLogFormatter
85 virtual OUString SAL_CALL getHead( ) throw (RuntimeException);
86 virtual OUString SAL_CALL format( const LogRecord& Record ) throw (RuntimeException);
87 virtual OUString SAL_CALL getTail( ) throw (RuntimeException);
89 // XServiceInfo
90 virtual OUString SAL_CALL getImplementationName() throw(RuntimeException);
91 virtual ::sal_Bool SAL_CALL supportsService( const OUString& service_name ) throw(RuntimeException);
92 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() throw(RuntimeException);
94 private:
95 ::comphelper::ComponentContext m_aContext;
96 ::sal_Bool m_LogEventNo;
97 ::sal_Bool m_LogThread;
98 ::sal_Bool m_LogTimestamp;
99 ::sal_Bool m_LogSource;
100 ::sal_Bool m_MultiColumn;
101 ::com::sun::star::uno::Sequence< OUString > m_Columnnames;
103 } // namespace logging
105 //= private helpers
106 namespace
108 const sal_Unicode quote_char = OUString("\"").toChar();
109 const sal_Unicode comma_char = OUString(",").toChar();
110 const OUString dos_newline = OUString("\r\n");
112 inline bool needsQuoting(const OUString& str)
114 static const OUString quote_trigger_chars = OUString( "\",\n\r");
115 sal_Int32 len = str.getLength();
116 for(sal_Int32 i=0; i<len; i++)
117 if(quote_trigger_chars.indexOf(str[i])!=-1)
118 return true;
119 return false;
122 inline void appendEncodedString(OUStringBuffer& buf, const OUString& str)
124 if(needsQuoting(str))
126 // each double-quote will get replaced by two double-quotes
127 buf.append(quote_char);
128 const sal_Int32 buf_offset = buf.getLength();
129 const sal_Int32 str_length = str.getLength();
130 buf.append(str);
131 // special treatment for the last character
132 if(quote_char==str[str_length-1])
133 buf.append(quote_char);
134 // iterating backwards because the index at which we insert wont be shifted
135 // when moving that way.
136 for(sal_Int32 i = str_length; i>=0; )
138 i=str.lastIndexOf(quote_char, --i);
139 if(i!=-1)
140 buf.insert(buf_offset + i, quote_char);
142 buf.append(quote_char);
144 else
145 buf.append(str);
148 ::com::sun::star::uno::Sequence< OUString> initialColumns()
150 com::sun::star::uno::Sequence< OUString> result = ::com::sun::star::uno::Sequence< OUString>(1);
151 result[0] = OUString("message");
152 return result;
156 //= CsvFormatter - implementation
157 namespace logging
159 CsvFormatter::CsvFormatter( const Reference< XComponentContext >& context )
160 :m_aContext( context ),
161 m_LogEventNo(true),
162 m_LogThread(true),
163 m_LogTimestamp(true),
164 m_LogSource(false),
165 m_MultiColumn(false),
166 m_Columnnames(initialColumns())
169 CsvFormatter::~CsvFormatter()
172 ::sal_Bool CsvFormatter::getLogEventNo() throw (RuntimeException)
174 return m_LogEventNo;
177 ::sal_Bool CsvFormatter::getLogThread() throw (RuntimeException)
179 return m_LogThread;
182 ::sal_Bool CsvFormatter::getLogTimestamp() throw (RuntimeException)
184 return m_LogTimestamp;
187 ::sal_Bool CsvFormatter::getLogSource() throw (RuntimeException)
189 return m_LogSource;
192 Sequence< OUString > CsvFormatter::getColumnnames() throw (RuntimeException)
194 return m_Columnnames;
197 void CsvFormatter::setLogEventNo(::sal_Bool log_event_no) throw (RuntimeException)
199 m_LogEventNo = log_event_no;
202 void CsvFormatter::setLogThread(::sal_Bool log_thread) throw (RuntimeException)
204 m_LogThread = log_thread;
207 void CsvFormatter::setLogTimestamp(::sal_Bool log_timestamp) throw (RuntimeException)
209 m_LogTimestamp = log_timestamp;
212 void CsvFormatter::setLogSource(::sal_Bool log_source) throw (RuntimeException)
214 m_LogSource = log_source;
217 void CsvFormatter::setColumnnames(const Sequence< OUString >& columnnames) throw (RuntimeException)
219 m_Columnnames = Sequence< OUString>(columnnames);
220 m_MultiColumn = (m_Columnnames.getLength()>1);
223 OUString SAL_CALL CsvFormatter::getHead( ) throw (RuntimeException)
225 OUStringBuffer buf;
226 if(m_LogEventNo)
227 buf.appendAscii("event no,");
228 if(m_LogThread)
229 buf.appendAscii("thread,");
230 if(m_LogTimestamp)
231 buf.appendAscii("timestamp,");
232 if(m_LogSource)
233 buf.appendAscii("class,method,");
234 sal_Int32 columns = m_Columnnames.getLength();
235 for(sal_Int32 i=0; i<columns; i++)
237 buf.append(m_Columnnames[i]);
238 buf.append(comma_char);
240 buf.setLength(buf.getLength()-1);
241 buf.append(dos_newline);
242 return buf.makeStringAndClear();
245 OUString SAL_CALL CsvFormatter::format( const LogRecord& record ) throw (RuntimeException)
247 OUStringBuffer aLogEntry;
249 if(m_LogEventNo)
251 aLogEntry.append( record.SequenceNumber );
252 aLogEntry.append(comma_char);
255 if(m_LogThread)
257 aLogEntry.append( record.ThreadID );
258 aLogEntry.append(comma_char);
261 if(m_LogTimestamp)
263 // ISO 8601
264 char buffer[ 30 ];
265 const size_t buffer_size = sizeof( buffer );
266 snprintf( buffer, buffer_size, "%04i-%02i-%02iT%02i:%02i:%02i.%09i",
267 (int)record.LogTime.Year,
268 (int)record.LogTime.Month,
269 (int)record.LogTime.Day,
270 (int)record.LogTime.Hours,
271 (int)record.LogTime.Minutes,
272 (int)record.LogTime.Seconds,
273 (int)record.LogTime.NanoSeconds );
274 aLogEntry.appendAscii( buffer );
275 aLogEntry.append(comma_char);
278 if(m_LogSource)
280 appendEncodedString(aLogEntry, record.SourceClassName);
281 aLogEntry.append(comma_char);
283 appendEncodedString(aLogEntry, record.SourceMethodName);
284 aLogEntry.append(comma_char);
287 // if the CsvFormatter has multiple columns set via setColumnnames(), the
288 // message of the record is expected to be encoded with formatMultiColumn
289 // if the CsvFormatter has only one column set, the message is expected not
290 // to be encoded
291 if(m_MultiColumn)
292 aLogEntry.append(record.Message);
293 else
294 appendEncodedString(aLogEntry, record.Message);
296 aLogEntry.append( dos_newline );
297 return aLogEntry.makeStringAndClear();
300 OUString SAL_CALL CsvFormatter::getTail( ) throw (RuntimeException)
302 return OUString();
305 OUString SAL_CALL CsvFormatter::formatMultiColumn(const Sequence< OUString>& column_data) throw (RuntimeException)
307 sal_Int32 columns = column_data.getLength();
308 OUStringBuffer buf;
309 for(int i=0; i<columns; i++)
311 appendEncodedString(buf, column_data[i]);
312 buf.append(comma_char);
314 buf.setLength(buf.getLength()-1);
315 return buf.makeStringAndClear();
318 ::sal_Bool SAL_CALL CsvFormatter::supportsService( const OUString& service_name ) throw(RuntimeException)
320 const Sequence< OUString > aServiceNames( getSupportedServiceNames() );
321 for ( const OUString* pServiceNames = aServiceNames.getConstArray();
322 pServiceNames != aServiceNames.getConstArray() + aServiceNames.getLength();
323 ++pServiceNames
325 if ( service_name == *pServiceNames )
326 return sal_True;
327 return sal_False;
330 OUString SAL_CALL CsvFormatter::getImplementationName() throw(RuntimeException)
332 return getImplementationName_static();
335 Sequence< OUString > SAL_CALL CsvFormatter::getSupportedServiceNames() throw(RuntimeException)
337 return getSupportedServiceNames_static();
340 OUString SAL_CALL CsvFormatter::getImplementationName_static()
342 return OUString( "com.sun.star.comp.extensions.CsvFormatter" );
345 Sequence< OUString > SAL_CALL CsvFormatter::getSupportedServiceNames_static()
347 Sequence< OUString > aServiceNames(1);
348 aServiceNames[0] = OUString( "com.sun.star.logging.CsvFormatter" );
349 return aServiceNames;
352 Reference< XInterface > CsvFormatter::Create( const Reference< XComponentContext >& context )
354 return *( new CsvFormatter( context ) );
357 void createRegistryInfo_CsvFormatter()
359 static OAutoRegistration< CsvFormatter > aAutoRegistration;
361 } // namespace logging
363 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */