package vlt

  1. Overview
  2. Docs
A variant of Bolt logging tool

Install

dune-project
 Dependency

Authors

Maintainers

Sources

v0.2.5.tar.gz
sha256=756a6cba94204cda45ee767ca5f7e52ec321873dd53de48025c32dba1e03de24
md5=c0f22efcafa1119a9c82ffd9d7422da2

doc/src/vlt/output.ml.html

Source file output.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
(*
 * This file is part of Bolt.
 * Copyright (C) 2009-2012 Xavier Clerc.
 *
 * Bolt is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Bolt is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *)


(* Definitions *)

class type impl =
  object
    method write : string -> unit
    method close : unit
  end

type rotation = {
    seconds_elapsed : float option;
    signal_caught : Signal.t option;
  }

type t = string -> rotation -> Layout.t lazy_t -> impl

let _, register, register_unnamed, get =
  Utils.make_container_functions ()


(* Predefined outputs *)

let void _ _ _ =
  object
    method write _ = ()
    method close = ()
  end

let outputname s t =
  let dir = Filename.dirname s in
  let base = Filename.basename s in
  let buff_sz = 64 + (String.length s) in
  let buff = Buffer.create buff_sz in
  let time =
    let now = Unix.localtime t in
    let millis = int_of_float ((t -. (floor t)) *. 1000.) in
    Printf.sprintf "%d-%02d-%02d-%02d-%02d-%02d-%03d"
      (1900 + now.Unix.tm_year)
      (succ now.Unix.tm_mon)
      now.Unix.tm_mday
      now.Unix.tm_hour
      now.Unix.tm_min
      now.Unix.tm_sec
      millis in
  String.iter
    (function
      | '%' -> Buffer.add_string buff time
      | c -> Buffer.add_char buff c)
    base;
  let file =
    try
      let file = Buffer.create buff_sz in
      let try_with_empty f x =
        try f x with _ -> "" in
      let subst = function
        | "time" -> time
        | "pid" -> try_with_empty (fun () -> string_of_int (Unix.getpid ())) ()
        | "hostname" -> try_with_empty Unix.gethostname ()
        | s -> try_with_empty Sys.getenv s in
      Buffer.add_substitute file subst (Buffer.contents buff);
      Buffer.contents file
    with Not_found -> Buffer.contents buff in
  Filename.concat dir file

let write_strings ch l =
  try
    List.iter (fun s -> output_string ch s; output_char ch '\n') l
  with _ ->
    Utils.verbose "unable to write data"

let open_channel filename h t =
  let ch, reg = match filename with
  | "<stdout>" -> stdout, false
  | "<stderr>" -> stderr, false
  | _ ->
      let file = outputname filename t in
      let kind = try (Unix.stat file).Unix.st_kind with _ -> Unix.S_REG in
      (open_out file),
      (match kind with Unix.S_REG | Unix.S_LNK -> true | _ -> false) in
  write_strings ch h;
  (try flush ch with _ -> Utils.verbose "unable to write data");
  ch, reg

let signals = Array.make Signal.max_int false

let file filename rot layout =
  let now = Unix.gettimeofday () in
  let header, footer, _ = Lazy.force layout in
  try
    let ch, regular = open_channel filename header now in
    let rotate = if regular then Some rot else None in
    object (self)
      val mutable channel = ch
      val mutable last_rotate = now
      method write s =
        try
          if s <> "" then begin
            output_string channel s;
            output_char channel '\n';
            flush channel;
          end;
          let now = Unix.gettimeofday () in
          match rotate with
          | Some r ->
              let do_rotate =
                (match r.seconds_elapsed with
                | Some x ->
                    now -. last_rotate >= x
                | None -> false)
              || (match r.signal_caught with
                | Some s ->
                    let idx = Signal.to_int s in
                    Utils.enter_critical_section ();
                    let res = signals.(idx) in
                    signals.(idx) <- false;
                    Utils.leave_critical_section ();
                    res
                | None -> false) in
              if do_rotate then begin
                self#close;
                channel <- fst (open_channel filename header now);
                last_rotate <- now
              end
          | None -> ()
        with _ -> Utils.verbose "unable to write data"
      method close =
        write_strings ch footer;
        close_out_noerr ch
    end
  with _ ->
    Utils.verbose "unable to create output (resorting to 'void')";
    void filename rot layout

let growlnotify _ _ _ =
  object
    method write msg =
      let progname = Sys.argv.(0) in
      let basename = Filename.basename progname in
      match Sys.os_type with
      | "Unix" ->
          (try
            let command =
              Printf.sprintf "growlnotify -n %s -t %s -m %S"
                (Filename.quote progname)
                (Filename.quote basename)
                msg in
            ignore (Sys.command command)
          with _ -> ())
      | "Win32" | "Cygwin" ->
          (try
            let command =
              Printf.sprintf "growlnotify.exe /t:%s %S"
                (Filename.quote basename)
                msg in
            ignore (Sys.command command)
          with _ -> ())
      | _ -> ()
    method close = ()
  end

let bell _ _ _ =
  object
    method write _ = print_char '\007'
    method close = ()
  end

let say _ _ _ =
  object
    method write msg =
      try
        let command = Printf.sprintf "say %S" msg in
        ignore (Sys.command command)
      with _ -> ()
    method close = ()
  end

let () =
  List.iter
    (fun (x, y) -> register x y)
    [ "void",        void ;
      "file",        file ;
      "growlnotify", growlnotify ;
      "bell",        bell ;
      "say",         say ]