log.c 3.8 KB

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