logging.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /*
  2. * logging.c
  3. * Copyright (C) 2018 Kovid Goyal <kovid at kovidgoyal.net>
  4. *
  5. * Distributed under terms of the GPL3 license.
  6. */
  7. #include "data-types.h"
  8. #include "charsets.h"
  9. #include <stdlib.h>
  10. #include <stdarg.h>
  11. #include <time.h>
  12. #include <sys/time.h>
  13. #ifdef __APPLE__
  14. #include <os/log.h>
  15. #endif
  16. static bool use_os_log = false;
  17. void
  18. log_error(const char *fmt, ...) {
  19. int n = 0;
  20. va_list ar;
  21. va_start(ar, fmt);
  22. n = vsnprintf(NULL, 0, fmt, ar);
  23. va_end(ar);
  24. if (n < 0) return;
  25. size_t size = 5 * (size_t)n + 8;
  26. RAII_ALLOC(char, arena, calloc(size, sizeof(char)));
  27. if (!arena) return;
  28. va_start(ar, fmt);
  29. n = vsnprintf(arena, size, fmt, ar);
  30. va_end(ar);
  31. char *sanbuf = arena + n + 1;
  32. char utf8buf[4];
  33. START_ALLOW_CASE_RANGE
  34. size_t j = 0;
  35. for (char *x = arena; x < arena + n; x++) {
  36. switch(*x) {
  37. case C0_EXCEPT_NL_SPACE_TAB: {
  38. const uint32_t ch = 0x2400 + *x;
  39. const unsigned sz = encode_utf8(ch, utf8buf);
  40. for (unsigned c = 0; c < sz; c++, j++) sanbuf[j] = utf8buf[c];
  41. } break;
  42. default:
  43. sanbuf[j++] = *x;
  44. break;
  45. }
  46. }
  47. sanbuf[j] = 0;
  48. END_ALLOW_CASE_RANGE
  49. if (!use_os_log) { // Apple's os_log already records timestamps
  50. fprintf(stderr, "[%.3f] ", monotonic_t_to_s_double(monotonic()));
  51. }
  52. #ifdef __APPLE__
  53. if (use_os_log) os_log(OS_LOG_DEFAULT, "%{public}s", sanbuf);
  54. #endif
  55. if (!use_os_log) fprintf(stderr, "%s\n", sanbuf);
  56. #undef bufprint
  57. }
  58. static PyObject*
  59. log_error_string(PyObject *self UNUSED, PyObject *args) {
  60. const char *msg;
  61. if (!PyArg_ParseTuple(args, "s", &msg)) return NULL;
  62. log_error("%s", msg);
  63. Py_RETURN_NONE;
  64. }
  65. static PyObject*
  66. set_use_os_log(PyObject *self UNUSED, PyObject *args) {
  67. use_os_log = PyObject_IsTrue(args) ? true : false;
  68. Py_RETURN_NONE;
  69. }
  70. static PyMethodDef module_methods[] = {
  71. METHODB(log_error_string, METH_VARARGS),
  72. METHODB(set_use_os_log, METH_O),
  73. {NULL, NULL, 0, NULL} /* Sentinel */
  74. };
  75. bool
  76. init_logging(PyObject *module) {
  77. if (PyModule_AddFunctions(module, module_methods) != 0) return false;
  78. #ifdef __APPLE__
  79. if (getenv("KITTY_LAUNCHED_BY_LAUNCH_SERVICES") != NULL) use_os_log = true;
  80. #endif
  81. return true;
  82. }