1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #include <stdio.h>
3 #include <assert.h>
4 #include <iostream>
5 
6 #include <platform/dirutils.h>
7 #include <extensions/protocol_extension.h>
8 #include <memcached/config_parser.h>
9 
10 EXTENSION_LOGGER_DESCRIPTOR *logger;
11 
12 extern "C" {
13     static EXTENSION_LOG_LEVEL get_log_level(void);
14     static bool register_extension(extension_type_t type, void *extension);
15     static void register_callback(ENGINE_HANDLE *eh,
16                                   ENGINE_EVENT_TYPE type,
17                                   EVENT_CALLBACK cb,
18                                   const void *cb_data);
19     static SERVER_HANDLE_V1 *get_server_api(void);
20 }
21 
22 
get_log_level(void)23 static EXTENSION_LOG_LEVEL get_log_level(void)
24 {
25     return EXTENSION_LOG_DETAIL;
26 }
27 
register_extension(extension_type_t type, void *extension)28 static bool register_extension(extension_type_t type, void *extension)
29 {
30     assert(type == EXTENSION_LOGGER);
31     logger = reinterpret_cast<EXTENSION_LOGGER_DESCRIPTOR *>(extension);
32     return true;
33 }
34 
register_callback(ENGINE_HANDLE *eh, ENGINE_EVENT_TYPE type, EVENT_CALLBACK cb, const void *cb_data)35 static void register_callback(ENGINE_HANDLE *eh,
36                               ENGINE_EVENT_TYPE type,
37                               EVENT_CALLBACK cb,
38                               const void *cb_data)
39 {
40     (void)eh;
41     (void)type;
42     (void)cb;
43     (void)cb_data;
44 }
45 
get_server_api(void)46 static SERVER_HANDLE_V1 *get_server_api(void)
47 {
48     static int init;
49     static SERVER_CORE_API core_api;
50     static SERVER_COOKIE_API server_cookie_api;
51     static SERVER_STAT_API server_stat_api;
52     static SERVER_LOG_API server_log_api;
53     static SERVER_EXTENSION_API extension_api;
54     static SERVER_CALLBACK_API callback_api;
55     static ALLOCATOR_HOOKS_API hooks_api;
56     static SERVER_HANDLE_V1 rv;
57 
58     if (!init) {
59         init = 1;
60 
61         core_api.parse_config = parse_config;
62         server_log_api.get_level = get_log_level;
63         extension_api.register_extension = register_extension;
64         callback_api.register_callback = register_callback;
65 
66         rv.interface = 1;
67         rv.core = &core_api;
68         rv.stat = &server_stat_api;
69         rv.extension = &extension_api;
70         rv.callback = &callback_api;
71         rv.log = &server_log_api;
72         rv.cookie = &server_cookie_api;
73         rv.alloc_hooks = &hooks_api;
74     }
75 
76     return &rv;
77 }
78 
remove_files(std::vector<std::string> &files)79 static void remove_files(std::vector<std::string> &files) {
80     for (std::vector<std::string>::iterator iter = files.begin();
81          iter != files.end();
82          ++iter) {
83         CouchbaseDirectoryUtilities::rmrf(*iter);
84     }
85 }
86 
main(int argc, char **argv)87 int main(int argc, char **argv)
88 {
89     EXTENSION_ERROR_CODE ret;
90     int ii;
91 
92     std::vector<std::string> files;
93     files = CouchbaseDirectoryUtilities::findFilesWithPrefix("log_test");
94     if (!files.empty()) {
95         remove_files(files);
96     }
97 
98 
99     // Note: Ensure buffer is at least 4* larger than the expected message
100     // length, otherwise the writer will be blocked waiting for the flusher
101     // thread to timeout and write (as we haven't actually hit the 75%
102     // watermark which would normally trigger an immediate flush).
103     ret = memcached_extensions_initialize("unit_test=true;prettyprint=true;loglevel=warning;cyclesize=1024;buffersize=512;sleeptime=1;filename=log_test", get_server_api);
104     assert(ret == EXTENSION_SUCCESS);
105 
106     for (ii = 0; ii < 8192; ++ii) {
107         logger->log(EXTENSION_LOG_DETAIL, NULL,
108                     "Hei hopp, dette er bare noe tull... Paa tide med kaffe!!");
109     }
110 
111     logger->shutdown();
112 
113     files = CouchbaseDirectoryUtilities::findFilesWithPrefix("log_test");
114 
115     // The cyclesize isn't a hard limit. We don't truncate entries that
116     // won't fit to move to the next file. We'll rather dump the entire
117     // buffer to the file. This means that each file may in theory be
118     // up to a buffersize bigger than the cyclesize.. It is a bit hard
119     // determine the exact number of files we should get here.. Testing
120     // on MacOSX I'm logging 97 bytes in my timezone (summertime), but
121     // on Windows it turned out to be a much longer timezone name etc..
122     // I'm assuming that we should end up with 90+ files..
123     assert(files.size() >= 90);
124     remove_files(files);
125 
126     return 0;
127 }
128