]> xenbits.xensource.com Git - xcp/xen-api-libs.git/commitdiff
[refactoring] move debug.ml from xen-api.hg to xen-api-libs.hg/log
authorDavid Scott <dave.scott@eu.citrix.com>
Mon, 26 Oct 2009 16:32:15 +0000 (16:32 +0000)
committerDavid Scott <dave.scott@eu.citrix.com>
Mon, 26 Oct 2009 16:32:15 +0000 (16:32 +0000)
Signed-off-by: Thomas Gazagnaire <thomas.gazagnaire@citrix.com>
log/META.in
log/Makefile
log/debug.ml [new file with mode: 0644]
log/debug.mli [new file with mode: 0644]
log/log.ml
log/log.mli
log/logs.ml
log/logs.mli [new file with mode: 0644]
log/syslog.mli [new file with mode: 0644]

index 5c3646a62169bbc311e6b94a4b6d02379f19b9e3..98f0c4c501491170f38bc6d6f10a1230bb2b5ba8 100644 (file)
@@ -1,4 +1,5 @@
 version = "@VERSION@"
 description = "Log - logging library"
+requires = "unix,stdext"
 archive(byte) = "log.cma"
 archive(native) = "log.cmxa"
index be0719a085752e1e5fde801439d72fe88c21ef98..28d9fb6f69388e2edd9a5f86de7756e7c582f74a 100644 (file)
@@ -15,8 +15,8 @@ OCAMLABI := $(shell ocamlc -version)
 OCAMLLIBDIR := $(shell ocamlc -where)
 OCAMLDESTDIR ?= $(OCAMLLIBDIR)
 
-OBJS = syslog log logs
-INTF = log.cmi logs.cmi syslog.cmi
+OBJS = syslog log logs debug
+INTF = log.cmi logs.cmi syslog.cmi debug.cmi
 LIBS = log.cma log.cmxa
 
 all: $(INTF) $(LIBS) $(PROGRAMS)
@@ -38,32 +38,25 @@ libsyslog_stubs.a: syslog_stubs.o
        ar rcs $@ $+
        ocamlmklib -o syslog_stubs $+
 
-%.cmo: %.ml
-       $(OCAMLC) -c $(OCAMLCFLAGS) -o $@ $<
-
 %.cmi: %.mli
        $(OCAMLC) -c $(OCAMLCFLAGS) -o $@ $<
 
-%.cmx: %.ml
-       $(OCAMLOPT) $(OCAMLOPTFLAGS) -c -o $@ $<
+%.cmo: %.ml %.cmi
+       $(OCAMLC) -c $(OCAMLCFLAGS) -thread -o $@ $<
+
+%.cmx: %.ml %.cmi
+       $(OCAMLOPT) $(OCAMLOPTFLAGS) -thread -c -o $@ $<
 
 %.o: %.c
        $(CC) $(CFLAGS) -c -o $@ $<
 
-logs.mli : logs.ml
-       $(OCAMLC) -i $(OCAMLCFLAGS) $< > $@
-
-syslog.mli : syslog.ml
-       $(OCAMLC) -i $< > $@
-
 META: META.in
        sed 's/@VERSION@/$(VERSION)/g' < $< > $@
 
 #dependency:
-log.cmo: syslog.cmo log.cmi 
-log.cmx: syslog.cmx log.cmi 
-logs.cmo: log.cmi 
-logs.cmx: log.cmx 
+log.cmi: syslog.cmi
+logs.cmi: log.cmi
+debug.cmi: logs.cmi
 
 .PHONY: install
 install: $(LIBS) META
diff --git a/log/debug.ml b/log/debug.ml
new file mode 100644 (file)
index 0000000..bdd43e8
--- /dev/null
@@ -0,0 +1,132 @@
+(*
+ * Copyright (C) 2006-2009 Citrix Systems Inc.
+ *
+ * This program 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; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program 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.
+ *)
+open Stringext
+open Pervasiveext
+open Threadext
+
+(** Associate a task with each active thread *)
+let thread_tasks : (int, string) Hashtbl.t = Hashtbl.create 256 
+let thread_tasks_m = Mutex.create ()
+
+let get_thread_id () =
+  try Thread.id (Thread.self ()) with _ -> -1 
+
+(* Theses functions need to be defined later in the code. *)
+let get_hostname = 
+  let f () = "Debug.get_hostname not set" in
+  ref f
+
+let associate_thread_with_task task = 
+  let id = get_thread_id () in
+  if id <> -1
+  then begin
+    Mutex.execute thread_tasks_m (fun () -> Hashtbl.add thread_tasks id task); 
+  end
+
+let get_task_from_thread () = 
+  let id = get_thread_id () in
+  Mutex.execute thread_tasks_m 
+    (fun () -> if Hashtbl.mem thread_tasks id then Some(Hashtbl.find thread_tasks id) else None)
+
+let dissociate_thread_from_task () =
+  let id = get_thread_id () in
+  if id <> -1
+  then match get_task_from_thread () with
+  | Some _ ->
+      Mutex.execute thread_tasks_m (fun () -> Hashtbl.remove thread_tasks id)
+  | None ->
+      let extra = Printf.sprintf "[thread: debug (%n)] " id in
+      Logs.info ~extra "debug" "Thread id %d is not associated with any task" id
+
+let with_thread_associated task f x = 
+  associate_thread_with_task task;
+  finally
+    (fun () -> f x)
+    dissociate_thread_from_task
+
+let threadnames = Hashtbl.create 256
+let tnmutex = Mutex.create () 
+module StringSet = Set.Make(struct type t=string let compare=Pervasives.compare end)
+let debug_keys = ref StringSet.empty 
+let get_all_debug_keys () =
+       StringSet.fold (fun key keys -> key::keys) !debug_keys []
+
+let dkmutex = Mutex.create ()
+
+let _ = Hashtbl.add threadnames (-1) "no thread"
+
+let get_thread_id () =
+    try Thread.id (Thread.self ()) with _ -> -1 
+
+let name_thread name =
+    let id = get_thread_id () in
+    Mutex.execute tnmutex (fun () -> Hashtbl.add threadnames id name)
+
+let remove_thread_name () =
+    let id = get_thread_id () in
+    Mutex.execute tnmutex (fun () -> Hashtbl.remove threadnames id)
+
+module type BRAND = sig
+  val name: string
+end
+
+module Debugger = functor(Brand: BRAND) -> struct
+  let hostname = Unix.gethostname ()
+  let _ =
+    Mutex.execute dkmutex (fun () -> 
+      debug_keys := StringSet.add Brand.name !debug_keys)
+
+  let get_thread_name () =
+    let id = get_thread_id () in
+    Mutex.execute tnmutex 
+      (fun () -> 
+        try
+          Printf.sprintf "%d %s" id (Hashtbl.find threadnames id)
+        with _ -> 
+          Printf.sprintf "%d" id)
+
+  let get_task () =
+    default "" (may (fun s -> s) (get_task_from_thread ()))
+
+  let output (f:string -> ?extra:string -> ('a, unit, string, 'b) format4 -> 'a) fmt =
+    let extra = 
+      Printf.sprintf "%s|%s|%s|%s" 
+      hostname
+      (get_thread_name ()) 
+      (get_task ())
+      Brand.name
+    in
+    f Brand.name ~extra fmt
+
+       let output_and_return ?raw (f:string -> ?raw:bool -> ?extra:string -> ('a, unit, string, 'b) format4 -> 'a) fmt =
+    let extra =
+      Printf.sprintf "%s|%s|%s|%s"
+      hostname
+      (get_thread_name ())
+      (get_task ())
+      Brand.name
+    in
+    f Brand.name ?raw ~extra fmt
+    
+  let debug fmt = output Logs.debug fmt
+  let warn fmt = output Logs.warn fmt
+  let info fmt = output Logs.info fmt
+  let error fmt = output Logs.error fmt
+  let audit ?raw fmt = output_and_return ?raw Logs.audit fmt
+
+  let log_backtrace () =
+    let backtrace = Backtrace.get_backtrace () in
+    debug "%s" (String.escaped backtrace)
+
+end
diff --git a/log/debug.mli b/log/debug.mli
new file mode 100644 (file)
index 0000000..22e0013
--- /dev/null
@@ -0,0 +1,58 @@
+(*
+ * Copyright (C) 2006-2009 Citrix Systems Inc.
+ *
+ * This program 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; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program 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.
+ *)
+
+(** Debug utilities *)
+
+(** {2 Associate a task to the current actions} *)
+
+(** Associate a task name to the current thread *)
+val associate_thread_with_task : string -> unit
+
+(** Dissociate a task name to the current thread *)
+val dissociate_thread_from_task : unit -> unit
+
+(** Do an action with a task name associated with the current thread *)
+val with_thread_associated : string -> ('a -> 'b) -> 'a -> 'b
+
+(** {2 Associate a name to the current thread} *)
+
+val name_thread : string -> unit
+
+val remove_thread_name : unit -> unit
+
+val get_all_debug_keys : unit -> string list
+
+module type BRAND = sig val name : string end
+
+module Debugger : functor (Brand : BRAND) ->
+sig
+
+       (** Debug function *)
+       val debug : ('a, unit, string, unit) format4 -> 'a
+
+    (** Warn function *)
+       val warn : ('a, unit, string, unit) format4 -> 'a
+
+       (** Info function *)
+    val info : ('a, unit, string, unit) format4 -> 'a
+    
+       (** Error function *)
+       val error : ('a, unit, string, unit) format4 -> 'a
+
+    (** Audit function *)
+       val audit : ?raw:bool -> ('a, unit, string, string) format4 -> 'a
+    
+       val log_backtrace : unit -> unit
+end
+       
index ad7e10c7ed0d27bfdea1851712aa46a97b9a877f..3d3b0e4427cf253a6654e5f9ffb9927cf6980e59 100644 (file)
  *)
 
 open Printf
-open Threadext
+
+module Mutex = struct
+    include Mutex
+    let execute lock f =
+       Mutex.lock lock;
+       let r = begin try f () with exn -> Mutex.unlock lock; raise exn end; in
+       Mutex.unlock lock;
+       r
+end
 
 exception Unknown_level of string
 
@@ -64,6 +72,12 @@ let mkdir_rec dir perm =
 
 type t = { output: output; mutable level: level; }
 
+let get_strings t = match t.output with
+       | String s -> !s
+       | _ -> []
+
+let get_level t = t.level
+
 let make output level = { output = output; level = level; }
 
 let make_stream ty channel = 
@@ -134,7 +148,7 @@ let close t =
        | String _      -> ()
 
 (** create a string representating the parameters of the logger *)
-let string_of_logger t =
+let to_string t =
        match t.output with
        | Nil           -> "nil"
        | Syslog k      -> sprintf "syslog:%s" k
@@ -148,7 +162,7 @@ let string_of_logger t =
            end
 
 (** parse a string to a logger *)
-let logger_of_string s : t =
+let of_string s : t =
        match s with
        | "nil"    -> opennil ()
        | "stderr" -> openerr Debug
index 607b7b518f35fe44b062adb4ca0a6a4e0e9f0921..3eb1a1c573d00208e4d98ed69a03b09c07e2b037 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU Lesser General Public License for more details.
  *)
-exception Unknown_level of string
+
+(** Logging utilities *)
+
+type t
+
+(** create a string representating the parameters of the logger *)
+val to_string : t -> string
+
+(** parse a string to a logger *)
+val of_string : string -> t
+
+(** try to reopen a logger *)
+val reopen : t -> t
+
+(** close a logger *)
+val close : t -> unit
+
+val gettimestring : unit -> string
+
+(** {2 Builders} *)
+
 type level = Debug | Info | Warn | Error
+val get_level : t -> level
 
-type stream_type = Stderr | Stdout | File of string
-type stream_log = {
-  ty : stream_type;
-  channel : out_channel option ref;
-  mutex : Mutex.t;
-}
-type output =
-    Stream of stream_log
-  | String of string list ref
-  | Syslog of string
-  | Nil
-val int_of_level : level -> int
-val string_of_level : level -> string
+exception Unknown_level of string
 val level_of_string : string -> level
-val mkdir_safe : string -> Unix.file_perm -> unit
-val mkdir_rec : string -> Unix.file_perm -> unit
-type t = { output : output; mutable level : level; }
-val make : output -> level -> t
+val string_of_level : level -> string
+
+(** open a syslog logger *)
 val opensyslog : string -> level -> t
+
+(** open a stderr logger *)
 val openerr : level -> t
+
+(** open a stdout logger *)
 val openout : level -> t
+
+(** open a stream logger - returning the output type *)
 val openfile : string -> level -> t
+
+(** open a nil logger *)
 val opennil : unit -> t
+
+(** open a string logger *)
 val openstring : level -> t
-val reopen : t -> t
-val close : t -> unit
-val string_of_logger : t -> string
-val logger_of_string : string -> t
-val validate : string -> unit
-val set : t -> level -> unit
-val gettimestring : unit -> string
-val filesize : int ref
-val mutex : Mutex.t
+val get_strings : t -> string list
+
+(** {2 Raw output functions} *)
+
 val output : t -> ?key:string -> ?extra:string -> level -> string -> unit
 val output_and_return : t -> ?raw:bool -> ?key:string -> ?extra:string -> level -> string -> string
-val log : t -> level -> ('a, unit, string, unit) format4 -> 'a
+
+(** {2 Pretty output functions} *)
+
 val debug : t -> ('a, unit, string, unit) format4 -> 'a
 val info : t -> ('a, unit, string, unit) format4 -> 'a
 val warn : t -> ('a, unit, string, unit) format4 -> 'a
 val error : t -> ('a, unit, string, unit) format4 -> 'a
+val log : t -> level -> ('a, unit, string, unit) format4 -> 'a
+
+(** {2 Output validation} *)
+
+val validate : string -> unit
+
+(** {2 Concurrency} *)
+
+(** TODO: It would be very nice to have a thread-free log module (ie. put the control outside that module).
+       This mutex protects all the recorded outputs. *)
+val mutex : Mutex.t
+
+(** TODO: remove the global state (what happens if multiple log files are opened???) ! *)
+val filesize : int ref
+
+(*
+type stream_type = Stderr | Stdout | File of string
+type stream_log = {
+  ty : stream_type;
+  channel : out_channel option ref;
+  mutex : Mutex.t;
+}
+
+val int_of_level : level -> int
+val mkdir_safe : string -> Unix.file_perm -> unit
+val mkdir_rec : string -> Unix.file_perm -> unit
+val set : t -> level -> unit
+val mutex : Mutex.t
+*)
index 94a8a38b1fd6ec2b140bd36904c651457a1e29ab..8adac3d71181546ddb0ea8de24588f3cf5f14c13 100644 (file)
@@ -41,7 +41,7 @@ let get_or_open logstring =
        if Hashtbl.mem __all_loggers logstring then
                Hashtbl.find __all_loggers logstring
        else
-               let t = Log.logger_of_string logstring in
+               let t = Log.of_string logstring in
                Hashtbl.add __all_loggers logstring t;
                t
 
diff --git a/log/logs.mli b/log/logs.mli
new file mode 100644 (file)
index 0000000..0aa701e
--- /dev/null
@@ -0,0 +1,43 @@
+type keylogger = {
+  mutable debug : string list;
+  mutable info : string list;
+  mutable warn : string list;
+  mutable error : string list;
+  no_default : bool;
+}
+val __all_loggers : (string, Log.t) Hashtbl.t
+val __default_logger : keylogger
+val __log_mapping : (string, keylogger) Hashtbl.t
+val get_or_open : string -> Log.t
+val add : string -> string list -> unit
+val get_by_level : keylogger -> Log.level -> string list
+val set_by_level : keylogger -> Log.level -> string list -> unit
+val set : string -> Log.level -> string list -> unit
+val set_default : Log.level -> string list -> unit
+val append : string -> Log.level -> string -> unit
+val append_default : Log.level -> string -> unit
+val reopen : unit -> unit
+val reclaim : unit -> unit
+val clear : string -> Log.level -> unit
+val clear_default : Log.level -> unit
+val reset_all : string list -> unit
+val log_common :
+  string ->
+  Log.level ->
+  ?extra:string ->
+  ret_fn1:(string -> 'a) ->
+  ret_fn2:(Log.t list -> 'b) -> ('b, unit, string, 'a) format4 -> 'b
+val log :
+  string ->
+  Log.level -> ?extra:string -> ('a, unit, string, unit) format4 -> 'a
+val log_and_return :
+  string ->
+  Log.level ->
+  ?raw:bool -> ?extra:string -> ('a, unit, string, string) format4 -> 'a
+val debug : string -> ?extra:string -> ('a, unit, string, unit) format4 -> 'a
+val info : string -> ?extra:string -> ('a, unit, string, unit) format4 -> 'a
+val warn : string -> ?extra:string -> ('a, unit, string, unit) format4 -> 'a
+val error : string -> ?extra:string -> ('a, unit, string, unit) format4 -> 'a
+val audit :
+  string ->
+  ?raw:bool -> ?extra:string -> ('a, unit, string, string) format4 -> 'a
diff --git a/log/syslog.mli b/log/syslog.mli
new file mode 100644 (file)
index 0000000..eabafb8
--- /dev/null
@@ -0,0 +1,41 @@
+(*
+ * Copyright (C) 2006-2009 Citrix Systems Inc.
+ *
+ * This program 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; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program 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.
+ *)
+
+type level = Emerg | Alert | Crit | Err | Warning | Notice | Info | Debug
+type facility =
+    Auth
+  | Authpriv
+  | Cron
+  | Daemon
+  | Ftp
+  | Kern
+  | Local0
+  | Local1
+  | Local2
+  | Local3
+  | Local4
+  | Local5
+  | Local6
+  | Local7
+  | Lpr
+  | Mail
+  | News
+  | Syslog
+  | User
+  | Uucp
+
+external log : facility -> level -> string -> unit = "stub_syslog"
+external close : unit -> unit = "stub_closelog"
+
+