xref: /plan9/sys/src/libventi/log.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
1 #include <u.h>
2 #include <libc.h>
3 #include <venti.h>
4 
5 char *VtServerLog = "libventi/server";
6 
7 int ventilogging;
8 #define log	not_the_log_library_call
9 
10 static char Eremoved[] = "[removed]";
11 
12 enum
13 {	/* defaults */
14 	LogChunkSize = 8192,
15 	LogSize = 65536
16 };
17 
18 static struct {
19 	QLock lk;
20 	VtLog *hash[1024];
21 } vl;
22 
23 static uint
24 hash(char *s)
25 {
26 	uint h;
27 	uchar *p;
28 
29 	h = 0;
30 	for(p=(uchar*)s; *p; p++)
31 		h = h*37 + *p;
32 	return h;
33 }
34 
35 char**
36 vtlognames(int *pn)
37 {
38 	int i, nname, size;
39 	VtLog *l;
40 	char **s, *a, *e;
41 
42 	qlock(&vl.lk);
43 	size = 0;
44 	nname = 0;
45 	for(i=0; i<nelem(vl.hash); i++)
46 	for(l=vl.hash[i]; l; l=l->next){
47 		nname++;
48 		size += strlen(l->name)+1;
49 	}
50 
51 	s = vtmalloc(nname*sizeof(char*)+size);
52 	a = (char*)(s+nname);
53 	e = (char*)s+nname*sizeof(char*)+size;
54 
55 	nname = 0;
56 	for(i=0; i<nelem(vl.hash); i++)
57 	for(l=vl.hash[i]; l; l=l->next){
58 		strcpy(a, l->name);
59 		s[nname++] = a;
60 		a += strlen(a)+1;
61 	}
62 	*pn = nname;
63 	assert(a == e);
64 	qunlock(&vl.lk);
65 
66 	return s;
67 }
68 
69 VtLog*
70 vtlogopen(char *name, uint size)
71 {
72 	uint h;
73 	int i, nc;
74 	char *p;
75 	VtLog *l, *last;
76 
77 	if(!ventilogging)
78 		return nil;
79 
80 	h = hash(name)%nelem(vl.hash);
81 	qlock(&vl.lk);
82 	last = nil;
83 	for(l=vl.hash[h]; l; last=l, l=l->next)
84 		if(strcmp(l->name, name) == 0){
85 			if(last){	/* move to front */
86 				last->next = l->next;
87 				l->next = vl.hash[h];
88 				vl.hash[h] = l;
89 			}
90 			l->ref++;
91 			qunlock(&vl.lk);
92 			return l;
93 		}
94 
95 	if(size == 0){
96 		qunlock(&vl.lk);
97 		return nil;
98 	}
99 
100 	/* allocate */
101 	nc = (size+LogChunkSize-1)/LogChunkSize;
102 	l = vtmalloc(sizeof *l + nc*(sizeof(*l->chunk)+LogChunkSize) + strlen(name)+1);
103 	memset(l, 0, sizeof *l);
104 	l->chunk = (VtLogChunk*)(l+1);
105 	l->nchunk = nc;
106 	l->w = l->chunk;
107 	p = (char*)(l->chunk+nc);
108 	for(i=0; i<nc; i++){
109 		l->chunk[i].p = p;
110 		l->chunk[i].wp = p;
111 		p += LogChunkSize;
112 		l->chunk[i].ep = p;
113 	}
114 	strcpy(p, name);
115 	l->name = p;
116 
117 	/* insert */
118 	l->next = vl.hash[h];
119 	vl.hash[h] = l;
120 	l->ref++;
121 
122 	l->ref++;
123 	qunlock(&vl.lk);
124 	return l;
125 }
126 
127 void
128 vtlogclose(VtLog *l)
129 {
130 	if(l == nil)
131 		return;
132 
133 	qlock(&vl.lk);
134 	if(--l->ref == 0){
135 		/* must not be in hash table */
136 		assert(l->name == Eremoved);
137 		free(l);
138 	}else
139 		assert(l->ref > 0);
140 	qunlock(&vl.lk);
141 }
142 
143 void
144 vtlogremove(char *name)
145 {
146 	uint h;
147 	VtLog *last, *l;
148 
149 	h = hash(name)%nelem(vl.hash);
150 	qlock(&vl.lk);
151 	last = nil;
152 	for(l=vl.hash[h]; l; last=l, l=l->next)
153 		if(strcmp(l->name, name) == 0){
154 			if(last)
155 				last->next = l->next;
156 			else
157 				vl.hash[h] = l->next;
158 			l->name = Eremoved;
159 			l->next = nil;
160 			qunlock(&vl.lk);
161 			vtlogclose(l);
162 			return;
163 		}
164 	qunlock(&vl.lk);
165 }
166 
167 static int
168 timefmt(Fmt *fmt)
169 {
170 	static uvlong t0;
171 	uvlong t;
172 	Tm tm;
173 
174 	if(fmt->flags&FmtSharp){
175 		if(t0 == 0)
176 			t0 = nsec();
177 		t = nsec()-t0;
178 		return fmtprint(fmt, "T+%d.%04d", (uint)(t/1000000000), (uint)(t%1000000000)/100000);
179 	}else{
180 		tm = *localtime(time(0));
181 		return fmtprint(fmt, "%04d/%02d%02d %02d:%02d:%02d",
182 			1900+tm.year, tm.mon+1, tm.mday, tm.hour, tm.min, tm.sec);
183 	}
184 }
185 
186 void
187 vtlogvprint(VtLog *l, char *fmt, va_list arg)
188 {
189 	int n;
190 	char *p;
191 	VtLogChunk *c;
192 	static int first = 1;
193 
194 	if(l == nil)
195 		return;
196 
197 	if(first){
198 		fmtinstall('T', timefmt);
199 		first = 0;
200 	}
201 
202 
203 	qlock(&l->lk);
204 	c = l->w;
205 	n = c->ep - c->wp;
206 	if(n < 512){
207 		c++;
208 		if(c == l->chunk+l->nchunk)
209 			c = l->chunk;
210 		c->wp = c->p;
211 		l->w = c;
212 	}
213 	p = vseprint(c->wp, c->ep, fmt, arg);
214 	if(p)
215 		c->wp = p;
216 	qunlock(&l->lk);
217 }
218 
219 void
220 vtlogprint(VtLog *l, char *fmt, ...)
221 {
222 	va_list arg;
223 
224 	if(l == nil)
225 		return;
226 
227 	va_start(arg, fmt);
228 	vtlogvprint(l, fmt, arg);
229 	va_end(arg);
230 }
231 
232 void
233 vtlog(char *name, char *fmt, ...)
234 {
235 	VtLog *l;
236 	va_list arg;
237 
238 	l = vtlogopen(name, LogSize);
239 	if(l == nil)
240 		return;
241 	va_start(arg, fmt);
242 	vtlogvprint(l, fmt, arg);
243 	va_end(arg);
244 	vtlogclose(l);
245 }
246 
247 void
248 vtlogdump(int fd, VtLog *l)
249 {
250 	int i;
251 	VtLogChunk *c;
252 
253 	if(l == nil)
254 		return;
255 
256 	c = l->w;
257 	for(i=0; i<l->nchunk; i++){
258 		if(++c == l->chunk+l->nchunk)
259 			c = l->chunk;
260 		write(fd, c->p, c->wp-c->p);
261 	}
262 }
263 
264