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,90 @@ 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+ if (fImmediate || ArchiveCheckDate > PrevArchiveCheckDate)
204+ {
205+ {
206+ LOCK (cs_log);
207+
208+ if (logfile.is_open ())
209+ {
210+ logfile.flush ();
211+ logfile.close ();
212+ }
213+
214+ plogfile = pathDataDir / " scraper.log" ;
215+ pfile_temp = pathDataDir / (" scraper-" + DateTimeStrFormat (" %Y%m%d%H%M%S" , nTime) + " .log" );
216+ pfile_out = pathDataDir / (" scraper-" + DateTimeStrFormat (" %Y%m%d%H%M%S" , nTime) + " .log.gz" );
217+
218+ try
219+ {
220+ fs::rename (plogfile, pfile_temp);
221+ }
222+ catch (...)
223+ {
224+ LogPrintf (" ERROR: Scraper: Logger: Failed to rename logging file\n " );
225+ return false ;
226+ }
227+
228+ PrevArchiveCheckDate = ArchiveCheckDate;
229+ }
230+
231+ std::ifstream infile (pfile_temp.string ().c_str (), std::ios_base::in | std::ios_base::binary);
232+
233+ if (!infile)
234+ {
235+ LogPrintf (" ERROR: logger: Failed to open archive log file for compression %s." , pfile_temp.string ());
236+ return false ;
237+ }
238+
239+ std::ofstream outgzfile (pfile_out.string ().c_str (), std::ios_base::out | std::ios_base::binary);
240+
241+ if (!outgzfile)
242+ {
243+ LogPrintf (" ERROR: logger: Failed to open archive gzip file %s." , pfile_out.string ());
244+ return false ;
245+ }
246+
247+ boostio::filtering_ostream out;
248+ out.push (boostio::gzip_compressor ());
249+ out.push (outgzfile);
250+
251+ boost::iostreams::copy (infile, out);
252+
253+ infile.close ();
254+ outgzfile.flush ();
255+ outgzfile.close ();
256+
257+ fs::remove (pfile_temp);
258+
259+ return true ;
260+ }
261+ else
262+ return false ;
263+ }
180264};
181265
266+ boost::gregorian::date logger::PrevArchiveCheckDate = boost::posix_time::from_time_t (GetAdjustedTime()).date();
267+ CCriticalSection logger::cs_log;
268+
269+
182270
183271void _log (logattribute eType, const std::string& sCall , const std::string& sMessage )
184272{
@@ -555,6 +643,7 @@ void Scraper(bool bSingleShot)
555643 _log (logattribute::INFO, " Scraper" , " Running in single shot mode." );
556644
557645 // This is necessary to maintain compatibility with Windows.
646+ pathDataDir.imbue (std::locale (std::locale (), new std::codecvt_utf8_utf16<wchar_t >()));
558647 pathScraper.imbue (std::locale (std::locale (), new std::codecvt_utf8_utf16<wchar_t >()));
559648
560649 // Hash check
@@ -932,6 +1021,13 @@ bool ScraperHousekeeping()
9321021 + " , Popularity: " + std::to_string (network_hash.second ));
9331022 }
9341023
1024+ logger log;
1025+
1026+ fs::path plogfile_out;
1027+
1028+ if (log.archive (false , plogfile_out))
1029+ _log (logattribute::INFO, " ScraperHousekeeping" , " Archived scraper.log to " + plogfile_out.string ());
1030+
9351031 return true ;
9361032}
9371033
@@ -4229,3 +4325,24 @@ UniValue deletecscrapermanifest(const UniValue& params, bool fHelp)
42294325}
42304326
42314327
4328+ UniValue archivescraperlog (const UniValue& params, bool fHelp )
4329+ {
4330+ if (fHelp || params.size () != 0 )
4331+ throw std::runtime_error (
4332+ " archivescraperlog takes no arguments and results in immediate archiving of the scraper log\n "
4333+ );
4334+
4335+ logger log;
4336+
4337+ fs::path pfile_out;
4338+ bool ret = log.archive (true , pfile_out);
4339+
4340+ if (!ret)
4341+ return UniValue (ret);
4342+ else
4343+ return UniValue (pfile_out.c_str ());
4344+
4345+ return UniValue (ret);
4346+ }
4347+
4348+
0 commit comments