Skip to content

Commit ac33d64

Browse files
committed
Use enum for logging level
1 parent 6a47df5 commit ac33d64

8 files changed

Lines changed: 48 additions & 65 deletions

File tree

c_src/unifex/unifex/logger.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,22 @@ static void free_tags_copy(char **tags, unsigned int tags_length) {
5454
free(tags);
5555
}
5656

57-
static void free_pending_message(char *level, char *message, char **tags,
57+
static void free_pending_message(char *message, char **tags,
5858
unsigned int tags_length) {
59-
free((void *)level);
6059
free((void *)message);
6160
free_tags_copy(tags, tags_length);
6261
}
6362

63+
const char *unifex_log_level_to_string(UnifexLogLevel level) {
64+
switch (level) {
65+
case UNIFEX_LOG_LEVEL_DEBUG: return "debug";
66+
case UNIFEX_LOG_LEVEL_INFO: return "info";
67+
case UNIFEX_LOG_LEVEL_WARN: return "warning";
68+
case UNIFEX_LOG_LEVEL_ERROR: return "error";
69+
default: return "unknown";
70+
}
71+
}
72+
6473
const char *unifex_logger_get_target() { return target_pid_name; }
6574

6675
uint64_t unifex_logger_get_timestamp() {
@@ -113,7 +122,7 @@ void unifex_logger_cleanup() {
113122
pthread_cond_destroy(&queue.cond);
114123
}
115124

116-
bool unifex_log(const char *level, const char *message, const char **tags,
125+
bool unifex_log(UnifexLogLevel level, const char *message, const char **tags,
117126
unsigned int tags_length) {
118127
if (!message) {
119128
return false;
@@ -131,7 +140,6 @@ bool unifex_log(const char *level, const char *message, const char **tags,
131140

132141
uint64_t timestamp = unifex_logger_get_timestamp();
133142

134-
char *level_copy = strdup(level);
135143
char *message_copy = strdup(message);
136144

137145
char **tags_copy = NULL;
@@ -150,8 +158,8 @@ bool unifex_log(const char *level, const char *message, const char **tags,
150158
}
151159
}
152160

153-
if (!level_copy || !message_copy || tags_alloc_failed) {
154-
free_pending_message(level_copy, message_copy, tags_copy, tags_length);
161+
if (!message_copy || tags_alloc_failed) {
162+
free_pending_message(message_copy, tags_copy, tags_length);
155163
return false;
156164
}
157165

@@ -160,11 +168,11 @@ bool unifex_log(const char *level, const char *message, const char **tags,
160168
if (queue.count >= UNIFEX_LOGGER_MAX_QUEUE_SIZE) {
161169
queue.dropped_count++;
162170
pthread_mutex_unlock(&queue.mutex);
163-
free_pending_message(level_copy, message_copy, tags_copy, tags_length);
171+
free_pending_message(message_copy, tags_copy, tags_length);
164172
return false;
165173
}
166174

167-
queue.messages[queue.tail].level = level_copy;
175+
queue.messages[queue.tail].level = level;
168176
queue.messages[queue.tail].message = message_copy;
169177
queue.messages[queue.tail].timestamp = timestamp;
170178
queue.messages[queue.tail].tags = tags_copy;
@@ -213,7 +221,7 @@ void *unifex_logger_worker(void *arg) {
213221
send_log_func(global_env, batch[i].level, batch[i].message,
214222
batch[i].timestamp, batch[i].tags, batch[i].tags_length);
215223
}
216-
free_pending_message(batch[i].level, batch[i].message, batch[i].tags,
224+
free_pending_message(batch[i].message, batch[i].tags,
217225
batch[i].tags_length);
218226
}
219227

c_src/unifex/unifex/logger.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,19 @@ extern "C" {
2323
#define UNIFEX_LOGGER_BACKEND_CTOR_PRIORITY 1000
2424
#define UNIFEX_LOGGER_QUEUE_CTOR_PRIORITY 2000
2525

26-
// Log level constants
27-
#define UNIFEX_LOG_LEVEL_DEBUG "debug"
28-
#define UNIFEX_LOG_LEVEL_INFO "info"
29-
#define UNIFEX_LOG_LEVEL_WARN "warning"
30-
#define UNIFEX_LOG_LEVEL_ERROR "error"
26+
// Log level enum for compile-time type safety
27+
typedef enum {
28+
UNIFEX_LOG_LEVEL_DEBUG,
29+
UNIFEX_LOG_LEVEL_INFO,
30+
UNIFEX_LOG_LEVEL_WARN,
31+
UNIFEX_LOG_LEVEL_ERROR,
32+
} UnifexLogLevel;
33+
34+
// Convert log level enum to string representation (for internal use by backends)
35+
const char *unifex_log_level_to_string(UnifexLogLevel level);
3136

3237
typedef struct {
33-
char *level;
38+
UnifexLogLevel level;
3439
char *message;
3540
uint64_t timestamp;
3641
char **tags;
@@ -49,15 +54,15 @@ typedef struct {
4954
pthread_t worker_thread;
5055
} UnifexLoggerQueue;
5156

52-
typedef int (*UnifexLoggerSendFunc)(void *env, const char *level,
57+
typedef int (*UnifexLoggerSendFunc)(void *env, UnifexLogLevel level,
5358
const char *message, uint64_t timestamp,
5459
char **tags, unsigned int tags_length);
5560

5661
void unifex_logger_init();
5762

5863
void unifex_logger_cleanup();
5964

60-
bool unifex_log(const char *level, const char *message, const char **tags,
65+
bool unifex_log(UnifexLogLevel level, const char *message, const char **tags,
6166
unsigned int tags_length);
6267

6368
void unifex_logger_register_send_func(UnifexLoggerSendFunc func);

c_src/unifex/unifex/logger_backend.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@
66
* Include the appropriate backend implementation in your project.
77
*/
88

9+
#include "logger.h"
10+
911
#ifdef __cplusplus
1012
extern "C" {
1113
#endif
1214

13-
int unifex_logger_nif_send(void *env, const char *level, const char *message,
15+
int unifex_logger_nif_send(void *env, UnifexLogLevel level, const char *message,
1416
uint64_t timestamp, char **tags,
1517
unsigned int tags_length);
1618

17-
int unifex_logger_cnode_send(void *env, const char *level, const char *message,
19+
int unifex_logger_cnode_send(void *env, UnifexLogLevel level, const char *message,
1820
uint64_t timestamp, char **tags,
1921
unsigned int tags_length);
2022

c_src/unifex/unifex/logger_cnode.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include "logger.h"
1111
#include "logger_backend.h"
1212

13-
int unifex_logger_cnode_send(void *env_ptr, const char *level,
13+
int unifex_logger_cnode_send(void *env_ptr, UnifexLogLevel level,
1414
const char *message, uint64_t timestamp,
1515
char **tags, unsigned int tags_length) {
1616
UnifexEnv *env = (UnifexEnv *)env_ptr;
@@ -25,7 +25,7 @@ int unifex_logger_cnode_send(void *env_ptr, const char *level,
2525

2626
ei_x_encode_atom(&out_buff, "unifex_logger");
2727

28-
ei_x_encode_atom(&out_buff, level);
28+
ei_x_encode_atom(&out_buff, unifex_log_level_to_string(level));
2929

3030
ei_x_encode_binary(&out_buff, message, strlen(message));
3131

c_src/unifex/unifex/logger_nif.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
static UnifexEnv *fallback_env = NULL;
1313

14-
int unifex_logger_nif_send(void *env_ptr, const char *level,
14+
int unifex_logger_nif_send(void *env_ptr, UnifexLogLevel level,
1515
const char *message, uint64_t timestamp, char **tags,
1616
unsigned int tags_length) {
1717
UnifexEnv *env = (UnifexEnv *)env_ptr;
@@ -37,7 +37,7 @@ int unifex_logger_nif_send(void *env_ptr, const char *level,
3737
return 0;
3838
}
3939

40-
ERL_NIF_TERM level_atom = enif_make_atom(send_env, level);
40+
ERL_NIF_TERM level_atom = enif_make_atom(send_env, unifex_log_level_to_string(level));
4141
ERL_NIF_TERM message_term = unifex_string_to_term(send_env, message);
4242
ERL_NIF_TERM timestamp_term = enif_make_uint64(send_env, timestamp);
4343

lib/unifex/logger.ex

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ defmodule Unifex.Logger do
44
use GenServer
55
require Logger
66

7-
@valid_levels ~w(emergency alert critical error warning notice info debug)a
8-
97
@spec start_link(any()) :: GenServer.on_start()
108
def start_link(_opts) do
119
GenServer.start_link(__MODULE__, [], name: __MODULE__)
@@ -17,13 +15,16 @@ defmodule Unifex.Logger do
1715
end
1816

1917
@impl true
20-
@spec handle_info({:unifex_logger, atom(), String.t(), integer(), list(atom())}, map()) ::
18+
@spec handle_info(
19+
{:unifex_logger, atom() | String.t(), String.t(), integer(), list(String.t())},
20+
map()
21+
) ::
2122
{:noreply, map()}
2223
def handle_info({:unifex_logger, level, message, timestamp, tags}, state) do
2324
metadata = [tags: tags, unifex_nif: true, timestamp: timestamp]
2425

2526
Logger.log(
26-
normalize_level(level),
27+
level,
2728
fn -> format_message(message, tags, timestamp) end,
2829
metadata
2930
)
@@ -38,21 +39,7 @@ defmodule Unifex.Logger do
3839
end
3940

4041
@doc false
41-
@spec normalize_level(atom()) :: atom()
42-
def normalize_level(level) when level in @valid_levels, do: level
43-
44-
@doc false
45-
@spec normalize_level(any()) :: atom()
46-
def normalize_level(level) do
47-
Logger.warning(
48-
"Unifex.Logger received unknown log level #{inspect(level)}, defaulting to :info"
49-
)
50-
51-
:info
52-
end
53-
54-
@doc false
55-
@spec format_message(String.t(), list(atom()), integer()) :: String.t()
42+
@spec format_message(String.t(), list(String.t()), integer()) :: String.t()
5643
def format_message(message, tags, timestamp) do
5744
tag_parts = Enum.map(tags, &"[#{&1}]")
5845
Enum.join(["[#{format_timestamp(timestamp)}]"] ++ tag_parts ++ [message], " ")

pages/logger.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ UNIFEX_TERM process(UnifexEnv *env, int num) {
5050
### `unifex_log`
5151
5252
```c
53-
bool unifex_log(const char *level, const char *message, const char **tags,
53+
bool unifex_log(UnifexLogLevel level, const char *message, const char **tags,
5454
unsigned int tags_length);
5555
```
5656

57-
* `level` - one of the `UNIFEX_LOG_LEVEL_DEBUG` / `_INFO` / `_WARN` / `_ERROR` constants
58-
(or any other string; it's copied, so any level your `Unifex.Logger` handler
59-
understands works).
57+
* `level` - one of the `UNIFEX_LOG_LEVEL_DEBUG`, `UNIFEX_LOG_LEVEL_INFO`,
58+
`UNIFEX_LOG_LEVEL_WARN`, or `UNIFEX_LOG_LEVEL_ERROR` enum values. This is a
59+
typed enum, so the compiler will catch typos or invalid values at compile time.
6060
* `message` - the log message. Must not be `NULL`.
6161
* `tags` / `tags_length` - an optional array of extra tag strings attached to the
6262
message (pass `NULL, 0` for none).

test/unifex/logger_test.exs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,6 @@ defmodule Unifex.LoggerTest do
1515
end
1616
end
1717

18-
test "normalizes valid log levels" do
19-
assert Unifex.Logger.normalize_level(:debug) == :debug
20-
assert Unifex.Logger.normalize_level(:info) == :info
21-
assert Unifex.Logger.normalize_level(:warning) == :warning
22-
assert Unifex.Logger.normalize_level(:error) == :error
23-
assert Unifex.Logger.normalize_level(:critical) == :critical
24-
assert Unifex.Logger.normalize_level(:alert) == :alert
25-
assert Unifex.Logger.normalize_level(:emergency) == :emergency
26-
assert Unifex.Logger.normalize_level(:notice) == :notice
27-
end
28-
29-
test "normalizes invalid log levels to :info with warning" do
30-
# This test verifies that unknown levels are normalized to :info
31-
# The warning is a side effect that we can't easily capture here
32-
assert Unifex.Logger.normalize_level(:unknown_level) == :info
33-
assert Unifex.Logger.normalize_level("string_level") == :info
34-
assert Unifex.Logger.normalize_level(123) == :info
35-
end
36-
3718
test "formats message without tags" do
3819
# microseconds since epoch
3920
timestamp = 1_700_000_000_000_000

0 commit comments

Comments
 (0)