logr.ml 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. (*
  2. * _ _ ____ _
  3. * _| || |_/ ___| ___ _ __ _ __ ___ | |
  4. * |_ .. _\___ \ / _ \ '_ \| '_ \ / _ \| |
  5. * |_ _|___) | __/ |_) | |_) | (_) |_|
  6. * |_||_| |____/ \___| .__/| .__/ \___/(_)
  7. * |_| |_|
  8. *
  9. * Personal Social Web.
  10. *
  11. * logr.ml
  12. *
  13. * Copyright (C) The #Seppo contributors. All rights reserved.
  14. *
  15. * This program is free software: you can redistribute it and/or modify
  16. * it under the terms of the GNU General Public License as published by
  17. * the Free Software Foundation, either version 3 of the License, or
  18. * (at your option) any later version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  27. *)
  28. let min_level = 1
  29. type t = Target of Format.formatter
  30. let output = ref (Target Format.err_formatter)
  31. let tz_offset_s = ref 0
  32. let kb = 1024
  33. let mb = kb * kb
  34. (** start logging to the file app/var/log/seppo.log like e.g.
  35. https://github.com/oxidizing/sihl/blob/c6786f25424c1b9f40ce656e908bd31515f1cd09/sihl/src/core_log.ml#L18
  36. keep stdout exclusive for response!
  37. *)
  38. let open_out ?(max_size = 10 * mb) fn =
  39. let tz = Timedesc.Time_zone.(local() |> Option.value ~default:utc) in
  40. tz_offset_s := Ptime_clock.now() |> Rfc3339.tz_offset_s tz;
  41. if max_size < try (Unix.stat fn).st_size with _ -> 0
  42. then Unix.rename fn (fn ^ ".0");
  43. let c = open_out_gen [ Open_wronly; Open_append; Open_creat; Open_binary ] 0o644 fn
  44. |> Format.formatter_of_out_channel in
  45. output := Target c
  46. let close_out () =
  47. let Target lc = !output in
  48. Format.pp_print_flush lc ();
  49. let c = Stdlib.stderr |> Format.formatter_of_out_channel in
  50. output := Target c
  51. let msg' (Target lc) (level : Logs.level) msgf =
  52. let now = Ptime_clock.now () |> Ptime.to_rfc3339 ~tz_offset_s:!tz_offset_s ~frac_s:3 in
  53. let w (lvi : int) (lv : string) =
  54. if min_level <= lvi then (
  55. Format.fprintf lc "%s %s " now lv;
  56. msgf (Format.fprintf lc);
  57. Format.fprintf lc "\n%!"
  58. (* flush %! here seems necessary, or if run as a CGI under lighttpd/1.4.59 writes
  59. are silently dropped. Not so if run from the shell (with sudo -u www-data)
  60. *)
  61. )
  62. in
  63. (match level with
  64. | Logs.App -> ()
  65. | Logs.Debug -> w 0 "DEBUG"
  66. | Logs.Info -> w 1 "INFO "
  67. | Logs.Warning -> w 2 "WARN "
  68. | Logs.Error -> w 3 "ERROR"
  69. )
  70. let msg lv = msg' (!output) lv
  71. let err fm = msg Logs.Error fm
  72. let warn fm = msg Logs.Warning fm
  73. let info fm = msg Logs.Info fm
  74. let debug fm = msg Logs.Debug fm