1 
2 /* Web Polygraph       http://www.web-polygraph.org/
3  * Copyright 2003-2011 The Measurement Factory
4  * Licensed under the Apache License, Version 2.0 */
5 
6 #ifndef POLYGRAPH__BASE_OLOG_H
7 #define POLYGRAPH__BASE_OLOG_H
8 
9 #include "xstd/h/iosfwd.h"
10 #include "xstd/Time.h"
11 #include "xstd/Size.h"
12 #include "xstd/NetDouble.h"
13 #include "xstd/BigSize.h"
14 #include "xstd/String.h"
15 #include "xstd/NetAddr.h"
16 #include "xstd/Array.h"
17 #include "xstd/Endian.h"
18 
19 // some environments do not know better than #define these
20 #ifdef getc
21 #	undef getc
22 #endif
23 #ifdef putc
24 #	undef putc
25 #endif
26 
27 namespace zlib {
28 class OFStream;
29 }
30 
31 // buffered binary output log
32 class OLog {
33 	public:
34 		typedef void (Manip)(class OLog &);
35 
36 	public:
37 		OLog();
38 		virtual ~OLog();
39 
capacity()40 		Size capacity() const { return theCapacity; }
size()41 		Size size() const { return theSize; }
42 
43 		void stream(const String &aName, ostream *aStream);
44 		void capacity(Size aCap);
45 
putc(char c)46 		void putc(char c) { put(&c, 1); }
putb(bool b)47 		void putb(bool b) { putc((char)(b ? 1 : 0)); }
puti(int x)48 		void puti(int x) { x = htonl(x); put(&x, SizeOf(x)); }
49 		void puti(const int *x, int count);
puti64(int64_t x)50 		void puti64(int64_t x) { x = htobe64(x); put(&x, SizeOf(x)); }
puts(const char * s,Size size)51 		void puts(const char *s, Size size) { puti(size); if (size) put(s, size); }
puta(const struct sockaddr_storage & a)52 		void puta(const struct sockaddr_storage &a) { put(&a, SizeOf(a)); }
53 
54 		virtual void begEntry(int tag);
55 		void endEntry();
56 
57 		void flush(Size maxSize); // flushes up-to max size
flush()58 		void flush() { flush(theSize); }
59 		void close(); // flushes if needed
60 
61 	protected:
62 		void resize(Size minCap);
63 
64 		inline void put(const void *buf, Size size);
65 		void write(const char *const buf, const Size size);
66 		void overflow(const void *buf, Size size);
67 
68 		virtual void putHeader();
69 		virtual void putTrailer();
70 
71 	protected:
72 		ostream *theStream;
73 		zlib::OFStream *theZStream;
74 		String theName;
75 
76 		char *theBuf;
77 		Size theCapacity;  // buffer space allocated
78 		Size theSize;      // buffer space used
79 		Size thePos;       // global offset
80 
81 		char *theEntry;	   // start of the current entry
82 		int theEntryTag;   // tag saved until endEntry()
83 
84 		Array<int> theDir; // directory (one entry per tag)
85 };
86 
87 
88 /* manipulators to begin and end logging of a named entry */
89 
90 struct bege {
begebege91 	bege(int t, int cat): tag(t | (cat << 16)) {}
92 	int tag;
93 };
94 
ende(OLog & log)95 inline void ende(OLog &log) { log.endEntry(); }
96 
97 
98 /* logging of common types */
99 
100 inline
101 OLog &operator <<(OLog &ol, char c) {
102 	ol.putc(c);
103 	return ol;
104 }
105 
106 inline
107 OLog &operator <<(OLog &ol, bool b) {
108 	ol.putb(b);
109 	return ol;
110 }
111 
112 inline
113 OLog &operator <<(OLog &ol, int x) {
114 	ol.puti(x);
115 	return ol;
116 }
117 
118 inline
119 OLog &operator <<(OLog &ol, const int64_t x) {
120 	ol.puti64(x);
121 	return ol;
122 }
123 
124 inline
125 OLog &operator <<(OLog &ol, double x) {
126 	NetDouble nd(x);
127 	return ol << nd.mnt << nd.exp;
128 }
129 
130 inline
131 OLog &operator <<(OLog &ol, const char *s) {
132 	ol.puts(s, strlen(s)+1);
133 	return ol;
134 }
135 
136 inline
137 OLog &operator <<(OLog &ol, const String &s) {
138 	if (s)
139 		ol.puts(s.cstr(), s.len()+1);
140 	else
141 		ol.puts(0, 0);
142 	return ol;
143 }
144 
145 inline
146 OLog &operator <<(OLog &ol, const Time &t) {
147 	ol.puti(t.tv_sec);
148 	ol.puti(t.tv_usec);
149 	return ol;
150 }
151 
152 inline
153 OLog &operator <<(OLog &ol, const BigSize &bs) {
154 	return ol << bs.theAcc << bs.theCnt;
155 }
156 
157 // XXX: should log either A or N
158 inline
159 OLog &operator <<(OLog &ol, const NetAddr &a) {
160 	ol.puta(a.addrN().sockAddr(a.port()));
161 	return ol;
162 }
163 
164 inline
165 OLog &operator <<(OLog &ol, const bege &b) {
166 	ol.begEntry(b.tag);
167 	return ol;
168 }
169 
170 inline
171 OLog &operator <<(OLog &ol, OLog::Manip m) {
172 	m(ol);
173 	return ol;
174 }
175 
176 template <class Item>
177 inline
178 OLog &operator <<(OLog &ol, const Array<Item> &a) {
179 	ol.puti(a.count());
180 	for (int i = 0; i < a.count(); ++i)
181 		ol << a[i];
182 	return ol;
183 }
184 
185 // store array of not-null pointers to items
186 template <class Item>
187 inline
188 OLog &operator <<(OLog &ol, const Array<Item *> &a) {
189 	ol.puti(a.count());
190 	for (int i = 0; i < a.count(); ++i) {
191 		if (a[i])
192 			ol << i << *a[i];
193 	}
194 	ol << -1;
195 	return ol;
196 }
197 
198 /* inlined methods */
199 
200 inline
put(const void * buf,Size size)201 void OLog::put(const void *buf, Size size) {
202 	if (size > 0 && theStream) {
203 		// just append if fits
204 		if (theSize + size <= theCapacity) {
205 			memcpy(theBuf + theSize, buf, size);
206 			theSize += size;
207 			thePos += size;
208 		} else {
209 			overflow(buf, size); // always uses put() recursively
210 		}
211 	}
212 }
213 
214 #endif
215