Skip to content

Commit 37b7b07

Browse files
authored
Merge pull request mouredev#4415 from luishendrix92/main
#25 - OCaml
2 parents cf14175 + 0ae9743 commit 37b7b07

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
(******************************************************************************)
2+
(* *)
3+
(* Logging *)
4+
(* *)
5+
(* Logging is a practise where the developers of an application display *)
6+
(* information about what's going on at runtime to an output channel, which *)
7+
(* can be either the standard output channel (aka, the console window), or *)
8+
(* a file writter so that we can create and manage log files that can be *)
9+
(* used by both developers and users alike to debug a particular problem. *)
10+
(* *)
11+
(* Logging libraries exist in every language and they all have some things *)
12+
(* in common, especially the important concept of a {b level}. A level is *)
13+
(* a tier of severity for a message displayed on the channel. For example, *)
14+
(* a user can be concerned only with log messages written by the developer *)
15+
(* for the end user (also known as "application level"); or maybe it's set *)
16+
(* to {e debug} which will display messages intended for displaying the *)
17+
(* flow of data structures in a readable manner, which should not be shown *)
18+
(* to the end user. That's why loggers have a function to set this level. *)
19+
(* *)
20+
(******************************************************************************)
21+
22+
let stamp_tag : Mtime.span Logs.Tag.def =
23+
Logs.Tag.def "stamp" ~doc:"Relative monotonic time stamp" Mtime.Span.pp
24+
;;
25+
26+
let stamp c = Logs.Tag.(empty |> add stamp_tag (Mtime_clock.count c))
27+
28+
let log_levels () =
29+
Logs.app (fun m -> m "This message is only shown at the Logs.App level.");
30+
(* This message won't be displayed! I set the level to Logs.Info, which is
31+
one level above Debug. To show it I'd have to change it to Logs.Debug. *)
32+
Logs.debug (fun m -> m "Only shown during Logs.Debug, ideal for development.");
33+
Logs.info (fun m -> m "Normal message with information about the processes.");
34+
Logs.warn (fun m -> m "The ozone layer is in danger :(");
35+
Logs.err (fun m -> m "Error reporting, recoverable or caught");
36+
Logs.info (fun m ->
37+
m "Message with a custom header called 'DONUT'..." ?header:(Some "DONUT"))
38+
;;
39+
40+
(* DIFICULTAD EXTRA (opcional):
41+
============================
42+
Crea un programa ficticio de gestión de tareas que permita añadir, eliminar
43+
y listar dichas tareas.
44+
- Añadir: recibe nombre y descripción.
45+
- Eliminar: por nombre de la tarea.
46+
47+
Implementa diferentes mensajes de log que muestren información según la
48+
tarea ejecutada (a tu elección).
49+
Utiliza el log para visualizar el tiempo de ejecución de cada tarea. *)
50+
module TaskRepository = struct
51+
type task =
52+
{ name : string
53+
; description : string
54+
}
55+
[@@deriving show { with_path = false }]
56+
57+
let tasks : (string, task) Hashtbl.t =
58+
Logs.info (fun m -> m "TaskRepository hash table initialized");
59+
Hashtbl.create 100
60+
;;
61+
62+
let add task =
63+
if Hashtbl.mem tasks task.name
64+
then
65+
Logs.warn (fun m ->
66+
m "Task [%s] already exists so it will be replaced." task.name);
67+
Hashtbl.replace tasks task.name task;
68+
Logs.info (fun m -> m "Task [%s] added to the repository." (show_task task))
69+
;;
70+
71+
let remove_by_name name =
72+
if not (Hashtbl.mem tasks name)
73+
then
74+
Logs.err (fun m ->
75+
m "Task [%s] doesn't exist, therefore it can't be deleted." name)
76+
else begin
77+
let task = Hashtbl.find tasks name in
78+
Hashtbl.remove tasks name;
79+
Logs.info (fun m -> m "Task %s successfully deleted." (show_task task))
80+
end
81+
;;
82+
83+
let print_all () =
84+
Logs.app (fun m -> m "List of pending tasks:");
85+
Hashtbl.iter
86+
(fun _ { name; description } ->
87+
Logs.app (fun m -> m "- %s (#%s)" description name))
88+
tasks
89+
;;
90+
end
91+
92+
let extra_exercise () =
93+
let c = Mtime_clock.counter () in
94+
Logs.info (fun m ->
95+
m "======> Starting 4-task insertion for time measuring...");
96+
TaskRepository.add
97+
{ name = "milk"; description = "Buy milk at the grocery store" };
98+
TaskRepository.add
99+
{ name = "exercise"; description = "Have some abdominal exercise b4 sleep" };
100+
TaskRepository.add
101+
{ name = "email"; description = "Send an email to my parents down south" };
102+
TaskRepository.add
103+
{ name = "milk"; description = "Borrow milk from grandma instead" };
104+
(* Adding a tag with the [stamp] function (using the [c] clock counter will
105+
cause the 2nd header of this particualr log line to display the elapsed
106+
time (in microseconds) since the task started (counter created)!
107+
108+
NOTE: On average, inserting these 4 tasks took 40 microseconds. *)
109+
Logs.info (fun m -> m "...Finished 4-task insertion <======" ~tags:(stamp c));
110+
TaskRepository.add { name = "delete"; description = "Please delete this!" };
111+
TaskRepository.remove_by_name "delete";
112+
TaskRepository.remove_by_name "ghost";
113+
TaskRepository.print_all ()
114+
;;
115+
116+
(* Boilerplate code for a custom reporter with a timestamp tag
117+
----------------------------------------------------------------------------
118+
This function is a custom reporter that looks through the set of tags and
119+
extracts the specific one that handles the elapsed span of time since a
120+
given stimestamp [c] (Monotonic clock tick counter). *)
121+
let reporter ppf =
122+
let report _src level ~over k msgf =
123+
let k _ =
124+
over ();
125+
k ()
126+
in
127+
let with_stamp h tags k ppf fmt =
128+
let dt =
129+
Option.(
130+
bind tags (Logs.Tag.find stamp_tag)
131+
|> map (fun s -> Mtime.Span.to_float_ns s /. 1_000.0)
132+
|> map (fun dt -> Printf.sprintf "[%0+4.0fus]" dt)
133+
|> value ~default:"")
134+
in
135+
Format.kfprintf
136+
k
137+
ppf
138+
("%a%s @[" ^^ fmt ^^ "@]@.")
139+
Logs.pp_header
140+
(level, h)
141+
dt
142+
in
143+
msgf @@ fun ?header ?tags fmt -> with_stamp header tags k ppf fmt
144+
in
145+
{ Logs.report }
146+
;;
147+
148+
let _ =
149+
Logs.set_reporter (reporter Format.std_formatter);
150+
Logs.set_level (Some Logs.Info);
151+
log_levels ();
152+
print_newline ();
153+
extra_exercise ();
154+
()
155+
;;

0 commit comments

Comments
 (0)