2015-12-31 06:39:56 +00:00
// Copyright (c) 2014-2016, The Monero Project
2015-05-31 11:40:18 +00:00
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2015-02-12 19:59:39 +00:00
# include "data_logger.hpp"
2015-02-24 19:12:56 +00:00
# include <stdexcept>
2015-02-12 19:59:39 +00:00
# include <boost/chrono.hpp>
2015-02-20 21:28:03 +00:00
# include <boost/filesystem.hpp>
2016-02-18 21:30:10 +00:00
# include <boost/thread.hpp>
2015-02-12 19:59:39 +00:00
# include <chrono>
2016-03-19 21:48:36 +00:00
# include "common/exception.h"
2015-02-20 21:28:03 +00:00
# include "../../contrib/otshell_utils/utils.hpp"
2015-02-12 19:59:39 +00:00
namespace epee
{
namespace net_utils
{
2015-02-24 19:12:56 +00:00
data_logger & data_logger : : get_instance ( ) {
2016-03-11 12:25:28 +00:00
boost : : call_once ( m_singleton ,
2015-02-24 19:12:56 +00:00
[ ] {
_info_c ( " dbg/data " , " Creating singleton of data_logger " ) ;
2016-03-19 21:48:36 +00:00
if ( m_state ! = data_logger_state : : state_before_init ) { _erro_c ( " dbg/data " , " Internal error in singleton " ) ; throw tools : : runtime_error ( " data_logger singleton " ) ; }
2015-02-24 19:12:56 +00:00
m_state = data_logger_state : : state_during_init ;
m_obj . reset ( new data_logger ( ) ) ;
m_state = data_logger_state : : state_ready_to_use ;
}
) ;
2015-02-24 20:02:48 +00:00
if ( m_state ! = data_logger_state : : state_ready_to_use ) {
_erro ( " trying to use not working data_logger " ) ;
2016-03-19 21:48:36 +00:00
throw tools : : runtime_error ( " data_logger ctor state " ) ;
2015-02-24 20:02:48 +00:00
}
2015-02-24 19:12:56 +00:00
return * m_obj ;
2015-02-12 19:59:39 +00:00
}
2015-02-24 19:12:56 +00:00
data_logger : : data_logger ( ) {
2015-04-02 14:27:19 +00:00
_note_c ( " dbg/data " , " Starting data logger (for graphs data) " ) ;
2016-03-19 21:48:36 +00:00
if ( m_state ! = data_logger_state : : state_during_init ) { _erro_c ( " dbg/data " , " Singleton ctor state " ) ; throw tools : : runtime_error ( " data_logger ctor state " ) ; }
2016-03-11 12:25:28 +00:00
boost : : lock_guard < boost : : mutex > lock ( mMutex ) ; // lock
2015-02-12 19:59:39 +00:00
2015-02-24 19:12:56 +00:00
// prepare all the files for given data channels:
2015-02-12 19:59:39 +00:00
mFilesMap [ " peers " ] = data_logger : : fileData ( " log/dr-monero/peers.data " ) ;
mFilesMap [ " download " ] = data_logger : : fileData ( " log/dr-monero/net/in-all.data " ) ;
mFilesMap [ " upload " ] = data_logger : : fileData ( " log/dr-monero/net/out-all.data " ) ;
mFilesMap [ " request " ] = data_logger : : fileData ( " log/dr-monero/net/req-all.data " ) ;
mFilesMap [ " sleep_down " ] = data_logger : : fileData ( " log/dr-monero/down_sleep_log.data " ) ;
mFilesMap [ " sleep_up " ] = data_logger : : fileData ( " log/dr-monero/up_sleep_log.data " ) ;
2015-02-20 21:28:03 +00:00
mFilesMap [ " calc_time " ] = data_logger : : fileData ( " log/dr-monero/get_objects_calc_time.data " ) ;
mFilesMap [ " blockchain_processing_time " ] = data_logger : : fileData ( " log/dr-monero/blockchain_log.data " ) ;
2015-04-01 17:00:45 +00:00
mFilesMap [ " block_processing " ] = data_logger : : fileData ( " log/dr-monero/block_proc.data " ) ;
2015-02-12 19:59:39 +00:00
2015-02-20 21:28:03 +00:00
mFilesMap [ " peers_limit " ] = data_logger : : fileData ( " log/dr-monero/peers_limit.info " ) ;
mFilesMap [ " download_limit " ] = data_logger : : fileData ( " log/dr-monero/limit_down.info " ) ;
mFilesMap [ " upload_limit " ] = data_logger : : fileData ( " log/dr-monero/limit_up.info " ) ;
mFilesMap [ " peers_limit " ] . mLimitFile = true ;
mFilesMap [ " download_limit " ] . mLimitFile = true ;
mFilesMap [ " upload_limit " ] . mLimitFile = true ;
2015-02-24 19:12:56 +00:00
// do NOT modify mFilesMap below this point, since there is no locking for this used (yet)
2015-04-02 14:27:19 +00:00
_info_c ( " dbg/data " , " Creating thread for data logger " ) ; // create timer thread
2015-02-24 19:12:56 +00:00
m_thread_maybe_running = true ;
2016-02-18 21:30:10 +00:00
std : : shared_ptr < boost : : thread > logger_thread ( new boost : : thread ( [ & ] ( ) {
2015-04-02 14:27:19 +00:00
_info_c ( " dbg/data " , " Inside thread for data logger " ) ;
2015-02-24 19:12:56 +00:00
while ( m_state = = data_logger_state : : state_during_init ) { // wait for creation to be done (in other thread, in singleton) before actually running
2016-03-11 12:25:28 +00:00
boost : : this_thread : : sleep_for ( boost : : chrono : : seconds ( 1 ) ) ;
2015-02-24 19:12:56 +00:00
}
2015-04-02 14:27:19 +00:00
_info_c ( " dbg/data " , " Inside thread for data logger - going into main loop " ) ;
2015-02-24 19:12:56 +00:00
while ( m_state = = data_logger_state : : state_ready_to_use ) { // run as long as we are not closing the single object
2016-03-11 12:25:28 +00:00
boost : : this_thread : : sleep_for ( boost : : chrono : : seconds ( 1 ) ) ;
2015-02-24 19:12:56 +00:00
saveToFile ( ) ; // save all the pending data
}
2015-04-02 14:27:19 +00:00
_info_c ( " dbg/data " , " Inside thread for data logger - done the main loop " ) ;
2015-02-24 19:12:56 +00:00
m_thread_maybe_running = false ;
} ) ) ;
logger_thread - > detach ( ) ;
_info_c ( " dbg/data " , " Data logger constructed " ) ;
}
data_logger : : ~ data_logger ( ) {
_note_c ( " dbg/data " , " Destructor of the data logger " ) ;
{
2016-03-11 12:25:28 +00:00
boost : : lock_guard < boost : : mutex > lock ( mMutex ) ;
2015-02-24 19:12:56 +00:00
m_state = data_logger_state : : state_dying ;
}
_info_c ( " dbg/data " , " State was set to dying " ) ;
while ( m_thread_maybe_running ) { // wait for the thread to exit
2016-03-11 12:25:28 +00:00
boost : : this_thread : : sleep_for ( boost : : chrono : : seconds ( 1 ) ) ;
2015-02-24 19:12:56 +00:00
_info_c ( " dbg/data " , " Waiting for background thread to exit " ) ;
}
_info_c ( " dbg/data " , " Thread exited " ) ;
}
void data_logger : : kill_instance ( ) {
2015-02-24 20:02:48 +00:00
m_state = data_logger_state : : state_dying ;
2015-02-24 19:12:56 +00:00
m_obj . reset ( ) ;
2015-02-12 19:59:39 +00:00
}
2015-02-24 19:12:56 +00:00
void data_logger : : add_data ( std : : string filename , unsigned int data ) {
2016-03-11 12:25:28 +00:00
boost : : lock_guard < boost : : mutex > lock ( mMutex ) ;
2015-02-24 19:12:56 +00:00
if ( m_state ! = data_logger_state : : state_ready_to_use ) { _info_c ( " dbg/data " , " Data logger is not ready, returning. " ) ; return ; }
if ( mFilesMap . find ( filename ) = = mFilesMap . end ( ) ) { // no such file/counter
_erro_c ( " dbg/data " , " Trying to use not opened data file filename= " < < filename ) ;
_erro_c ( " dbg/data " , " Disabling saving of graphs due to error " ) ;
m_save_graph = false ; // <--- disabling saving graphs
return ;
}
2015-02-20 21:28:03 +00:00
2015-02-24 19:12:56 +00:00
if ( mFilesMap [ filename ] . mLimitFile ) { // this holds a number (that is not additive) - e.g. the limit setting
2015-02-20 21:28:03 +00:00
mFilesMap [ filename ] . mDataToSave = data ;
2015-02-24 19:12:56 +00:00
} else {
mFilesMap [ filename ] . mDataToSave + = data ; // this holds a number that should be sum of all accumulated samples
}
}
2015-04-01 17:00:45 +00:00
bool data_logger : : is_dying ( ) {
if ( m_state = = data_logger_state : : state_dying ) {
return true ;
}
else {
return false ;
}
}
2015-02-24 19:12:56 +00:00
void data_logger : : saveToFile ( ) {
_dbg2_c ( " dbg/data " , " saving to files " ) ;
2016-03-11 12:25:28 +00:00
boost : : lock_guard < boost : : mutex > lock ( mMutex ) ;
2015-02-24 19:12:56 +00:00
if ( m_state ! = data_logger_state : : state_ready_to_use ) { _info_c ( " dbg/data " , " Data logger is not ready, returning. " ) ; return ; }
nOT : : nUtils : : cFilesystemUtils : : CreateDirTree ( " log/dr-monero/net/ " ) ;
for ( auto & element : mFilesMap )
{
element . second . save ( ) ;
if ( ! element . second . mLimitFile ) element . second . mDataToSave = 0 ;
}
2015-02-12 19:59:39 +00:00
}
2015-02-24 19:12:56 +00:00
// the inner class:
2015-02-12 19:59:39 +00:00
2015-02-24 19:12:56 +00:00
double data_logger : : fileData : : get_current_time ( ) {
2015-04-01 17:00:45 +00:00
# if defined(__APPLE__)
auto point = std : : chrono : : system_clock : : now ( ) ;
# else
auto point = std : : chrono : : steady_clock : : now ( ) ;
# endif
2015-02-12 19:59:39 +00:00
auto time_from_epoh = point . time_since_epoch ( ) ;
2015-04-01 17:00:45 +00:00
auto ms = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( time_from_epoh ) . count ( ) ;
2015-02-12 19:59:39 +00:00
double ms_f = ms ;
return ms_f / 1000. ;
}
2015-02-24 19:12:56 +00:00
data_logger : : fileData : : fileData ( std : : string pFile ) {
_dbg3_c ( " dbg/data " , " opening data file named pFile= " < < pFile < < " for this= " < < this ) ;
2015-02-12 19:59:39 +00:00
mFile = std : : make_shared < std : : ofstream > ( pFile ) ;
2015-02-24 19:12:56 +00:00
_dbg1_c ( " dbg/data " , " opened data file named pFile= " < < pFile < < " in mFile= " < < mFile < < " for this= " < < this ) ;
2015-02-20 21:28:03 +00:00
mPath = pFile ;
2015-02-12 19:59:39 +00:00
}
2015-02-24 19:12:56 +00:00
void data_logger : : fileData : : save ( ) {
if ( ! data_logger : : m_save_graph ) return ; // <--- disabled
_dbg2_c ( " dbg/data " , " saving to the file now, mFile= " < < mFile ) ;
2015-02-20 21:28:03 +00:00
mFile - > open ( mPath , std : : ios : : app ) ;
2015-02-12 19:59:39 +00:00
* mFile < < static_cast < int > ( get_current_time ( ) ) < < " " < < mDataToSave < < std : : endl ;
2015-02-20 21:28:03 +00:00
mFile - > close ( ) ;
2015-02-12 19:59:39 +00:00
}
2015-02-24 19:12:56 +00:00
data_logger_state data_logger : : m_state ( data_logger_state : : state_before_init ) ; ///< (static) state of the singleton object
std : : atomic < bool > data_logger : : m_save_graph ( false ) ; // (static)
std : : atomic < bool > data_logger : : m_thread_maybe_running ( false ) ; // (static)
2016-03-11 12:25:28 +00:00
boost : : once_flag data_logger : : m_singleton ; // (static)
2015-02-24 19:12:56 +00:00
std : : unique_ptr < data_logger > data_logger : : m_obj ; // (static)
2015-02-12 19:59:39 +00:00
} // namespace
} // namespace
2015-02-24 19:12:56 +00:00