1 #ifndef DEBUG_H
2 #define DEBUG_H
3 
4 #include <iostream>
5 #include "Util.h"
6 #include "Timer.h"
7 #include "MathUtil.h"
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <cstddef>
11 #include <sys/stat.h>
12 
13 class TtyCheck {
14 public:
TtyCheck()15     TtyCheck()  {
16         tty = false;
17 
18         bool stdoutIsTty = isatty(fileno(stdout));
19         bool stderrtIsTty = isatty(fileno(stderr));
20         struct stat stats;
21         fstat(fileno(stdin), &stats);
22         bool isChr = S_ISCHR (stats.st_mode) == true; // is terminal
23         bool isFifo = S_ISFIFO(stats.st_mode) == false; // is no pipe
24         bool isReg = S_ISREG(stats.st_mode) == false;
25         if (isFifo && stdoutIsTty && stderrtIsTty && isReg && isChr) {
26             tty = true;
27         }
28 
29         char* ttyEnv = getenv("TTY");
30         if(ttyEnv != NULL && strcasecmp(ttyEnv, "1") == 0) {
31             tty = true;
32         }
33         if(ttyEnv != NULL && strcasecmp(ttyEnv, "0") == 0) {
34             tty = false;
35         }
36 
37     };
38     bool tty;
39 };
40 
41 class Debug
42 {
43 
44 public:
45     static const int NOTHING = 0;
46     static const int ERROR = 1;
47     static const int WARNING = 2;
48     static const int INFO = 3;
49 
50     enum Color {
51         FG_RED      = 31,
52         FG_GREEN    = 32,
53         FG_YELLOW    = 33,
54         FG_BLUE     = 34,
55         FG_DEFAULT  = 39,
56         BG_RED      = 41,
57         BG_GREEN    = 42,
58         BG_BLUE     = 44,
59         BG_DEFAULT  = 49
60     };
61 
62     static int debugLevel;
63 
64 
Debug(int level)65     explicit Debug( int level ) : level(level) {
66         static TtyCheck check;
67         interactive = check.tty;
68     };
69 
~Debug()70     ~Debug(){
71         if (level <= ERROR && level <= debugLevel){
72             std::cout << std::flush;
73             if(interactive){
74                 std::cerr << "\033[" << Color::FG_RED << "m" << buffer << "\033[" << Color::FG_DEFAULT << "m";;
75             }else{
76                 std::cerr << buffer;
77             }
78             std::cerr << std::flush;
79         } else if(level == WARNING && level <= debugLevel){
80             if(interactive){
81                 std::cout << "\033[" << Color::FG_YELLOW << "m" << buffer << "\033[" << Color::FG_DEFAULT << "m";
82             }else{
83                 std::cout << buffer;
84             }
85             std::cout << std::flush;
86         } else if(level > WARNING && level <= debugLevel) {
87             std::cout << buffer;
88 //            std::cout << std::flush;
89         }
90     }
91 
92 
93     template<typename T>
94     Debug& operator<<( T t)
95     {
96         buffer.append(SSTR(t));
97         return *this;
98     }
99 
100     Debug& operator<<(double val){
101         char str[64];
102         snprintf(str, sizeof(str), "%f", val);
103         buffer.append(str);
104         return *this;
105     }
106 
107     Debug& operator<<(float val){
108         char str[64];
109         snprintf(str, sizeof(str), "%f", val);
110         buffer.append(str);
111         return *this;
112     }
113     static void setDebugLevel(int i);
114 
115     class Progress{
116     private:
117         size_t currentPos;
118         size_t prevPrintedId;
119         size_t totalEntries;
120         bool interactive;
121         Timer timer;
122 
123         const static int BARWIDTH = 65;
124 
buildItemString(size_t id)125         std::string buildItemString(size_t id){
126             std::string line;
127             unsigned int exp = MathUtil::log10(static_cast<unsigned int>(id+1));
128             unsigned int base = 100;
129 
130             char appending=' ';
131             switch(exp){
132                 case 3:
133                 case 4:
134                 case 5:
135                     base = MathUtil::log10base(1000);
136                     appending = 'K';
137                     break;
138                 case 6:
139                 case 7:
140                 case 8:
141                     base = MathUtil::log10base(1000000);
142                     appending = 'M';
143                     break;
144                 case 9:
145                 case 10:
146                 case 11:
147                     base = MathUtil::log10base(1000000000);
148                     appending = 'B';
149             }
150             char fmtbuffer[32];
151             if(exp < 3){
152                 int fmtElm = sprintf(fmtbuffer, "%d",  static_cast<int>(id+1));
153                 line.append(fmtbuffer, fmtElm);
154             }else{
155                 int fmtElm = sprintf(fmtbuffer, "%.2f", static_cast<float>(id+1)/ static_cast<float>(base));
156                 line.append(fmtbuffer, fmtElm);
157                 line.push_back(appending);
158             }
159             return line;
160         }
161 
162     public:
Progress(size_t totalEntries)163         Progress(size_t totalEntries)
164                 :  currentPos(0), prevPrintedId(0), totalEntries(totalEntries){
165             static TtyCheck check;
166             interactive = check.tty;
167         }
168 
Progress()169         Progress() : currentPos(0),  prevPrintedId(0), totalEntries(SIZE_MAX){
170             static TtyCheck check;
171             interactive = check.tty;
172         }
173 
reset(size_t totalEntries)174         void reset(size_t totalEntries) {
175             this->totalEntries = totalEntries;
176             currentPos = 0;
177             prevPrintedId = 0;
178         }
179 
updateProgress()180         void updateProgress(){
181             size_t id = __sync_fetch_and_add(&currentPos, 1);
182             // if no active terminal exists write dots
183             if(interactive == false){
184                 if(totalEntries==SIZE_MAX) {
185                     if(id==0) {
186                         Debug(INFO) << '[';
187                     }
188                     if (id % 1000000 == 0 && id > 0){
189                         Debug(INFO) << "\t" << (id / 1000000) << " Mio. sequences processed\n";
190                         fflush(stdout);
191                     }
192                     else if (id % 10000 == 0 && id > 0) {
193                         Debug(INFO) << "=";
194                         fflush(stdout);
195                     }
196                 }else{
197                     if(id==0) {
198                         Debug(INFO) << '[';
199                     }
200                     float progress = (totalEntries==1) ? 1.0 : (static_cast<float>(id) / static_cast<float>(totalEntries-1));
201                     float prevPrintedProgress = (totalEntries==1 || id == 0) ? 0.0 : (static_cast<float>(id-1) / static_cast<float>(totalEntries-1));
202                     int prevPos = BARWIDTH * prevPrintedProgress;
203                     int pos     = BARWIDTH * progress;
204                     for (int write = prevPos; write < pos; write++) {
205                         Debug(INFO) << '=';
206                         fflush(stdout);
207                     }
208 
209                     if(id == (totalEntries - 1) ){
210                         Debug(INFO) << "] ";
211                         Debug(INFO) << buildItemString(id);
212                         Debug(INFO) << " ";
213                         Debug(INFO) << timer.lapProgress();
214                         Debug(INFO) << "\n";
215                     }
216                 }
217             }else{
218                 if(totalEntries==SIZE_MAX){
219                     if(id > prevPrintedId + 100) {
220                         std::string line;
221                         line.push_back('[');
222                         line.append(SSTR(id+1));
223                         line.append("] ");
224                         line.append(timer.lapProgress());
225                         line.push_back('\r');
226                         Debug(Debug::INFO) << line;
227                         fflush(stdout);
228                         prevPrintedId = id;
229                     }
230                 }else{
231                     float progress = (totalEntries==1) ? 1.0 : (static_cast<float>(id) / static_cast<float>(totalEntries-1));
232                     float prevPrintedProgress = (totalEntries==1) ? 0.0 : (static_cast<float>(prevPrintedId) / static_cast<float>(totalEntries-1));
233                     if(progress-prevPrintedProgress > 0.01 || id == (totalEntries - 1)  || id == 0 ){
234                         std::string line;
235                         line.push_back('[');
236                         int pos = BARWIDTH * progress;
237                         for (int i = 0; i < BARWIDTH; ++i) {
238                             if (i < pos) {
239                                 line.push_back('=');
240                             }else if (i == pos) {
241                                 line.push_back('>');
242                             } else {
243                                 line.push_back(' ');
244                             }
245                         }
246                         char buffer[32];
247                         int n = sprintf(buffer, "%.2f", progress * 100.0f);
248                         line.append("] ");
249                         line.append(buffer, n);
250                         line.append("% ");
251                         line.append(buildItemString(id));
252                         line.push_back(' ');
253                         if(id == 0){
254                             line.append("eta -");
255                         }else if(id == (totalEntries - 1) ){
256                             line.append(timer.lapProgress());
257                         }else{
258                             double timeDiff = timer.getTimediff();
259                             double eta = (timeDiff/progress * 1.0) - timeDiff;
260                             long long sec = (time_t)eta;
261 //                            long long msec = (time_t)((eta - sec) * 1e3);
262 //                            std::cout << timeDiff << "\t" << progress << std::endl;
263                             line.append("eta ");
264                             if(sec >= 3600){
265                                 line.append(SSTR(sec / 3600));
266                                 line.append("h ");
267                             }
268                             if(sec >= 60){
269                                 line.append(SSTR( (sec % 3600 / 60)));
270                                 line.append("m ");
271                             }
272                             line.append(SSTR(sec % 60));
273                             // need to overwrite the rest
274                             line.append("s       ");
275                         }
276                         //printf("%zu\t%zu\t%f\n", id, totalEntries, progress);
277                         line.push_back((id == (totalEntries - 1) ) ? '\n' : '\r' );
278                         Debug(Debug::INFO) << line;
279                         fflush(stdout);
280                         prevPrintedId=id;
281                     }
282                 }
283             }
284         }
285     };
286 
287 
288 
289 
290 private:
291     const int level;
292     std::string buffer;
293     bool interactive;
294 };
295 
296 
297 
298 #endif
299