00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #pragma once
00019
00020 #include "log.h"
00021 #include "mongoutils/html.h"
00022
00023 namespace mongo {
00024
00025 class RamLog : public Tee {
00026 enum {
00027 N = 128,
00028 C = 256
00029 };
00030 char lines[N][C];
00031 unsigned h, n;
00032
00033 public:
00034 RamLog() {
00035 h = 0; n = 0;
00036 for( int i = 0; i < N; i++ )
00037 lines[i][C-1] = 0;
00038 }
00039
00040 virtual void write(LogLevel ll, const string& str) {
00041 char *p = lines[(h+n)%N];
00042 if( str.size() < C )
00043 strcpy(p, str.c_str());
00044 else
00045 memcpy(p, str.c_str(), C-1);
00046 if( n < N ) n++;
00047 else h = (h+1) % N;
00048 }
00049
00050 void get( vector<const char*>& v) const {
00051 for( unsigned x=0, i=h; x++ < n; i=(i+1)%N )
00052 v.push_back(lines[i]);
00053 }
00054
00055 static int repeats(const vector<const char *>& v, int i) {
00056 for( int j = i-1; j >= 0 && j+8 > i; j-- ) {
00057 if( strcmp(v[i]+20,v[j]+20) == 0 ) {
00058 for( int x = 1; ; x++ ) {
00059 if( j+x == i ) return j;
00060 if( i+x>=(int) v.size() ) return -1;
00061 if( strcmp(v[i+x]+20,v[j+x]+20) ) return -1;
00062 }
00063 return -1;
00064 }
00065 }
00066 return -1;
00067 }
00068
00069
00070 static string clean(const vector<const char *>& v, int i, string line="") {
00071 if( line.empty() ) line = v[i];
00072 if( i > 0 && strncmp(v[i], v[i-1], 11) == 0 )
00073 return string(" ") + line.substr(11);
00074 return v[i];
00075 }
00076
00077 static string color(string line) {
00078 string s = str::after(line, "replSet ");
00079 if( str::startsWith(s, "warning") || startsWith(s, "error") )
00080 return html::red(line);
00081 if( str::startsWith(s, "info") ) {
00082 if( str::endsWith(s, " up\n") )
00083 return html::green(line);
00084 else if( str::contains(s, " down ") || str::endsWith(s, " down\n") )
00085 return html::yellow(line);
00086 return line;
00087 }
00088
00089 return line;
00090 }
00091
00092
00093 string linkify(const char *s) {
00094 const char *p = s;
00095 const char *h = strstr(p, "http://");
00096 if( h == 0 ) return s;
00097
00098 const char *sp = h + 7;
00099 while( *sp && *sp != ' ' ) sp++;
00100
00101 string url(h, sp-h);
00102 stringstream ss;
00103 ss << string(s, h-s) << "<a href=\"" << url << "\">" << url << "</a>" << sp;
00104 return ss.str();
00105 }
00106
00107 void toHTML(stringstream& s) {
00108 vector<const char*> v;
00109 get( v );
00110
00111 bool first = true;
00112 s << "<pre>\n";
00113 for( int i = 0; i < (int)v.size(); i++ ) {
00114 assert( strlen(v[i]) > 20 );
00115 int r = repeats(v, i);
00116 if( r < 0 ) {
00117 s << color( linkify( clean(v,i).c_str() ) );
00118 }
00119 else {
00120 stringstream x;
00121 x << string(v[i], 0, 20);
00122 int nr = (i-r);
00123 int last = i+nr-1;
00124 for( ; r < i ; r++ ) x << '.';
00125 if( 1 ) {
00126 stringstream r;
00127 if( nr == 1 ) r << "repeat last line";
00128 else r << "repeats last " << nr << " lines; ends " << string(v[last]+4,0,15);
00129 first = false; s << html::a("", r.str(), clean(v,i,x.str()));
00130 }
00131 else s << x.str();
00132 s << '\n';
00133 i = last;
00134 }
00135 }
00136 s << "</pre>\n";
00137 }
00138
00139
00140 };
00141
00142 }