logr.ml 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  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. type t = Target of Format.formatter
  29. let output = ref (Target Format.err_formatter)
  30. let tz_offset_s = ref 0
  31. let min_level = 1
  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. *
  37. * keep stdout exclusive for response!
  38. *)
  39. let open_out fn =
  40. let tz = Timedesc.Time_zone.(local() |> Option.value ~default:utc) in
  41. tz_offset_s := Ptime_clock.now() |> Rfc3339.tz_offset_s tz;
  42. if 10 * mb < try (Unix.stat fn).st_size with _ -> 0
  43. then Unix.rename fn (fn ^ ".0");
  44. let c = open_out_gen [ Open_wronly; Open_append; Open_creat; Open_binary ] 0o644 fn
  45. |> Format.formatter_of_out_channel in
  46. output := Target c
  47. let close_out () =
  48. let Target lc = !output in
  49. Format.pp_print_flush lc
  50. let msg' (Target lc) (level : Logs.level) msgf =
  51. let now = Ptime_clock.now () |> Ptime.to_rfc3339 ~tz_offset_s:!tz_offset_s ~frac_s:3 in
  52. let w (lvi : int) (lv : string) =
  53. if min_level <= lvi then (
  54. Format.fprintf lc "%s %s " now lv;
  55. msgf (Format.fprintf lc);
  56. Format.fprintf lc "\n%!"
  57. (* flush %! here seems necessary, or if run as a CGI under lighttpd/1.4.59 writes
  58. * are silently dropped. Not so if run from the shell (with sudo -u www-data)
  59. *)
  60. )
  61. in
  62. (match level with
  63. | Logs.App -> ()
  64. | Logs.Debug -> w 0 "DEBUG"
  65. | Logs.Info -> w 1 "INFO "
  66. | Logs.Warning -> w 2 "WARN "
  67. | Logs.Error -> w 3 "ERROR"
  68. )
  69. let msg lv = msg' (!output) lv
  70. let err fm = msg Logs.Error fm
  71. let warn fm = msg Logs.Warning fm
  72. let info fm = msg Logs.Info fm
  73. let debug fm = msg Logs.Debug fm