1414#include < boost/exception/diagnostic_information.hpp>
1515#include < boost/iostreams/stream.hpp>
1616#include < boost/iostreams/device/array.hpp>
17+ #include < boost/date_time.hpp>
18+ #include < boost/date_time/gregorian/gregorian.hpp>
19+ #include < boost/date_time/gregorian/greg_date.hpp>
1720
18- fs::path pathScraper = fs::current_path() / " Scraper" ;
21+ fs::path pathDataDir = fs::current_path();
22+ fs::path pathScraper = pathDataDir / " Scraper" ;
1923
2024extern bool fShutdown ;
2125extern bool fDebug ;
@@ -144,25 +148,32 @@ extern std::string PackBinarySuperblock(std::string sBlock);
144148
145149class logger
146150{
151+
147152private:
148153
149- // std::ofstream logfile;
154+ static CCriticalSection cs_log;
155+
156+ static boost::gregorian::date PrevArchiveCheckDate;
157+
150158 fs::ofstream logfile;
151159
152160public:
153161
154162 logger ()
155163 {
156- fs::path plogfile = GetDataDir () / " scraper.log " ;
164+ LOCK (cs_log) ;
157165
166+ fs::path plogfile = pathDataDir / " scraper.log" ;
158167 logfile.open (plogfile.c_str (), std::ios_base::out | std::ios_base::app);
159168
160169 if (!logfile.is_open ())
161- printf ( " Logging : Failed to open logging file\n " );
170+ LogPrintf ( " ERROR: Scraper: Logger : Failed to open logging file\n " );
162171 }
163172
164173 ~logger ()
165174 {
175+ LOCK (cs_log);
176+
166177 if (logfile.is_open ())
167178 {
168179 logfile.flush ();
@@ -172,13 +183,97 @@ class logger
172183
173184 void output (const std::string& tofile)
174185 {
186+ LOCK (cs_log);
187+
175188 if (logfile.is_open ())
176189 logfile << tofile << std::endl;
177190
178191 return ;
179192 }
193+
194+
195+
196+ bool archive (bool fImmediate , fs::path pfile_out)
197+ {
198+ int64_t nTime = GetAdjustedTime ();
199+ boost::gregorian::date ArchiveCheckDate = boost::posix_time::from_time_t (nTime).date ();
200+ fs::path plogfile;
201+ fs::path pfile_temp;
202+
203+ std::stringstream ssArchiveCheckDate, ssPrevArchiveCheckDate;
204+
205+ ssArchiveCheckDate << ArchiveCheckDate;
206+ ssPrevArchiveCheckDate << PrevArchiveCheckDate;
207+
208+ if (fDebug ) LogPrintf (" INFO: Scraper: Logger: ArchiveCheckDate %s, PrevArchiveCheckDate %s" , ssArchiveCheckDate.str (), ssPrevArchiveCheckDate.str ());
209+
210+ if (fImmediate || ArchiveCheckDate > PrevArchiveCheckDate)
211+ {
212+ {
213+ LOCK (cs_log);
214+
215+ if (logfile.is_open ())
216+ {
217+ logfile.flush ();
218+ logfile.close ();
219+ }
220+
221+ plogfile = pathDataDir / " scraper.log" ;
222+ pfile_temp = pathDataDir / (" scraper-" + DateTimeStrFormat (" %Y%m%d%H%M%S" , nTime) + " .log" );
223+ pfile_out = pathDataDir / (" scraper-" + DateTimeStrFormat (" %Y%m%d%H%M%S" , nTime) + " .log.gz" );
224+
225+ try
226+ {
227+ fs::rename (plogfile, pfile_temp);
228+ }
229+ catch (...)
230+ {
231+ LogPrintf (" ERROR: Scraper: Logger: Failed to rename logging file\n " );
232+ return false ;
233+ }
234+
235+ PrevArchiveCheckDate = ArchiveCheckDate;
236+ }
237+
238+ std::ifstream infile (pfile_temp.string ().c_str (), std::ios_base::in | std::ios_base::binary);
239+
240+ if (!infile)
241+ {
242+ LogPrintf (" ERROR: logger: Failed to open archive log file for compression %s." , pfile_temp.string ());
243+ return false ;
244+ }
245+
246+ std::ofstream outgzfile (pfile_out.string ().c_str (), std::ios_base::out | std::ios_base::binary);
247+
248+ if (!outgzfile)
249+ {
250+ LogPrintf (" ERROR: logger: Failed to open archive gzip file %s." , pfile_out.string ());
251+ return false ;
252+ }
253+
254+ boostio::filtering_ostream out;
255+ out.push (boostio::gzip_compressor ());
256+ out.push (outgzfile);
257+
258+ boost::iostreams::copy (infile, out);
259+
260+ infile.close ();
261+ outgzfile.flush ();
262+ outgzfile.close ();
263+
264+ fs::remove (pfile_temp);
265+
266+ return true ;
267+ }
268+ else
269+ return false ;
270+ }
180271};
181272
273+ boost::gregorian::date logger::PrevArchiveCheckDate = boost::posix_time::from_time_t (GetAdjustedTime()).date();
274+ CCriticalSection logger::cs_log;
275+
276+
182277
183278void _log (logattribute eType, const std::string& sCall , const std::string& sMessage )
184279{
@@ -555,6 +650,7 @@ void Scraper(bool bSingleShot)
555650 _log (logattribute::INFO, " Scraper" , " Running in single shot mode." );
556651
557652 // This is necessary to maintain compatibility with Windows.
653+ pathDataDir.imbue (std::locale (std::locale (), new std::codecvt_utf8_utf16<wchar_t >()));
558654 pathScraper.imbue (std::locale (std::locale (), new std::codecvt_utf8_utf16<wchar_t >()));
559655
560656 // Hash check
@@ -643,6 +739,15 @@ void Scraper(bool bSingleShot)
643739 if (fDebug3 ) _log (logattribute::INFO, " ENDLOCK" , " cs_Scraper" );
644740 }
645741
742+ // Need the log archive check here, because we don't run housekeeping in this while loop.
743+ logger log;
744+
745+ fs::path plogfile_out;
746+
747+ if (log.archive (false , plogfile_out))
748+ _log (logattribute::INFO, " Scraper" , " Archived scraper.log to " + plogfile_out.string ());
749+
750+
646751 sbage = data.sbage ();
647752 _log (logattribute::INFO, " Scraper" , " Superblock not needed. age=" + std::to_string (sbage));
648753 _log (logattribute::INFO, " Scraper" , " Sleeping for " + std::to_string (nScraperSleep / 1000 ) +" seconds" );
@@ -932,6 +1037,13 @@ bool ScraperHousekeeping()
9321037 + " , Popularity: " + std::to_string (network_hash.second ));
9331038 }
9341039
1040+ logger log;
1041+
1042+ fs::path plogfile_out;
1043+
1044+ if (log.archive (false , plogfile_out))
1045+ _log (logattribute::INFO, " ScraperHousekeeping" , " Archived scraper.log to " + plogfile_out.string ());
1046+
9351047 return true ;
9361048}
9371049
@@ -4229,3 +4341,24 @@ UniValue deletecscrapermanifest(const UniValue& params, bool fHelp)
42294341}
42304342
42314343
4344+ UniValue archivescraperlog (const UniValue& params, bool fHelp )
4345+ {
4346+ if (fHelp || params.size () != 0 )
4347+ throw std::runtime_error (
4348+ " archivescraperlog takes no arguments and results in immediate archiving of the scraper log\n "
4349+ );
4350+
4351+ logger log;
4352+
4353+ fs::path pfile_out;
4354+ bool ret = log.archive (true , pfile_out);
4355+
4356+ if (!ret)
4357+ return UniValue (ret);
4358+ else
4359+ return UniValue (pfile_out.c_str ());
4360+
4361+ return UniValue (ret);
4362+ }
4363+
4364+
0 commit comments