1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
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>
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
57 class CsvFormatter
: public CsvFormatter_Base
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
);
68 CsvFormatter( const Reference
< XComponentContext
>& context
);
69 virtual ~CsvFormatter();
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
);
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
);
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
);
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
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)
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();
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
);
140 buf
.insert(buf_offset
+ i
, quote_char
);
142 buf
.append(quote_char
);
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");
156 //= CsvFormatter - implementation
159 CsvFormatter::CsvFormatter( const Reference
< XComponentContext
>& context
)
160 :m_aContext( context
),
163 m_LogTimestamp(true),
165 m_MultiColumn(false),
166 m_Columnnames(initialColumns())
169 CsvFormatter::~CsvFormatter()
172 ::sal_Bool
CsvFormatter::getLogEventNo() throw (RuntimeException
)
177 ::sal_Bool
CsvFormatter::getLogThread() throw (RuntimeException
)
182 ::sal_Bool
CsvFormatter::getLogTimestamp() throw (RuntimeException
)
184 return m_LogTimestamp
;
187 ::sal_Bool
CsvFormatter::getLogSource() throw (RuntimeException
)
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
)
227 buf
.appendAscii("event no,");
229 buf
.appendAscii("thread,");
231 buf
.appendAscii("timestamp,");
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
;
251 aLogEntry
.append( record
.SequenceNumber
);
252 aLogEntry
.append(comma_char
);
257 aLogEntry
.append( record
.ThreadID
);
258 aLogEntry
.append(comma_char
);
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
);
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
292 aLogEntry
.append(record
.Message
);
294 appendEncodedString(aLogEntry
, record
.Message
);
296 aLogEntry
.append( dos_newline
);
297 return aLogEntry
.makeStringAndClear();
300 OUString SAL_CALL
CsvFormatter::getTail( ) throw (RuntimeException
)
305 OUString SAL_CALL
CsvFormatter::formatMultiColumn(const Sequence
< OUString
>& column_data
) throw (RuntimeException
)
307 sal_Int32 columns
= column_data
.getLength();
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();
325 if ( service_name
== *pServiceNames
)
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: */