Skip to content

Commit 8990b93

Browse files
[feat] Add pulsar_logger_t as the configurable C logger (apache#162)
### Motivation The current `pulsar_client_configuration_set_logger` API can only configure the `Logger::log` method, but the` Logger::isEnabled` method cannot be configured via C API. apache#158 added a `pulsar_client_configuration_set_logger_and_level` function to configure a log level, but it's not flexible. For example, the log level might be modified dynamically (though it's a complicated case). ### Modifications Add a `pulsar_logger_t` struct and the related `pulsar_client_configuration_set_logger_t` function to configure it as the C logger API. The `is_enabled` and `log` fields of the struct are the responding methods of the `isEnabled` and `log` methods in C++ `Logger`. Then add a `LogContext` example in `SampleCustomLoggerCApi.c` to print logs to a file or standard output. Eliminate the `pulsar_client_configuration_set_logger_and_level` function.
1 parent f3fc502 commit 8990b93

File tree

3 files changed

+117
-33
lines changed

3 files changed

+117
-33
lines changed

examples/SampleCustomLoggerCApi.c

+76-5
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,60 @@
1717
* under the License.
1818
*/
1919

20+
#include <ctype.h>
2021
#include <pulsar/c/client.h>
2122
#include <stdio.h>
2223
#include <stdlib.h>
2324
#include <string.h>
2425
#include <time.h>
2526

2627
char *current_time() {
27-
char *time_str = malloc(128);
28+
char *time_str = (char *)malloc(128);
2829
struct tm *p;
2930
time_t now = time(0);
3031
p = gmtime(&now);
3132
strftime(time_str, 128, "%Y-%m-%d %H:%M:%S", p);
3233
return time_str;
3334
}
3435

35-
void custom_logger(pulsar_logger_level_t level, const char *file, int line, const char *message, void *ctx) {
36+
typedef struct LogContext {
37+
FILE *file;
38+
pulsar_logger_level_t level;
39+
} LogContext;
40+
41+
void log_context_init(LogContext *ctx, const char *level, const char *filename);
42+
void log_context_destroy(LogContext *ctx);
43+
44+
bool is_enabled(pulsar_logger_level_t level, void *ctx) { return level >= ((LogContext *)ctx)->level; }
45+
46+
void log_func(pulsar_logger_level_t level, const char *file, int line, const char *message, void *ctx) {
3647
char *time_str = current_time();
37-
printf("[%s] [%u] [%s] [%d] [%s] \n", time_str, level, file, line, message);
48+
fprintf(((LogContext *)ctx)->file, "[%s] [%u] [%s] [%d] [%s] \n", time_str, level, file, line, message);
3849
free(time_str);
3950
}
4051

41-
int main() {
52+
int main(int argc, char *argv[]) {
53+
if (argc < 2) {
54+
fprintf(stderr,
55+
"Usage: %s log-level <filename>\n\n"
56+
" log-level could be DEBUG, INFO, WARN or ERROR\n"
57+
" If filename is specified, logs will be printed into the given file.\n"
58+
" Otherwise, logs will be printed into the standard output.\n",
59+
argv[0]);
60+
return 1;
61+
}
62+
63+
LogContext ctx;
64+
log_context_init(&ctx, argv[1], (argc > 2) ? argv[2] : NULL);
65+
66+
pulsar_logger_t logger;
67+
logger.ctx = &ctx;
68+
logger.is_enabled = &is_enabled;
69+
logger.log = &log_func;
70+
4271
pulsar_client_configuration_t *conf = pulsar_client_configuration_create();
4372

44-
pulsar_client_configuration_set_logger_and_level(conf, custom_logger, pulsar_DEBUG, NULL);
73+
pulsar_client_configuration_set_logger_t(conf, logger);
4574
pulsar_client_configuration_set_memory_limit(conf, 64 * 1024 * 1024);
4675
pulsar_client_t *client = pulsar_client_create("pulsar://localhost:6650", conf);
4776

@@ -79,4 +108,46 @@ int main() {
79108
pulsar_client_close(client);
80109
pulsar_client_free(client);
81110
pulsar_client_configuration_free(conf);
111+
log_context_destroy(&ctx);
112+
}
113+
114+
static bool str_equal_ignore_case(const char *lhs, const char *rhs) {
115+
int length = strlen(lhs);
116+
for (int i = 0; i < length; i++) {
117+
if (lhs[i] != rhs[i]) {
118+
return false;
119+
}
120+
}
121+
return true;
122+
}
123+
124+
void log_context_init(LogContext *ctx, const char *level, const char *filename) {
125+
if (str_equal_ignore_case(level, "debug")) {
126+
ctx->level = pulsar_DEBUG;
127+
} else if (str_equal_ignore_case(level, "info")) {
128+
ctx->level = pulsar_INFO;
129+
} else if (str_equal_ignore_case(level, "warn")) {
130+
ctx->level = pulsar_WARN;
131+
} else if (str_equal_ignore_case(level, "error")) {
132+
ctx->level = pulsar_ERROR;
133+
} else {
134+
fprintf(stderr, "Unknown log level: %s\n", level);
135+
exit(1);
136+
}
137+
138+
if (filename) {
139+
ctx->file = fopen(filename, "w+");
140+
if (!ctx->file) {
141+
fprintf(stderr, "Failed to open %s\n", filename);
142+
exit(2);
143+
}
144+
} else {
145+
ctx->file = stdout;
146+
}
147+
}
148+
149+
void log_context_destroy(LogContext *ctx) {
150+
if (ctx && ctx->file && ctx->file != stdout) {
151+
fclose(ctx->file);
152+
}
82153
}

include/pulsar/c/client_configuration.h

+12-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#pragma once
2121

2222
#include <pulsar/defines.h>
23+
#include <stdbool.h>
2324

2425
#ifdef __cplusplus
2526
extern "C" {
@@ -36,6 +37,15 @@ typedef enum
3637
typedef void (*pulsar_logger)(pulsar_logger_level_t level, const char *file, int line, const char *message,
3738
void *ctx);
3839

40+
typedef struct pulsar_logger_t {
41+
// The context that will be passed into `is_enabled` and `log` as the last argument
42+
void *ctx;
43+
// Whether to log for the given log level
44+
bool (*is_enabled)(pulsar_logger_level_t level, void *ctx);
45+
// How to log the message
46+
pulsar_logger log;
47+
} pulsar_logger_t;
48+
3949
typedef struct _pulsar_client_configuration pulsar_client_configuration_t;
4050
typedef struct _pulsar_authentication pulsar_authentication_t;
4151

@@ -134,9 +144,8 @@ PULSAR_PUBLIC int pulsar_client_configuration_get_concurrent_lookup_request(
134144
PULSAR_PUBLIC void pulsar_client_configuration_set_logger(pulsar_client_configuration_t *conf,
135145
pulsar_logger logger, void *ctx);
136146

137-
PULSAR_PUBLIC void pulsar_client_configuration_set_logger_and_level(pulsar_client_configuration_t *conf,
138-
pulsar_logger logger,
139-
pulsar_logger_level_t level, void *ctx);
147+
PULSAR_PUBLIC void pulsar_client_configuration_set_logger_t(pulsar_client_configuration_t *conf,
148+
pulsar_logger_t logger);
140149

141150
PULSAR_PUBLIC void pulsar_client_configuration_set_use_tls(pulsar_client_configuration_t *conf, int useTls);
142151

lib/c/c_ClientConfiguration.cc

+29-25
Original file line numberDiff line numberDiff line change
@@ -70,45 +70,49 @@ int pulsar_client_configuration_get_concurrent_lookup_request(pulsar_client_conf
7070
}
7171

7272
class PulsarCLogger : public pulsar::Logger {
73-
std::string file_;
74-
pulsar_logger logger_;
75-
pulsar_logger_level_t level_;
76-
void *ctx_;
77-
7873
public:
79-
PulsarCLogger(const std::string &file, pulsar_logger logger, pulsar_logger_level_t level, void *ctx)
80-
: file_(file), logger_(logger), level_(level), ctx_(ctx) {}
74+
PulsarCLogger(pulsar_logger_t logger, const std::string &fileName)
75+
: logger_(logger), fileName_(fileName) {}
8176

82-
bool isEnabled(Level level) { return (pulsar_logger_level_t)level >= level_; }
77+
bool isEnabled(Level level) override {
78+
return logger_.is_enabled(static_cast<pulsar_logger_level_t>(level), logger_.ctx);
79+
}
8380

84-
void log(Level level, int line, const std::string &message) {
85-
logger_((pulsar_logger_level_t)level, file_.c_str(), line, message.c_str(), ctx_);
81+
void log(Level level, int line, const std::string &message) override {
82+
logger_.log(static_cast<pulsar_logger_level_t>(level), fileName_.c_str(), line, message.c_str(),
83+
logger_.ctx);
8684
}
85+
86+
private:
87+
const pulsar_logger_t logger_;
88+
const std::string fileName_;
8789
};
8890

8991
class PulsarCLoggerFactory : public pulsar::LoggerFactory {
90-
pulsar_logger logger_;
91-
pulsar_logger_level_t level_;
92-
void *ctx_;
93-
9492
public:
95-
PulsarCLoggerFactory(pulsar_logger logger, pulsar_logger_level_t level, void *ctx)
96-
: logger_(logger), level_(level), ctx_(ctx) {}
93+
PulsarCLoggerFactory(pulsar_logger_t logger) : logger_(logger) {}
9794

98-
pulsar::Logger *getLogger(const std::string &fileName) {
99-
return new PulsarCLogger(fileName, logger_, level_, ctx_);
95+
pulsar::Logger *getLogger(const std::string &fileName) override {
96+
return new PulsarCLogger(logger_, fileName);
10097
}
98+
99+
private:
100+
const pulsar_logger_t logger_;
101101
};
102102

103-
void pulsar_client_configuration_set_logger(pulsar_client_configuration_t *conf, pulsar_logger logger,
104-
void *ctx) {
105-
conf->conf.setLogger(new PulsarCLoggerFactory(logger, pulsar_logger_level_t::pulsar_INFO, ctx));
103+
void pulsar_client_configuration_set_logger(pulsar_client_configuration_t *conf,
104+
pulsar_logger logger_function, void *ctx) {
105+
pulsar_logger_t logger;
106+
logger.ctx = ctx;
107+
logger.is_enabled = [](pulsar_logger_level_t level, void *ctx) {
108+
return level >= pulsar_logger_level_t::pulsar_INFO;
109+
};
110+
logger.log = logger_function;
111+
conf->conf.setLogger(new PulsarCLoggerFactory(logger));
106112
}
107113

108-
void pulsar_client_configuration_set_logger_and_level(pulsar_client_configuration_t *conf,
109-
pulsar_logger logger, pulsar_logger_level_t level,
110-
void *ctx) {
111-
conf->conf.setLogger(new PulsarCLoggerFactory(logger, level, ctx));
114+
void pulsar_client_configuration_set_logger_t(pulsar_client_configuration_t *conf, pulsar_logger_t logger) {
115+
conf->conf.setLogger(new PulsarCLoggerFactory(logger));
112116
}
113117

114118
void pulsar_client_configuration_set_use_tls(pulsar_client_configuration_t *conf, int useTls) {

0 commit comments

Comments
 (0)