summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2025-02-25 14:41:59 -0500
committerpommicket <pommicket@gmail.com>2025-02-25 15:16:09 -0500
commit5626363c05bd379047cbe102feaceb18a04a738c (patch)
tree5e9599171fc38a61f1f53988627013b289377f1e
parent9b90ceee792cb51917af474ddcbc47edaacff16b (diff)
start logger
-rw-r--r--camera.c8
-rw-r--r--camera.h5
-rw-r--r--log.c67
-rw-r--r--log.h16
-rw-r--r--main.c66
-rw-r--r--meson.build2
-rw-r--r--util.h5
7 files changed, 148 insertions, 21 deletions
diff --git a/camera.c b/camera.c
index 0a11ff2..397bdc1 100644
--- a/camera.c
+++ b/camera.c
@@ -1067,12 +1067,16 @@ Hash camera_hash(Camera *camera) {
return camera->hash;
}
-void camera_hash_str(Camera *camera, char str[HASH_SIZE * 2 + 1]) {
+void hash_to_str(Hash h, char str[HASH_STR_SIZE]) {
for (int i = 0; i < HASH_SIZE; i++) {
- sprintf(&str[2*i], "%02x", camera->hash.hash[i]);
+ sprintf(&str[2*i], "%02x", h.hash[i]);
}
}
+void camera_hash_str(Camera *camera, char str[HASH_STR_SIZE]) {
+ hash_to_str(camera->hash, str);
+}
+
const char *camera_devnode(Camera *camera) {
return camera->devnode;
}
diff --git a/camera.h b/camera.h
index 163bfbf..8e991dd 100644
--- a/camera.h
+++ b/camera.h
@@ -100,6 +100,9 @@ static bool hash_eq(Hash h1, Hash h2) {
return memcmp(h1.hash, h2.hash, sizeof h1.hash) == 0;
}
+#define HASH_STR_SIZE (2 * HASH_SIZE + 1)
+
+void hash_to_str(Hash h, char str[HASH_STR_SIZE]);
void camera_init(const GlProcs *procs);
bool pix_fmt_supported(uint32_t pixfmt);
int picture_format_cmp_resolution(const PictureFormat *a, const PictureFormat *b);
@@ -128,7 +131,7 @@ void camera_close(Camera *camera);
void cameras_from_device(const char *dev_path, const char *serial, Camera ***cameras);
bool camera_open(Camera *camera, PictureFormat desired_format, int desired_framerate);
Hash camera_hash(Camera *camera);
-void camera_hash_str(Camera *camera, char str[HASH_SIZE * 2 + 1]);
+void camera_hash_str(Camera *camera, char str[HASH_STR_SIZE]);
bool camera_set_format(Camera *camera, PictureFormat picfmt, int desired_framerate, CameraAccessMethod access, bool force);
/// Copy current frame from camera to AVFrame.
///
diff --git a/log.c b/log.c
new file mode 100644
index 0000000..a4e585d
--- /dev/null
+++ b/log.c
@@ -0,0 +1,67 @@
+#include "log.h"
+#include <stdbool.h>
+#include <unistd.h>
+
+static FILE *log_file = NULL;
+
+static void get_timestamp(char timestamp[24]) {
+ struct tm tm = {0};
+ localtime_r((const time_t[1]) { time(NULL) }, &tm);
+ strftime(timestamp, 24, "[%Y-%m-%d %H:%M:%S]", &tm);
+}
+
+void log_init(const char *out) {
+ assert(!log_file);
+ log_file = fopen(out, "a");
+ if (log_file) {
+ char timestamp[24] = {0};
+ get_timestamp(timestamp);
+ fprintf(log_file, "\n\n--- new session %s ---\n", timestamp);
+ } else {
+ perror("fopen");
+ }
+}
+
+void log_message(int severity, const char *fmt, va_list args) {
+ char *message = va_sprintf(fmt, args);
+ if (!message) return;
+ if (log_file) {
+ char timestamp[24] = {0};
+ get_timestamp(timestamp);
+ fprintf(log_file, "%s ", timestamp);
+ }
+ const char *color_start = "", *severity_str = "???";
+ switch (severity) {
+ case LOG_ERROR:
+ color_start = "\x1b[91m";
+ severity_str = "error";
+ break;
+ case LOG_WARNING:
+ color_start = "\x1b[93m";
+ severity_str = "warning";
+ break;
+ }
+ bool color = isatty(2) == 1;
+ if (color)
+ fprintf(stderr, "%s", color_start);
+ fprintf(stderr, "%s: ", severity_str);
+ if (color)
+ fprintf(stderr, "\x1b[0m");
+ fprintf(stderr, "%s\n", message);
+ if (log_file) fprintf(log_file, "%s: %s\n", severity_str, message);
+ free(message);
+}
+
+void log_error(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ log_message(LOG_ERROR, fmt, args);
+ va_end(args);
+}
+
+void log_warning(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ log_message(LOG_WARNING, fmt, args);
+ va_end(args);
+}
diff --git a/log.h b/log.h
new file mode 100644
index 0000000..b739837
--- /dev/null
+++ b/log.h
@@ -0,0 +1,16 @@
+#ifndef LOG_H_
+#define LOG_H_
+
+#include "util.h"
+
+enum {
+ LOG_WARNING = 20,
+ LOG_ERROR = 30,
+};
+
+void log_init(const char *out);
+void log_message(int severity, const char *fmt, va_list args);
+void log_error(PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(1, 2);
+void log_warning(PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(1, 2);
+
+#endif
diff --git a/main.c b/main.c
index 084c38c..d80844b 100644
--- a/main.c
+++ b/main.c
@@ -21,6 +21,7 @@ TODO
#include "util.h"
#include "camera.h"
#include "video.h"
+#include "log.h"
// pixel format used for convenience
#define PIX_FMT_XXXGRAY 0x47585858
@@ -114,6 +115,9 @@ static const int timer_options[] = {0, 2, 5, 10, 15, 30};
#endif
static GlProcs gl;
+static char home_dir[PATH_MAX];
+static char config_dir[PATH_MAX];
+
static void select_camera(State *state);
static void fatal_error(PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(1, 2);
@@ -123,6 +127,7 @@ static void fatal_error(const char *fmt, ...) {
static char message[256];
vsnprintf(message, sizeof message, fmt, args);
va_end(args);
+ log_error("%s", message);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "camlet error", message, NULL);
exit(EXIT_FAILURE);
}
@@ -623,7 +628,6 @@ static void get_cameras_from_udev_device(State *state, struct udev_device *dev)
str_builder_free(&serial);
}
-static char home_dir[PATH_MAX];
static bool get_expanded_output_dir(State *state, char path[PATH_MAX]) {
Settings *settings = &state->settings;
while (settings->output_dir && settings->output_dir[0] &&
@@ -707,22 +711,8 @@ int main(void) {
static State state_data;
State *state = &state_data;
Settings *settings = &state->settings;
- SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1"); // if this program is sent a SIGTERM/SIGINT, don't turn it into a quit event
- if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
- fprintf(stderr, "couldn't initialize SDL\n");
- return EXIT_FAILURE;
- }
- if (sodium_init() < 0) {
- fatal_error("couldn't initialize libsodium");
- }
- if (!FcInit()) {
- fatal_error("couldn't initialize fontconfig");
- }
- #define FcFini "don't call FcFini: it's broken on certain versions of fontconfig - https://github.com/brndnmtthws/conky/pull/1755"
- if (TTF_Init() < 0) {
- fatal_error("couldn't initialize SDL2_ttf: %s\n", TTF_GetError());
- }
{
+ // get home directory
const char *home = getenv("HOME");
if (home) {
snprintf(home_dir, sizeof home_dir, "%s", home);
@@ -736,6 +726,48 @@ int main(void) {
}
}
}
+ {
+ // get config directory
+ const char *cfg = getenv("XDG_CONFIG_HOME");
+ if (cfg) {
+ snprintf(config_dir, sizeof config_dir, "%s/camlet", cfg);
+ } else {
+ snprintf(config_dir, sizeof config_dir, "%s/.config/camlet", home_dir);
+ }
+ mkdir_with_parents(config_dir);
+ // set log path
+ char *log_path = a_sprintf("%s/log.txt", config_dir);
+ struct stat statbuf = {0};
+ stat(log_path, &statbuf);
+ if (statbuf.st_size > (128l << 10)) {
+ // keep old log around and start a new one
+ char *old_log_path = a_sprintf("%s/log_old.txt", config_dir);
+ remove(old_log_path);
+ rename(log_path, old_log_path);
+ free(old_log_path);
+ }
+ if (log_path) {
+ log_init(log_path);
+ } else {
+ perror("a_sprintf");
+ }
+ free(log_path);
+ }
+ SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1"); // if this program is sent a SIGTERM/SIGINT, don't turn it into a quit event
+ if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
+ log_error("couldn't initialize SDL");
+ return EXIT_FAILURE;
+ }
+ if (sodium_init() < 0) {
+ fatal_error("couldn't initialize libsodium");
+ }
+ if (!FcInit()) {
+ fatal_error("couldn't initialize fontconfig");
+ }
+ #define FcFini "don't call FcFini: it's broken on certain versions of fontconfig - https://github.com/brndnmtthws/conky/pull/1755"
+ if (TTF_Init() < 0) {
+ fatal_error("couldn't initialize SDL2_ttf: %s", TTF_GetError());
+ }
char *font_path = NULL;
{
// find a suitable font
@@ -1037,7 +1069,7 @@ void main() {\n\
for (size_t i = 0; i < arr_len(state->cameras); i++) {
Camera *camera = state->cameras[i];
printf("[%zu] %s ", i, camera_name(camera));
- char buf[HASH_SIZE * 2 + 1] = {0};
+ char buf[HASH_STR_SIZE] = {0};
camera_hash_str(camera, buf);
printf("%s", buf);
printf("\n");
diff --git a/meson.build b/meson.build
index 706a021..ccceffb 100644
--- a/meson.build
+++ b/meson.build
@@ -27,6 +27,6 @@ if get_option('debug')
else
debug_def = '-DDEBUG=0'
endif
-executable('camlet', 'main.c', 'camera.c', 'video.c', '3rd_party/stb_image_write.c',
+executable('camlet', 'main.c', 'camera.c', 'video.c', 'log.c', '3rd_party/stb_image_write.c',
dependencies: [v4l2, sdl2, sdl2_ttf, gl, udev, sodium, fontconfig, jpeg, avcodec, avformat, avutil, pulse, pulse_simple],
c_args: ['-Wno-unused-function', '-Wno-format-truncation', '-Wshadow', debug_def])
diff --git a/util.h b/util.h
index 0a87c0c..4aedcd9 100644
--- a/util.h
+++ b/util.h
@@ -1,3 +1,6 @@
+#ifndef UTIL_H_
+#define UTIL_H_
+
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
@@ -44,3 +47,5 @@ static uint8_t popcount64(uint64_t x) {
}
return cnt;
}
+
+#endif