14
14
#include < boost/exception/diagnostic_information.hpp>
15
15
#include < boost/iostreams/stream.hpp>
16
16
#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>
17
20
18
- fs::path pathScraper = fs::current_path() / " Scraper" ;
21
+ fs::path pathDataDir = GetDataDir();
22
+ fs::path pathScraper = pathDataDir / " Scraper" ;
19
23
20
24
extern bool fShutdown ;
21
25
extern bool fDebug ;
@@ -144,25 +148,32 @@ extern std::string PackBinarySuperblock(std::string sBlock);
144
148
145
149
class logger
146
150
{
151
+
147
152
private:
148
153
149
- // std::ofstream logfile;
154
+ static CCriticalSection cs_log;
155
+
156
+ static boost::gregorian::date PrevArchiveCheckDate;
157
+
150
158
fs::ofstream logfile;
151
159
152
160
public:
153
161
154
162
logger ()
155
163
{
156
- fs::path plogfile = GetDataDir () / " scraper.log " ;
164
+ LOCK (cs_log) ;
157
165
166
+ fs::path plogfile = pathDataDir / " scraper.log" ;
158
167
logfile.open (plogfile.c_str (), std::ios_base::out | std::ios_base::app);
159
168
160
169
if (!logfile.is_open ())
161
- printf ( " Logging : Failed to open logging file\n " );
170
+ LogPrintf ( " ERROR: Scraper: Logger : Failed to open logging file\n " );
162
171
}
163
172
164
173
~logger ()
165
174
{
175
+ LOCK (cs_log);
176
+
166
177
if (logfile.is_open ())
167
178
{
168
179
logfile.flush ();
@@ -172,13 +183,90 @@ class logger
172
183
173
184
void output (const std::string& tofile)
174
185
{
186
+ LOCK (cs_log);
187
+
175
188
if (logfile.is_open ())
176
189
logfile << tofile << std::endl;
177
190
178
191
return ;
179
192
}
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
+ }
180
264
};
181
265
266
+ boost::gregorian::date logger::PrevArchiveCheckDate = boost::posix_time::from_time_t (GetAdjustedTime()).date();
267
+ CCriticalSection logger::cs_log;
268
+
269
+
182
270
183
271
void _log (logattribute eType, const std::string& sCall , const std::string& sMessage )
184
272
{
@@ -555,6 +643,7 @@ void Scraper(bool bSingleShot)
555
643
_log (logattribute::INFO, " Scraper" , " Running in single shot mode." );
556
644
557
645
// This is necessary to maintain compatibility with Windows.
646
+ pathDataDir.imbue (std::locale (std::locale (), new std::codecvt_utf8_utf16<wchar_t >()));
558
647
pathScraper.imbue (std::locale (std::locale (), new std::codecvt_utf8_utf16<wchar_t >()));
559
648
560
649
// Hash check
@@ -932,6 +1021,13 @@ bool ScraperHousekeeping()
932
1021
+ " , Popularity: " + std::to_string (network_hash.second ));
933
1022
}
934
1023
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
+
935
1031
return true ;
936
1032
}
937
1033
@@ -4229,3 +4325,24 @@ UniValue deletecscrapermanifest(const UniValue& params, bool fHelp)
4229
4325
}
4230
4326
4231
4327
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