v / vlib / log / safe_log.v
114 lines · 103 sloc · 2.51 KB · bb7f9f2562ec5c33b32ded56b5fd25341a4457e8
Raw
1module log
2
3import sync
4
5// ThreadSafeLog embeds Log, and adds a mutex field.
6// It uses the mutex to synchronise accesses to the embedded Log.
7pub struct ThreadSafeLog {
8 Log
9pub mut:
10 mu &sync.Mutex = sync.new_mutex()
11}
12
13// new_thread_safe_log returns a new log structure, whose methods are safe
14// to call by multiple threads.
15pub fn new_thread_safe_log() &ThreadSafeLog {
16 slevel := $d('log_default_level', 'info')
17 level := level_from_tag(slevel.to_upper()) or { panic('invalid log_default_level: ${slevel}') }
18 mut x := &ThreadSafeLog{
19 level: level
20 }
21 return x
22}
23
24// free frees the given ThreadSafeLog instance.
25@[unsafe]
26pub fn (mut x ThreadSafeLog) free() {
27 unsafe {
28 // make sure other threads are not in the blocks protected by the mutex:
29 if x.mu.try_lock() {
30 x.mu.unlock()
31 }
32 x.mu.destroy()
33 free(x.mu)
34 x.mu = nil
35 x.Log.free()
36 }
37}
38
39// set_level changes the log level
40pub fn (mut x ThreadSafeLog) set_level(level Level) {
41 if unsafe { x.mu == 0 } {
42 return
43 }
44 x.mu.lock()
45 x.Log.set_level(level)
46 x.mu.unlock()
47}
48
49// set_always_flush called with true, will make the log flush after every single .fatal(), .error(), .warn(), .info(), .debug() call.
50// That can be much slower, if you plan to do lots of frequent calls, but if your program exits early or crashes, your logs will be more complete.
51pub fn (mut x ThreadSafeLog) set_always_flush(should_flush bool) {
52 if unsafe { x.mu == 0 } {
53 return
54 }
55 x.mu.lock()
56 x.Log.set_always_flush(should_flush)
57 x.mu.unlock()
58}
59
60// debug logs a debug message
61pub fn (mut x ThreadSafeLog) debug(s string) {
62 if unsafe { x.mu == 0 } {
63 return
64 }
65 x.mu.lock()
66 x.Log.debug(s)
67 x.mu.unlock()
68}
69
70// info logs an info messagep
71pub fn (mut x ThreadSafeLog) info(s string) {
72 if unsafe { x.mu == 0 } {
73 return
74 }
75 x.mu.lock()
76 x.Log.info(s)
77 x.mu.unlock()
78}
79
80// warn logs a warning message
81pub fn (mut x ThreadSafeLog) warn(s string) {
82 if unsafe { x.mu == 0 } {
83 return
84 }
85 x.mu.lock()
86 x.Log.warn(s)
87 x.mu.unlock()
88}
89
90// error logs an error message
91pub fn (mut x ThreadSafeLog) error(s string) {
92 if unsafe { x.mu == 0 } {
93 return
94 }
95 x.mu.lock()
96 x.Log.error(s)
97 x.mu.unlock()
98}
99
100// fatal logs a fatal message, and panics
101@[noreturn]
102pub fn (mut x ThreadSafeLog) fatal(s string) {
103 if unsafe { x.mu == 0 } {
104 panic(s)
105 }
106 x.mu.lock()
107 defer {
108 // TODO: Log.fatal() is marked as noreturn, but this defer is allowed.
109 // Think whether it should be, or if it should be a compiler notice at least,
110 // since it would not be reached at all (.fatal() panics).
111 x.mu.unlock()
112 }
113 x.Log.fatal(s)
114}
115