File: debug.ml

package info (click to toggle)
xen-api-libs 0.5.2-3
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 1,940 kB
  • sloc: ml: 13,925; sh: 2,930; ansic: 1,699; makefile: 1,240; python: 83
file content (137 lines) | stat: -rw-r--r-- 4,234 bytes parent folder | download
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
(*
 * 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 

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

let hostname_cache = ref None
let hostname_m = Mutex.create ()
let get_hostname () =
  match Mutex.execute hostname_m (fun () -> !hostname_cache) with
  | Some h -> h
  | None ->
		let h = Unix.gethostname () in
		Mutex.execute hostname_m (fun () -> hostname_cache := Some h);
		h
let invalidate_hostname_cache () = Mutex.execute hostname_m (fun () -> hostname_cache := None)

module Debugger = functor(Brand: BRAND) -> struct
  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" 
      (get_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"
      (get_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