Commit 91c7cc97 authored by 957dd's avatar 957dd

UTF-8

parent c82ad482
zlog @ 5de0ce76
Subproject commit 5de0ce7607ae70a8a654f6fb050a5d25d96a6728
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
# zlog
zlog is a reliable, high-performance, thread safe, flexible, clear-model, pure C logging library.
Actually, in the C world there was NO good logging library for applications like logback in java or log4cxx in c++.
Using printf can work, but can not be redirected or reformatted easily. syslog is slow and is designed for system use.
So I wrote zlog.
It is faster, safer and more powerful than log4c. So it can be widely used.
## 1. Install
Downloads: <https://github.com/HardySimpson/zlog/releases>
```bash
tar -zxvf zlog-latest-stable.tar.gz
cd zlog-latest-stable/
make
sudo make install
```
Or
```bash
make PREFIX=/usr/local/
sudo make PREFIX=/usr/local/ install
```
PREFIX indicates the installation destination for zlog. After installation, refresh your dynamic linker to make sure
your program can find zlog library.
```bash
$ sudo vi /etc/ld.so.conf
/usr/local/lib
$ sudo ldconfig
```
Before running a real program, make sure libzlog.so is in the directory where the system's dynamic lib loader can find
it. The command metioned above are for linux. Other systems will need a similar set of actions.
## 2. Configuration file
There are 3 important concepts in zlog: categories, formats and rules.
Categories specify different kinds of log entries. In the zlog source code, category is a `zlog_category_t *` variable.
In your program, different categories for the log entries will distinguish them from each other.
Formats describe log patterns, such as: with or without time stamp, source file, source line.
Rules consist of category, level, output file (or other channel) and format. In brief, if the category string in a rule
in the configuration file equals the name of a category variable in the source, then they match. Still there is complex
match range of category. Rule decouples variable conditions. For example, log4j must specify a level for each logger(or
inherit from father logger). That's not convenient when each grade of logger has its own level for output(child logger
output at the level of debug, when father logger output at the level of error)
Now create a configuration file. The function zlog_init takes the files path as its only argument.
```bash
$ cat /etc/zlog.conf
[formats]
simple = "%m%n"
[rules]
my_cat.DEBUG >stdout; simple
```
In the configuration file log messages in the category `my_cat` and a level of DEBUG or higher are output to standard
output, with the format of simple `%m - usermessage %n - newline`. If you want to direct out to a file and limit the
files maximum size, use this configuration
```config
my_cat.DEBUG "/var/log/aa.log", 1M; simple
```
## 3. Using zlog API in C source file
### 3.1 Sample code
```bash
$ vi test_hello.c
#include <stdio.h>
#include "zlog.h"
int main(int argc, char** argv)
{
int rc;
zlog_category_t *c;
rc = zlog_init("/etc/zlog.conf");
if (rc) {
printf("init failed\n");
return -1;
}
c = zlog_get_category("my_cat");
if (!c) {
printf("get cat fail\n");
zlog_fini();
return -2;
}
zlog_info(c, "hello, zlog");
zlog_fini();
return 0;
}
```
### 3.2 Compile, and run it
```bash
$ cc -c -o test_hello.o test_hello.c -I/usr/local/include
$ cc -o test_hello test_hello.o -L/usr/local/lib -lzlog -lpthread
$ ./test_hello
hello, zlog
```
## 4. Advanced Usage
* syslog model, better than log4j model
* log format customization
* multiple output destinations including static file path, dynamic file path, stdout, stderr, syslog, user-defined
output
* runtime manually or automatically refresh configure(safely)
* high-performance, 250'000 logs/second on my laptop, about 1000 times faster than syslog(3) with rsyslogd
* user-defined log level
* thread-safe and process-safe log file rotation
* microsecond accuracy
* dzlog, a default category log API for easy use
* MDC, a log4j style key-value map
* self debuggable, can output zlog's self debug&error log at runtime
* No external dependencies, just based on a POSIX system and a C99 compliant vsnprintf.
## 5. Reference
* Homepage: <http://hardysimpson.github.io/zlog>
* Downloads: <https://github.com/HardySimpson/zlog/releases>
* Author's Email: <HardySimpson1984@gmail.com>
* Auto tools version: <https://github.com/bmanojlovic/zlog>
* CMake verion: <https://github.com/lisongmin/zlog>
* Windows version: <https://github.com/lopsd07/WinZlog>
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <stdint.h>
#include "zc_defs.h"
#include "buf.h"
/*******************************************************************************/
/* Author's Note
* This buf.c is base on C99, that is, if buffer size is not enough,
* the return value of vsnprintf(3) is a number tell how many character should
* be output. vsnprintf in glibc 2.1 conforms to C99 , but glibc 2.0 doesn't.
* see manpage of vsnprintf(3) on you platform for more detail.
* So, what should you do if you want to using zlog on the platform that doesn't
* conform C99? My Answer is, crack zlog with a portable C99-vsnprintf, like this
* http://sourceforge.net/projects/ctrio/
* http://www.jhweiss.de/software/snprintf.html
* If you can see this note, you can fix it yourself? Aren't you? ^_^
* Oh, I put the snprintf in C99 standard here,
* vsnprintf is the same on return value.
7.19.6.5 The snprintf function
Synopsis
[#1]
#include <stdio.h>
int snprintf(char * restrict s, size_t n,
const char * restrict format, ...);
Description
[#2] The snprintf function is equivalent to fprintf, except
that the output is written into an array (specified by
argument s) rather than to a stream. If n is zero, nothing
is written, and s may be a null pointer. Otherwise, output
characters beyond the n-1st are discarded rather than being
written to the array, and a null character is written at the
end of the characters actually written into the array. If
copying takes place between objects that overlap, the
behavior is undefined.
Returns
[#3] The snprintf function returns the number of characters
that would have been written had n been sufficiently large,
not counting the terminating null character, or a negative
value if an encoding error occurred. Thus, the null-
terminated output has been completely written if and only if
the returned value is nonnegative and less than n.
*/
/*******************************************************************************/
void zlog_buf_profile(zlog_buf_t * a_buf, int flag)
{
//zc_assert(a_buf,);
zc_profile(flag, "---buf[%p][%ld-%ld][%ld][%s][%p:%ld]---",
a_buf,
a_buf->size_min, a_buf->size_max,
a_buf->size_real,
a_buf->truncate_str,
a_buf->start, a_buf->tail - a_buf->start);
return;
}
/*******************************************************************************/
void zlog_buf_del(zlog_buf_t * a_buf)
{
//zc_assert(a_buf,);
if (a_buf->start) free(a_buf->start);
zc_debug("zlog_buf_del[%p]", a_buf);
free(a_buf);
return;
}
zlog_buf_t *zlog_buf_new(size_t buf_size_min, size_t buf_size_max, const char *truncate_str)
{
zlog_buf_t *a_buf;
if (buf_size_min == 0) {
zc_error("buf_size_min == 0, not allowed");
return NULL;
}
if (buf_size_max != 0 && buf_size_max < buf_size_min) {
zc_error("buf_size_max[%lu] < buf_size_min[%lu] && buf_size_max != 0",
(unsigned long)buf_size_max, (unsigned long)buf_size_min);
return NULL;
}
a_buf = calloc(1, sizeof(*a_buf));
if (!a_buf) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
if (truncate_str) {
if (strlen(truncate_str) > sizeof(a_buf->truncate_str) - 1) {
zc_error("truncate_str[%s] overflow", truncate_str);
goto err;
} else {
strcpy(a_buf->truncate_str, truncate_str);
}
a_buf->truncate_str_len = strlen(truncate_str);
}
a_buf->size_min = buf_size_min;
a_buf->size_max = buf_size_max;
a_buf->size_real = a_buf->size_min;
a_buf->start = calloc(1, a_buf->size_real);
if (!a_buf->start) {
zc_error("calloc fail, errno[%d]", errno);
goto err;
}
a_buf->tail = a_buf->start;
a_buf->end_plus_1 = a_buf->start + a_buf->size_real;
a_buf->end = a_buf->end_plus_1 - 1;
//zlog_buf_profile(a_buf, ZC_DEBUG);
return a_buf;
err:
zlog_buf_del(a_buf);
return NULL;
}
/*******************************************************************************/
static void zlog_buf_truncate(zlog_buf_t * a_buf)
{
char *p;
size_t len;
if ((a_buf->truncate_str)[0] == '\0') return;
p = (a_buf->tail - a_buf->truncate_str_len);
if (p < a_buf->start) p = a_buf->start;
len = a_buf->tail - p;
memcpy(p, a_buf->truncate_str, len);
return;
}
/*******************************************************************************/
/* return 0: success
* return <0: fail, set size_real to -1;
* return >0: by conf limit, can't extend size
* increment must > 0
*/
static int zlog_buf_resize(zlog_buf_t * a_buf, size_t increment)
{
int rc = 0;
size_t new_size = 0;
size_t len = 0;
char *p = NULL;
if (a_buf->size_max != 0 && a_buf->size_real >= a_buf->size_max) {
zc_error("a_buf->size_real[%ld] >= a_buf->size_max[%ld]",
a_buf->size_real, a_buf->size_max);
return 1;
}
if (a_buf->size_max == 0) {
/* unlimit */
new_size = a_buf->size_real + 1.5 * increment;
} else {
/* limited */
if (a_buf->size_real + increment <= a_buf->size_max) {
new_size = a_buf->size_real + increment;
} else {
new_size = a_buf->size_max;
rc = 1;
}
}
len = a_buf->tail - a_buf->start;
p = realloc(a_buf->start, new_size);
if (!p) {
zc_error("realloc fail, errno[%d]", errno);
free(a_buf->start);
a_buf->start = NULL;
a_buf->tail = NULL;
a_buf->end = NULL;
a_buf->end_plus_1 = NULL;
return -1;
} else {
a_buf->start = p;
a_buf->tail = p + len;
a_buf->size_real = new_size;
a_buf->end_plus_1 = a_buf->start + new_size;
a_buf->end = a_buf->end_plus_1 - 1;
}
return rc;
}
int zlog_buf_vprintf(zlog_buf_t * a_buf, const char *format, va_list args)
{
va_list ap;
size_t size_left;
int nwrite;
if (!a_buf->start) {
zc_error("pre-use of zlog_buf_resize fail, so can't convert");
return -1;
}
va_copy(ap, args);
size_left = a_buf->end_plus_1 - a_buf->tail;
nwrite = vsnprintf(a_buf->tail, size_left, format, ap);
if (nwrite >= 0 && nwrite < size_left) {
a_buf->tail += nwrite;
//*(a_buf->tail) = '\0';
return 0;
} else if (nwrite < 0) {
zc_error("vsnprintf fail, errno[%d]", errno);
zc_error("nwrite[%d], size_left[%ld], format[%s]", nwrite, size_left, format);
return -1;
} else if (nwrite >= size_left) {
int rc;
//zc_debug("nwrite[%d]>=size_left[%ld],format[%s],resize", nwrite, size_left, format);
rc = zlog_buf_resize(a_buf, nwrite - size_left + 1);
if (rc > 0) {
zc_error("conf limit to %ld, can't extend, so truncate", a_buf->size_max);
va_copy(ap, args);
size_left = a_buf->end_plus_1 - a_buf->tail;
vsnprintf(a_buf->tail, size_left, format, ap);
a_buf->tail += size_left - 1;
//*(a_buf->tail) = '\0';
zlog_buf_truncate(a_buf);
return 1;
} else if (rc < 0) {
zc_error("zlog_buf_resize fail");
return -1;
} else {
//zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
va_copy(ap, args);
size_left = a_buf->end_plus_1 - a_buf->tail;
nwrite = vsnprintf(a_buf->tail, size_left, format, ap);
if (nwrite < 0) {
zc_error("vsnprintf fail, errno[%d]", errno);
zc_error("nwrite[%d], size_left[%ld], format[%s]", nwrite, size_left, format);
return -1;
} else {
a_buf->tail += nwrite;
//*(a_buf->tail) = '\0';
return 0;
}
}
}
return 0;
}
/*******************************************************************************/
/* if width > num_len, 0 padding, else output num */
int zlog_buf_printf_dec32(zlog_buf_t * a_buf, uint32_t ui32, int width)
{
unsigned char *p;
char *q;
unsigned char tmp[ZLOG_INT32_LEN + 1];
size_t num_len, zero_len, out_len;
if (!a_buf->start) {
zc_error("pre-use of zlog_buf_resize fail, so can't convert");
return -1;
}
p = tmp + ZLOG_INT32_LEN;
do {
*--p = (unsigned char) (ui32 % 10 + '0');
} while (ui32 /= 10);
/* zero or space padding */
num_len = (tmp + ZLOG_INT32_LEN) - p;
if (width > num_len) {
zero_len = width - num_len;
out_len = width;
} else {
zero_len = 0;
out_len = num_len;
}
if ((q = a_buf->tail + out_len) > a_buf->end) {
int rc;
//zc_debug("size_left not enough, resize");
rc = zlog_buf_resize(a_buf, out_len - (a_buf->end - a_buf->tail));
if (rc > 0) {
size_t len_left;
zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max);
len_left = a_buf->end - a_buf->tail;
if (len_left <= zero_len) {
zero_len = len_left;
num_len = 0;
} else if (len_left > zero_len) {
/* zero_len not changed */
num_len = len_left - zero_len;
}
if (zero_len) memset(a_buf->tail, '0', zero_len);
memcpy(a_buf->tail + zero_len, p, num_len);
a_buf->tail += len_left;
//*(a_buf->tail) = '\0';
zlog_buf_truncate(a_buf);
return 1;
} else if (rc < 0) {
zc_error("zlog_buf_resize fail");
return -1;
} else {
//zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
q = a_buf->tail + out_len; /* re-calculate p*/
}
}
if (zero_len) memset(a_buf->tail, '0', zero_len);
memcpy(a_buf->tail + zero_len, p, num_len);
a_buf->tail = q;
//*(a_buf->tail) = '\0';
return 0;
}
/*******************************************************************************/
int zlog_buf_printf_dec64(zlog_buf_t * a_buf, uint64_t ui64, int width)
{
unsigned char *p;
char *q;
unsigned char tmp[ZLOG_INT64_LEN + 1];
size_t num_len, zero_len, out_len;
uint32_t ui32;
if (!a_buf->start) {
zc_error("pre-use of zlog_buf_resize fail, so can't convert");
return -1;
}
p = tmp + ZLOG_INT64_LEN;
if (ui64 <= ZLOG_MAX_UINT32_VALUE) {
/*
* To divide 64-bit numbers and to find remainders
* on the x86 platform gcc and icc call the libc functions
* [u]divdi3() and [u]moddi3(), they call another function
* in its turn. On FreeBSD it is the qdivrem() function,
* its source code is about 170 lines of the code.
* The glibc counterpart is about 150 lines of the code.
*
* For 32-bit numbers and some divisors gcc and icc use
* a inlined multiplication and shifts. For example,
* unsigned "i32 / 10" is compiled to
*
* (i32 * 0xCCCCCCCD) >> 35
*/
ui32 = (uint32_t) ui64;
do {
*--p = (unsigned char) (ui32 % 10 + '0');
} while (ui32 /= 10);
} else {
do {
*--p = (unsigned char) (ui64 % 10 + '0');
} while (ui64 /= 10);
}
/* zero or space padding */
num_len = (tmp + ZLOG_INT64_LEN) - p;
if (width > num_len) {
zero_len = width - num_len;
out_len = width;
} else {
zero_len = 0;
out_len = num_len;
}
if ((q = a_buf->tail + out_len) > a_buf->end) {
int rc;
//zc_debug("size_left not enough, resize");
rc = zlog_buf_resize(a_buf, out_len - (a_buf->end - a_buf->tail));
if (rc > 0) {
size_t len_left;
zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max);
len_left = a_buf->end - a_buf->tail;
if (len_left <= zero_len) {
zero_len = len_left;
num_len = 0;
} else if (len_left > zero_len) {
/* zero_len not changed */
num_len = len_left - zero_len;
}
if (zero_len) memset(a_buf->tail, '0', zero_len);
memcpy(a_buf->tail + zero_len, p, num_len);
a_buf->tail += len_left;
//*(a_buf->tail) = '\0';
zlog_buf_truncate(a_buf);
return 1;
} else if (rc < 0) {
zc_error("zlog_buf_resize fail");
return -1;
} else {
//zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
q = a_buf->tail + out_len; /* re-calculate p*/
}
}
if (zero_len) memset(a_buf->tail, '0', zero_len);
memcpy(a_buf->tail + zero_len, p, num_len);
a_buf->tail = q;
//*(a_buf->tail) = '\0';
return 0;
}
/*******************************************************************************/
int zlog_buf_printf_hex(zlog_buf_t * a_buf, uint32_t ui32, int width)
{
unsigned char *p;
char *q;
unsigned char tmp[ZLOG_INT32_LEN + 1];
size_t num_len, zero_len, out_len;
static unsigned char hex[] = "0123456789abcdef";
//static unsigned char HEX[] = "0123456789ABCDEF";
if (!a_buf->start) {
zc_error("pre-use of zlog_buf_resize fail, so can't convert");
return -1;
}
p = tmp + ZLOG_INT32_LEN;
do {
/* the "(uint32_t)" cast disables the BCC's warning */
*--p = hex[(uint32_t) (ui32 & 0xf)];
} while (ui32 >>= 4);
#if 0
} else { /* is_hex == 2 */
do {
/* the "(uint32_t)" cast disables the BCC's warning */
*--p = HEX[(uint32_t) (ui64 & 0xf)];
} while (ui64 >>= 4);
}
#endif
/* zero or space padding */
num_len = (tmp + ZLOG_INT32_LEN) - p;
if (width > num_len) {
zero_len = width - num_len;
out_len = width;
} else {
zero_len = 0;
out_len = num_len;
}
if ((q = a_buf->tail + out_len) > a_buf->end) {
int rc;
//zc_debug("size_left not enough, resize");
rc = zlog_buf_resize(a_buf, out_len - (a_buf->end - a_buf->tail));
if (rc > 0) {
size_t len_left;
zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max);
len_left = a_buf->end - a_buf->tail;
if (len_left <= zero_len) {
zero_len = len_left;
num_len = 0;
} else if (len_left > zero_len) {
/* zero_len not changed */
num_len = len_left - zero_len;
}
if (zero_len) memset(a_buf->tail, '0', zero_len);
memcpy(a_buf->tail + zero_len, p, num_len);
a_buf->tail += len_left;
//*(a_buf->tail) = '\0';
zlog_buf_truncate(a_buf);
return 1;
} else if (rc < 0) {
zc_error("zlog_buf_resize fail");
return -1;
} else {
//zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
q = a_buf->tail + out_len; /* re-calculate p*/
}
}
if (zero_len) memset(a_buf->tail, '0', zero_len);
memcpy(a_buf->tail + zero_len, p, num_len);
a_buf->tail = q;
//*(a_buf->tail) = '\0';
return 0;
}
/*******************************************************************************/
int zlog_buf_append(zlog_buf_t * a_buf, const char *str, size_t str_len)
{
char *p;
#if 0
if (str_len <= 0 || str == NULL) {
return 0;
}
if (!a_buf->start) {
zc_error("pre-use of zlog_buf_resize fail, so can't convert");
return -1;
}
#endif
if ((p = a_buf->tail + str_len) > a_buf->end) {
int rc;
//zc_debug("size_left not enough, resize");
rc = zlog_buf_resize(a_buf, str_len - (a_buf->end - a_buf->tail));
if (rc > 0) {
size_t len_left;
zc_error("conf limit to %ld, can't extend, so output",
a_buf->size_max);
len_left = a_buf->end - a_buf->tail;
memcpy(a_buf->tail, str, len_left);
a_buf->tail += len_left;
//*(a_buf->tail) = '\0';
zlog_buf_truncate(a_buf);
return 1;
} else if (rc < 0) {
zc_error("zlog_buf_resize fail");
return -1;
} else {
//zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
p = a_buf->tail + str_len; /* re-calculate p*/
}
}
memcpy(a_buf->tail, str, str_len);
a_buf->tail = p;
// *(a_buf->tail) = '\0';
return 0;
}
/*******************************************************************************/
int zlog_buf_adjust_append(zlog_buf_t * a_buf, const char *str, size_t str_len,
int left_adjust, int zero_pad, size_t in_width, size_t out_width)
{
size_t append_len = 0;
size_t source_len = 0;
size_t space_len = 0;
#if 0
if (str_len <= 0 || str == NULL) {
return 0;
}
#endif
if (!a_buf->start) {
zc_error("pre-use of zlog_buf_resize fail, so can't convert");
return -1;
}
/* calculate how many character will be got from str */
if (out_width == 0 || str_len < out_width) {
source_len = str_len;
} else {
source_len = out_width;
}
/* calculate how many character will be output */
if (in_width == 0 || source_len >= in_width ) {
append_len = source_len;
space_len = 0;
} else {
append_len = in_width;
space_len = in_width - source_len;
}
/* |-----append_len-----------| */
/* |-source_len---|-space_len-| left_adjust */
/* |-space_len---|-source_len-| right_adjust */
/* |-(size_real-1)---| size not enough */
if (append_len > a_buf->end - a_buf->tail) {
int rc = 0;
//zc_debug("size_left not enough, resize");
rc = zlog_buf_resize(a_buf, append_len - (a_buf->end -a_buf->tail));
if (rc > 0) {
zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max);
append_len = (a_buf->end - a_buf->tail);
if (left_adjust) {
if (source_len < append_len) {
space_len = append_len - source_len;
} else {
source_len = append_len;
space_len = 0;
}
if (space_len) memset(a_buf->tail + source_len, ' ', space_len);
memcpy(a_buf->tail, str, source_len);
} else {
if (space_len < append_len) {
source_len = append_len - space_len;
} else {
space_len = append_len;
source_len = 0;
}
if (space_len) {
if (zero_pad) {
memset(a_buf->tail, '0', space_len);
} else {
memset(a_buf->tail, ' ', space_len);
}
}
memcpy(a_buf->tail + space_len, str, source_len);
}
a_buf->tail += append_len;
//*(a_buf->tail) = '\0';
zlog_buf_truncate(a_buf);
return 1;
} else if (rc < 0) {
zc_error("zlog_buf_resize fail");
return -1;
} else {
//zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
}
}
if (left_adjust) {
if (space_len) memset(a_buf->tail + source_len, ' ', space_len);
memcpy(a_buf->tail, str, source_len);
} else {
if (space_len) {
if (zero_pad) {
memset(a_buf->tail, '0', space_len);
} else {
memset(a_buf->tail, ' ', space_len);
}
}
memcpy(a_buf->tail + space_len, str, source_len);
}
a_buf->tail += append_len;
//*(a_buf->tail) = '\0';
return 0;
}
/*******************************************************************************/
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_buf_h
#define __zlog_buf_h
/* buf, is a dynamic expand buffer for one single log,
* as one single log will interlace if use multiple write() to file.
* and buf is always keep in a thread, to make each thread has its
* own buffer to avoid lock.
*/
#include <stdarg.h>
#include <stdint.h>
typedef struct zlog_buf_s {
char *start;
char *tail;
char *end;
char *end_plus_1;
size_t size_min;
size_t size_max;
size_t size_real;
char truncate_str[MAXLEN_PATH + 1];
size_t truncate_str_len;
} zlog_buf_t;
zlog_buf_t *zlog_buf_new(size_t min, size_t max, const char *truncate_str);
void zlog_buf_del(zlog_buf_t * a_buf);
void zlog_buf_profile(zlog_buf_t * a_buf, int flag);
int zlog_buf_vprintf(zlog_buf_t * a_buf, const char *format, va_list args);
int zlog_buf_append(zlog_buf_t * a_buf, const char *str, size_t str_len);
int zlog_buf_adjust_append(zlog_buf_t * a_buf, const char *str, size_t str_len,
int left_adjust, int zero_pad, size_t in_width, size_t out_width);
int zlog_buf_printf_dec32(zlog_buf_t * a_buf, uint32_t ui32, int width);
int zlog_buf_printf_dec64(zlog_buf_t * a_buf, uint64_t ui64, int width);
int zlog_buf_printf_hex(zlog_buf_t * a_buf, uint32_t ui32, int width);
#define zlog_buf_restart(a_buf) do { \
a_buf->tail = a_buf->start; \
} while(0)
#define zlog_buf_len(a_buf) (a_buf->tail - a_buf->start)
#define zlog_buf_str(a_buf) (a_buf->start)
#define zlog_buf_seal(a_buf) do {*(a_buf)->tail = '\0';} while (0)
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fmacros.h"
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "category.h"
#include "rule.h"
#include "zc_defs.h"
void zlog_category_profile(zlog_category_t *a_category, int flag)
{
int i;
zlog_rule_t *a_rule;
zc_assert(a_category,);
zc_profile(flag, "--category[%p][%s][%p]--",
a_category,
a_category->name,
a_category->fit_rules);
if (a_category->fit_rules) {
zc_arraylist_foreach(a_category->fit_rules, i, a_rule) {
zlog_rule_profile(a_rule, flag);
}
}
return;
}
/*******************************************************************************/
void zlog_category_del(zlog_category_t * a_category)
{
zc_assert(a_category,);
if (a_category->fit_rules) zc_arraylist_del(a_category->fit_rules);
zc_debug("zlog_category_del[%p]", a_category);
free(a_category);
return;
}
/* overlap one rule's level bitmap to cateogry,
* so category can judge whether a log level will be output by itself
* It is safe when configure is reloaded, when rule will be released an recreated
*/
static void zlog_cateogry_overlap_bitmap(zlog_category_t * a_category, zlog_rule_t *a_rule)
{
int i;
for(i = 0; i < sizeof(a_rule->level_bitmap); i++) {
a_category->level_bitmap[i] |= a_rule->level_bitmap[i];
}
}
static int zlog_category_obtain_rules(zlog_category_t * a_category, zc_arraylist_t * rules)
{
int i;
int count = 0;
int fit = 0;
zlog_rule_t *a_rule;
zlog_rule_t *wastebin_rule = NULL;
/* before set, clean last fit rules first */
if (a_category->fit_rules) zc_arraylist_del(a_category->fit_rules);
memset(a_category->level_bitmap, 0x00, sizeof(a_category->level_bitmap));
a_category->fit_rules = zc_arraylist_new(NULL);
if (!(a_category->fit_rules)) {
zc_error("zc_arraylist_new fail");
return -1;
}
/* get match rules from all rules */
zc_arraylist_foreach(rules, i, a_rule) {
fit = zlog_rule_match_category(a_rule, a_category->name);
if (fit) {
if (zc_arraylist_add(a_category->fit_rules, a_rule)) {
zc_error("zc_arrylist_add fail");
goto err;
}
zlog_cateogry_overlap_bitmap(a_category, a_rule);
count++;
}
if (zlog_rule_is_wastebin(a_rule)) {
wastebin_rule = a_rule;
}
}
if (count == 0) {
if (wastebin_rule) {
zc_debug("category[%s], no match rules, use wastebin_rule", a_category->name);
if (zc_arraylist_add(a_category->fit_rules, wastebin_rule)) {
zc_error("zc_arrylist_add fail");
goto err;
}
zlog_cateogry_overlap_bitmap(a_category, wastebin_rule);
count++;
} else {
zc_debug("category[%s], no match rules & no wastebin_rule", a_category->name);
}
}
return 0;
err:
zc_arraylist_del(a_category->fit_rules);
a_category->fit_rules = NULL;
return -1;
}
zlog_category_t *zlog_category_new(const char *name, zc_arraylist_t * rules)
{
size_t len;
zlog_category_t *a_category;
zc_assert(name, NULL);
zc_assert(rules, NULL);
len = strlen(name);
if (len > sizeof(a_category->name) - 1) {
zc_error("name[%s] too long", name);
return NULL;
}
a_category = calloc(1, sizeof(zlog_category_t));
if (!a_category) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
strcpy(a_category->name, name);
a_category->name_len = len;
if (zlog_category_obtain_rules(a_category, rules)) {
zc_error("zlog_category_fit_rules fail");
goto err;
}
zlog_category_profile(a_category, ZC_DEBUG);
return a_category;
err:
zlog_category_del(a_category);
return NULL;
}
/*******************************************************************************/
/* update success: fit_rules 1, fit_rules_backup 1 */
/* update fail: fit_rules 0, fit_rules_backup 1 */
int zlog_category_update_rules(zlog_category_t * a_category, zc_arraylist_t * new_rules)
{
zc_assert(a_category, -1);
zc_assert(new_rules, -1);
/* 1st, mv fit_rules fit_rules_backup */
if (a_category->fit_rules_backup) zc_arraylist_del(a_category->fit_rules_backup);
a_category->fit_rules_backup = a_category->fit_rules;
a_category->fit_rules = NULL;
memcpy(a_category->level_bitmap_backup, a_category->level_bitmap,
sizeof(a_category->level_bitmap));
/* 2nd, obtain new_rules to fit_rules */
if (zlog_category_obtain_rules(a_category, new_rules)) {
zc_error("zlog_category_obtain_rules fail");
a_category->fit_rules = NULL;
return -1;
}
/* keep the fit_rules_backup not change, return */
return 0;
}
/* commit fail: fit_rules_backup != 0 */
/* commit success: fit_rules 1, fit_rules_backup 0 */
void zlog_category_commit_rules(zlog_category_t * a_category)
{
zc_assert(a_category,);
if (!a_category->fit_rules_backup) {
zc_warn("a_category->fit_rules_backup is NULL, never update before");
return;
}
zc_arraylist_del(a_category->fit_rules_backup);
a_category->fit_rules_backup = NULL;
memset(a_category->level_bitmap_backup, 0x00,
sizeof(a_category->level_bitmap_backup));
return;
}
/* rollback fail: fit_rules_backup != 0 */
/* rollback success: fit_rules 1, fit_rules_backup 0 */
/* so whether update succes or not, make things back to old */
void zlog_category_rollback_rules(zlog_category_t * a_category)
{
zc_assert(a_category,);
if (!a_category->fit_rules_backup) {
zc_warn("a_category->fit_rules_backup in NULL, never update before");
return;
}
if (a_category->fit_rules) {
/* update success, rm new and backup */
zc_arraylist_del(a_category->fit_rules);
a_category->fit_rules = a_category->fit_rules_backup;
a_category->fit_rules_backup = NULL;
} else {
/* update fail, just backup */
a_category->fit_rules = a_category->fit_rules_backup;
a_category->fit_rules_backup = NULL;
}
memcpy(a_category->level_bitmap, a_category->level_bitmap_backup,
sizeof(a_category->level_bitmap));
memset(a_category->level_bitmap_backup, 0x00,
sizeof(a_category->level_bitmap_backup));
return; /* always success */
}
/*******************************************************************************/
int zlog_category_output(zlog_category_t * a_category, zlog_thread_t * a_thread)
{
int i;
int rc = 0;
zlog_rule_t *a_rule;
/* go through all match rules to output */
zc_arraylist_foreach(a_category->fit_rules, i, a_rule) {
rc = zlog_rule_output(a_rule, a_thread);
}
return rc;
}
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_category_h
#define __zlog_category_h
#include "zc_defs.h"
#include "thread.h"
typedef struct zlog_category_s {
char name[MAXLEN_PATH + 1];
size_t name_len;
unsigned char level_bitmap[32];
unsigned char level_bitmap_backup[32];
zc_arraylist_t *fit_rules;
zc_arraylist_t *fit_rules_backup;
} zlog_category_t;
zlog_category_t *zlog_category_new(const char *name, zc_arraylist_t * rules);
void zlog_category_del(zlog_category_t * a_category);
void zlog_category_profile(zlog_category_t *a_category, int flag);
int zlog_category_update_rules(zlog_category_t * a_category, zc_arraylist_t * new_rules);
void zlog_category_commit_rules(zlog_category_t * a_category);
void zlog_category_rollback_rules(zlog_category_t * a_category);
int zlog_category_output(zlog_category_t * a_category, zlog_thread_t * a_thread);
#define zlog_category_needless_level(a_category, lv) \
a_category && (zlog_env_conf->level > lv || !((a_category->level_bitmap[lv/8] >> (7 - lv % 8)) & 0x01))
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "zc_defs.h"
#include "category_table.h"
void zlog_category_table_profile(zc_hashtable_t * categories, int flag)
{
zc_hashtable_entry_t *a_entry;
zlog_category_t *a_category;
zc_assert(categories,);
zc_profile(flag, "-category_table[%p]-", categories);
zc_hashtable_foreach(categories, a_entry) {
a_category = (zlog_category_t *) a_entry->value;
zlog_category_profile(a_category, flag);
}
return;
}
/*******************************************************************************/
void zlog_category_table_del(zc_hashtable_t * categories)
{
zc_assert(categories,);
zc_hashtable_del(categories);
zc_debug("zlog_category_table_del[%p]", categories);
return;
}
zc_hashtable_t *zlog_category_table_new(void)
{
zc_hashtable_t *categories;
categories = zc_hashtable_new(20,
(zc_hashtable_hash_fn) zc_hashtable_str_hash,
(zc_hashtable_equal_fn) zc_hashtable_str_equal,
NULL, (zc_hashtable_del_fn) zlog_category_del);
if (!categories) {
zc_error("zc_hashtable_new fail");
return NULL;
} else {
zlog_category_table_profile(categories, ZC_DEBUG);
return categories;
}
}
/*******************************************************************************/
int zlog_category_table_update_rules(zc_hashtable_t * categories, zc_arraylist_t * new_rules)
{
zc_hashtable_entry_t *a_entry;
zlog_category_t *a_category;
zc_assert(categories, -1);
zc_hashtable_foreach(categories, a_entry) {
a_category = (zlog_category_t *) a_entry->value;
if (zlog_category_update_rules(a_category, new_rules)) {
zc_error("zlog_category_update_rules fail, try rollback");
return -1;
}
}
return 0;
}
void zlog_category_table_commit_rules(zc_hashtable_t * categories)
{
zc_hashtable_entry_t *a_entry;
zlog_category_t *a_category;
zc_assert(categories,);
zc_hashtable_foreach(categories, a_entry) {
a_category = (zlog_category_t *) a_entry->value;
zlog_category_commit_rules(a_category);
}
return;
}
void zlog_category_table_rollback_rules(zc_hashtable_t * categories)
{
zc_hashtable_entry_t *a_entry;
zlog_category_t *a_category;
zc_assert(categories,);
zc_hashtable_foreach(categories, a_entry) {
a_category = (zlog_category_t *) a_entry->value;
zlog_category_rollback_rules(a_category);
}
return;
}
/*******************************************************************************/
zlog_category_t *zlog_category_table_fetch_category(zc_hashtable_t * categories,
const char *category_name, zc_arraylist_t * rules)
{
zlog_category_t *a_category;
zc_assert(categories, NULL);
/* 1st find category in global category map */
a_category = zc_hashtable_get(categories, category_name);
if (a_category) return a_category;
/* else not found, create one */
a_category = zlog_category_new(category_name, rules);
if (!a_category) {
zc_error("zc_category_new fail");
return NULL;
}
if(zc_hashtable_put(categories, a_category->name, a_category)) {
zc_error("zc_hashtable_put fail");
goto err;
}
return a_category;
err:
zlog_category_del(a_category);
return NULL;
}
/*******************************************************************************/
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_category_table_h
#define __zlog_category_table_h
#include "zc_defs.h"
#include "category.h"
zc_hashtable_t *zlog_category_table_new(void);
void zlog_category_table_del(zc_hashtable_t * categories);
void zlog_category_table_profile(zc_hashtable_t * categories, int flag);
/* if none, create new and return */
zlog_category_t *zlog_category_table_fetch_category(
zc_hashtable_t * categories,
const char *category_name, zc_arraylist_t * rules);
int zlog_category_table_update_rules(zc_hashtable_t * categories, zc_arraylist_t * new_rules);
void zlog_category_table_commit_rules(zc_hashtable_t * categories);
void zlog_category_table_rollback_rules(zc_hashtable_t * categories);
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fmacros.h"
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
#include <unistd.h>
#else
#include "zlog_win.h"
#endif
#include <time.h>
#include "conf.h"
#include "rule.h"
#include "format.h"
#include "level_list.h"
#include "rotater.h"
#include "zc_defs.h"
#ifdef _WIN32
#define STATS_FILE stat
#else
#define STATS_FILE lstat
#endif
/*******************************************************************************/
#define ZLOG_CONF_DEFAULT_FORMAT "default = \"%D %V [%p:%F:%L] %m%n\""
#define ZLOG_CONF_DEFAULT_RULE "*.* >stdout"
#define ZLOG_CONF_DEFAULT_BUF_SIZE_MIN 1024
#define ZLOG_CONF_DEFAULT_BUF_SIZE_MAX (2 * 1024 * 1024)
#define ZLOG_CONF_DEFAULT_FILE_PERMS 0600
#define ZLOG_CONF_DEFAULT_RELOAD_CONF_PERIOD 0
#define ZLOG_CONF_DEFAULT_FSYNC_PERIOD 0
#define ZLOG_CONF_BACKUP_ROTATE_LOCK_FILE "/tmp/zlog.lock"
/*******************************************************************************/
void zlog_conf_profile(zlog_conf_t * a_conf, int flag)
{
int i;
zlog_rule_t *a_rule;
zlog_format_t *a_format;
zc_assert(a_conf,);
zc_profile(flag, "-conf[%p]-", a_conf);
zc_profile(flag, "--global--");
zc_profile(flag, "---file[%s],mtime[%s]---", a_conf->file, a_conf->mtime);
zc_profile(flag, "---in-memory conf[%s]---", a_conf->cfg_ptr);
zc_profile(flag, "---strict init[%d]---", a_conf->strict_init);
zc_profile(flag, "---buffer min[%ld]---", a_conf->buf_size_min);
zc_profile(flag, "---buffer max[%ld]---", a_conf->buf_size_max);
if (a_conf->default_format) {
zc_profile(flag, "---default_format---");
zlog_format_profile(a_conf->default_format, flag);
}
zc_profile(flag, "---file perms[0%o]---", a_conf->file_perms);
zc_profile(flag, "---reload conf period[%ld]---", a_conf->reload_conf_period);
zc_profile(flag, "---fsync period[%ld]---", a_conf->fsync_period);
zc_profile(flag, "---rotate lock file[%s]---", a_conf->rotate_lock_file);
if (a_conf->rotater) zlog_rotater_profile(a_conf->rotater, flag);
if (a_conf->levels) zlog_level_list_profile(a_conf->levels, flag);
if (a_conf->formats) {
zc_profile(flag, "--format list[%p]--", a_conf->formats);
zc_arraylist_foreach(a_conf->formats, i, a_format) {
zlog_format_profile(a_format, flag);
}
}
if (a_conf->rules) {
zc_profile(flag, "--rule_list[%p]--", a_conf->rules);
zc_arraylist_foreach(a_conf->rules, i, a_rule) {
zlog_rule_profile(a_rule, flag);
}
}
return;
}
/*******************************************************************************/
void zlog_conf_del(zlog_conf_t * a_conf)
{
zc_assert(a_conf,);
if (a_conf->rotater) zlog_rotater_del(a_conf->rotater);
if (a_conf->levels) zlog_level_list_del(a_conf->levels);
if (a_conf->default_format) zlog_format_del(a_conf->default_format);
if (a_conf->formats) zc_arraylist_del(a_conf->formats);
if (a_conf->rules) zc_arraylist_del(a_conf->rules);
free(a_conf);
zc_debug("zlog_conf_del[%p]");
return;
}
static int zlog_conf_build_without_file(zlog_conf_t * a_conf);
static int zlog_conf_build_with_file(zlog_conf_t * a_conf);
static int zlog_conf_build_with_string(zlog_conf_t *a_conf,
const char *conf_string);
static int zlog_conf_build_with_in_memory(zlog_conf_t * a_conf);
enum{
NO_CFG,
FILE_CFG,
IN_MEMORY_CFG
};
/*******************************************************************************/
zlog_conf_t *zlog_conf_new(const char *config)
{
int nwrite = 0;
int cfg_source = 0;
zlog_conf_t *a_conf = NULL;
a_conf = calloc(1, sizeof(zlog_conf_t));
if (!a_conf) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
// Find content of pointer. If it starts with '[' then content are configurations.
if (config && config[0] != '\0' && config[0] != '[') {
nwrite = snprintf(a_conf->file, sizeof(a_conf->file), "%s", config);
cfg_source = FILE_CFG;
} else if (getenv("ZLOG_CONF_PATH") != NULL) {
nwrite = snprintf(a_conf->file, sizeof(a_conf->file), "%s", getenv("ZLOG_CONF_PATH"));
cfg_source = FILE_CFG;
} else if (config && config[0]=='[') {
memset(a_conf->file, 0x00, sizeof(a_conf->file));
nwrite = snprintf(a_conf->cfg_ptr, sizeof(a_conf->cfg_ptr), "%s", config);
cfg_source = IN_MEMORY_CFG;
if (nwrite < 0 || nwrite >= sizeof(a_conf->file)) {
zc_error("not enough space for configurations, nwrite=[%d], errno[%d]", nwrite, errno);
goto err;
}
} else {
memset(a_conf->file, 0x00, sizeof(a_conf->file));
cfg_source = NO_CFG;
}
if ((nwrite < 0) || ((nwrite >= sizeof(a_conf->file)) && (cfg_source == FILE_CFG))) {
zc_error("not enough space for path name, nwrite=[%d], errno[%d]", nwrite, errno);
goto err;
}
/* set default configuration start */
a_conf->strict_init = 1;
a_conf->buf_size_min = ZLOG_CONF_DEFAULT_BUF_SIZE_MIN;
a_conf->buf_size_max = ZLOG_CONF_DEFAULT_BUF_SIZE_MAX;
if (cfg_source == FILE_CFG) {
/* configure file as default lock file */
strcpy(a_conf->rotate_lock_file, a_conf->file);
} else {
strcpy(a_conf->rotate_lock_file, ZLOG_CONF_BACKUP_ROTATE_LOCK_FILE);
}
strcpy(a_conf->default_format_line, ZLOG_CONF_DEFAULT_FORMAT);
a_conf->file_perms = ZLOG_CONF_DEFAULT_FILE_PERMS;
a_conf->reload_conf_period = ZLOG_CONF_DEFAULT_RELOAD_CONF_PERIOD;
a_conf->fsync_period = ZLOG_CONF_DEFAULT_FSYNC_PERIOD;
/* set default configuration end */
a_conf->levels = zlog_level_list_new();
if (!a_conf->levels) {
zc_error("zlog_level_list_new fail");
goto err;
}
a_conf->formats = zc_arraylist_new((zc_arraylist_del_fn) zlog_format_del);
if (!a_conf->formats) {
zc_error("zc_arraylist_new fail");
goto err;
}
a_conf->rules = zc_arraylist_new((zc_arraylist_del_fn) zlog_rule_del);
if (!a_conf->rules) {
zc_error("init rule_list fail");
goto err;
}
if (cfg_source == FILE_CFG) {
if (zlog_conf_build_with_file(a_conf)) {
zc_error("zlog_conf_build_with_file fail");
goto err;
}
} else if (cfg_source == IN_MEMORY_CFG) {
if(zlog_conf_build_with_in_memory(a_conf)){
zc_error("zlog_conf_build_with_in_memory fail");
goto err;
}
} else {
if (zlog_conf_build_without_file(a_conf)) {
zc_error("zlog_conf_build_without_file fail");
goto err;
}
}
zlog_conf_profile(a_conf, ZC_DEBUG);
return a_conf;
err:
zlog_conf_del(a_conf);
return NULL;
}
/*******************************************************************************/
zlog_conf_t *zlog_conf_new_from_string(const char *config_string)
{
zlog_conf_t *a_conf = NULL;
a_conf = calloc(1, sizeof(zlog_conf_t));
if (!a_conf) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
// no configuration file
memset(a_conf->file, 0x00, sizeof(a_conf->file));
a_conf->levels = zlog_level_list_new();
if (!a_conf->levels) {
zc_error("zlog_level_list_new fail");
goto err;
}
a_conf->formats = zc_arraylist_new((zc_arraylist_del_fn) zlog_format_del);
if (!a_conf->formats) {
zc_error("zc_arraylist_new fail");
goto err;
}
a_conf->rules = zc_arraylist_new((zc_arraylist_del_fn) zlog_rule_del);
if (!a_conf->rules) {
zc_error("init rule_list fail");
goto err;
}
strcpy(a_conf->rotate_lock_file, "zlog-rotate.lock");
a_conf->strict_init = 1;
a_conf->buf_size_min = ZLOG_CONF_DEFAULT_BUF_SIZE_MIN;
a_conf->buf_size_max = ZLOG_CONF_DEFAULT_BUF_SIZE_MAX;
strcpy(a_conf->default_format_line, ZLOG_CONF_DEFAULT_FORMAT);
a_conf->file_perms = ZLOG_CONF_DEFAULT_FILE_PERMS;
a_conf->reload_conf_period = ZLOG_CONF_DEFAULT_RELOAD_CONF_PERIOD;
a_conf->fsync_period = ZLOG_CONF_DEFAULT_FSYNC_PERIOD;
a_conf->default_format = zlog_format_new(a_conf->default_format_line,
&(a_conf->time_cache_count));
if (!a_conf->default_format) {
zc_error("zlog_format_new fail");
goto err;
}
a_conf->rotater = zlog_rotater_new(a_conf->rotate_lock_file);
if (!a_conf->rotater) {
zc_error("zlog_rotater_new fail");
goto err;
}
if (zlog_conf_build_with_string(a_conf, config_string)) {
zc_error("zlog_conf_build_with_string fail");
goto err;
}
zlog_conf_profile(a_conf, ZC_DEBUG);
return a_conf;
err:
zlog_conf_del(a_conf);
return NULL;
}
/*******************************************************************************/
static int zlog_conf_build_without_file(zlog_conf_t * a_conf)
{
zlog_rule_t *default_rule;
a_conf->default_format = zlog_format_new(a_conf->default_format_line, &(a_conf->time_cache_count));
if (!a_conf->default_format) {
zc_error("zlog_format_new fail");
return -1;
}
a_conf->rotater = zlog_rotater_new(a_conf->rotate_lock_file);
if (!a_conf->rotater) {
zc_error("zlog_rotater_new fail");
return -1;
}
default_rule = zlog_rule_new(
ZLOG_CONF_DEFAULT_RULE,
a_conf->levels,
a_conf->default_format,
a_conf->formats,
a_conf->file_perms,
a_conf->fsync_period,
&(a_conf->time_cache_count));
if (!default_rule) {
zc_error("zlog_rule_new fail");
return -1;
}
/* add default rule */
if (zc_arraylist_add(a_conf->rules, default_rule)) {
zlog_rule_del(default_rule);
zc_error("zc_arraylist_add fail");
return -1;
}
return 0;
}
/*******************************************************************************/
static int zlog_conf_parse_line(zlog_conf_t * a_conf, char *line, int *section);
char *sgets(char *s, int size, char **string)
{
if (*string == NULL) return NULL;
char* nlp = strchr(*string, '\n');
char *fstring = *string;
if (nlp == NULL) {
if (strlen(fstring) > 0) {
nlp = fstring + strlen(fstring);
} else {
return NULL;
}
}
int ss = (int)(nlp + 1 - fstring);
if (size > ss)
size = ss;
memcpy(s, *string, size);
s[size] = 0;
if (strlen(*string) == strlen(s)) {
*string = NULL;
} else {
*string += size;
}
return s;
}
static int zlog_conf_build_with_string(zlog_conf_t *a_conf,
const char *conf_string)
{
int rc = 0;
char line[MAXLEN_CFG_LINE + 1];
size_t line_len;
char *pline = NULL;
char *p = NULL;
int line_no = 0;
int i = 0;
int in_quotation = 0;
char *conf_string_l = (char*) conf_string;
int section = 0;
/* [global:1] [levels:2] [formats:3] [rules:4] */
if (a_conf == NULL) {
return -1;
}
/* Now process the file.
*/
pline = line;
memset(&line, 0x00, sizeof(line));
while (sgets(pline, MAXLEN_CFG_LINE, &conf_string_l) != NULL) {
++line_no;
line_len = strlen(pline);
if (pline[line_len - 1] == '\n') {
pline[line_len - 1] = '\0';
}
/* check for end-of-section, comments, strip off trailing
* spaces and newline character.
*/
p = pline;
while (*p && isspace((int)*p))
++p;
if (*p == '\0' || *p == '#')
continue;
for (i = 0; p[i] != '\0'; ++i) {
pline[i] = p[i];
}
pline[i] = '\0';
for (p = pline + strlen(pline) - 1; isspace((int)*p); --p)
/*EMPTY*/;
if (*p == '\\') {
if ((p - line) > MAXLEN_CFG_LINE - 30) {
/* Oops the buffer is full - what now? */
pline = line;
} else {
for (p--; isspace((int)*p); --p)
/*EMPTY*/;
p++;
*p = 0;
pline = p;
continue;
}
} else {
memmove(line, pline, strlen(pline)+1);
}
*++p = '\0';
/* clean the tail comments start from # and not in quotation */
in_quotation = 0;
for (p = line; *p != '\0'; p++) {
if (*p == '"') {
in_quotation ^= 1;
continue;
}
if (*p == '#' && !in_quotation) {
*p = '\0';
break;
}
}
/* we now have the complete line,
* and are positioned at the first non-whitespace
* character. So let's process it
*/
rc = zlog_conf_parse_line(a_conf, line, &section);
if (rc < 0) {
zc_error("parse configure file[%s]line_no[%ld] fail", a_conf->file, line_no);
zc_error("line[%s]", line);
goto exit;
} else if (rc > 0) {
zc_warn("parse configure file[%s]line_no[%ld] fail", a_conf->file, line_no);
zc_warn("line[%s]", line);
zc_warn("as strict init is set to false, ignore and go on");
rc = 0;
continue;
}
}
exit:
return rc;
}
static int zlog_conf_build_with_file(zlog_conf_t * a_conf)
{
int rc = 0;
struct zlog_stat a_stat;
struct tm local_time;
FILE *fp = NULL;
char line[MAXLEN_CFG_LINE + 1];
size_t line_len;
char *pline = NULL;
char *p = NULL;
int line_no = 0;
int i = 0;
int in_quotation = 0;
int section = 0;
/* [global:1] [levels:2] [formats:3] [rules:4] */
if (STATS_FILE(a_conf->file, &a_stat)) {
zc_error("lstat conf file[%s] fail, errno[%d]", a_conf->file,
errno);
return -1;
}
localtime_r(&(a_stat.st_mtime), &local_time);
strftime(a_conf->mtime, sizeof(a_conf->mtime), "%Y-%m-%d %H:%M:%S", &local_time);
if ((fp = fopen(a_conf->file, "r")) == NULL) {
zc_error("open configure file[%s] fail", a_conf->file);
return -1;
}
a_conf->log_level[0] = '\0';
/* Now process the file.
*/
pline = line;
memset(&line, 0x00, sizeof(line));
while (fgets((char *)pline, sizeof(line) - (pline - line), fp) != NULL) {
++line_no;
line_len = strlen(pline);
if (0 == line_len) {
continue;
}
if (pline[line_len - 1] == '\n') {
pline[line_len - 1] = '\0';
}
/* check for end-of-section, comments, strip off trailing
* spaces and newline character.
*/
p = pline;
while (*p && isspace((int)*p))
++p;
if (*p == '\0' || *p == '#')
continue;
for (i = 0; p[i] != '\0'; ++i) {
pline[i] = p[i];
}
pline[i] = '\0';
for (p = pline + strlen(pline) - 1; isspace((int)*p); --p)
/*EMPTY*/;
if (*p == '\\') {
if ((p - line) > MAXLEN_CFG_LINE - 30) {
/* Oops the buffer is full - what now? */
pline = line;
} else {
for (p--; p >= line && isspace((int)*p); --p)
/*EMPTY*/;
p++;
*p = 0;
pline = p;
continue;
}
} else
pline = line;
*++p = '\0';
/* clean the tail comments start from # and not in quotation */
in_quotation = 0;
for (p = line; *p != '\0'; p++) {
if (*p == '"') {
in_quotation ^= 1;
continue;
}
if (*p == '#' && !in_quotation) {
*p = '\0';
break;
}
}
/* we now have the complete line,
* and are positioned at the first non-whitespace
* character. So let's process it
*/
rc = zlog_conf_parse_line(a_conf, line, &section);
if (rc < 0) {
zc_error("parse configure file[%s]line_no[%ld] fail", a_conf->file, line_no);
zc_error("line[%s]", line);
goto exit;
} else if (rc > 0) {
zc_warn("parse configure file[%s]line_no[%ld] fail", a_conf->file, line_no);
zc_warn("line[%s]", line);
zc_warn("as strict init is set to false, ignore and go on");
rc = 0;
continue;
}
}
if (a_conf->log_level[0] != '\0') {
a_conf->level = zlog_level_list_atoi(a_conf->levels, a_conf->log_level);
}
exit:
fclose(fp);
return rc;
}
/**********************************************************************/
static int zlog_conf_build_with_in_memory(zlog_conf_t * a_conf)
{
int rc = 0;
char line[MAXLEN_CFG_LINE + 1];
char *pline = NULL;
int section = 0;
pline = line;
memset(&line, 0x00, sizeof(line));
pline = strtok((char *)a_conf->cfg_ptr, "\n");
while (pline != NULL) {
rc = zlog_conf_parse_line(a_conf, pline, &section);
if (rc < 0) {
zc_error("parse in-memory configurations[%s] line [%s] fail", a_conf->cfg_ptr, pline);
break;
} else if (rc > 0) {
zc_error("parse in-memory configurations[%s] line [%s] fail", a_conf->cfg_ptr, pline);
zc_warn("as strict init is set to false, ignore and go on");
rc = 0;
continue;
}
pline = strtok(NULL, "\n");
}
return rc;
}
/* section [global:1] [levels:2] [formats:3] [rules:4] */
static int zlog_conf_parse_line(zlog_conf_t * a_conf, char *line, int *section)
{
int nscan;
int nread;
char name[MAXLEN_CFG_LINE + 1] = "";
char word_1[MAXLEN_CFG_LINE + 1];
char word_2[MAXLEN_CFG_LINE + 1];
char word_3[MAXLEN_CFG_LINE + 1];
char value[MAXLEN_CFG_LINE + 1];
zlog_format_t *a_format = NULL;
zlog_rule_t *a_rule = NULL;
if (strlen(line) > MAXLEN_CFG_LINE) {
zc_error ("line_len[%ld] > MAXLEN_CFG_LINE[%ld], may cause overflow",
strlen(line), MAXLEN_CFG_LINE);
return -1;
}
/* get and set outer section flag, so it is a closure? haha */
if (line[0] == '[') {
int last_section = *section;
nscan = sscanf(line, "[ %[^] \t]", name);
if (STRCMP(name, ==, "global")) {
*section = 1;
} else if (STRCMP(name, ==, "levels")) {
*section = 2;
} else if (STRCMP(name, ==, "formats")) {
*section = 3;
} else if (STRCMP(name, ==, "rules")) {
*section = 4;
} else {
zc_error("wrong section name[%s]", name);
return -1;
}
/* check the sequence of section, must increase */
if (last_section >= *section) {
zc_error("wrong sequence of section, must follow global->levels->formats->rules");
return -1;
}
if (*section == 4) {
if (a_conf->reload_conf_period != 0
&& a_conf->fsync_period >= a_conf->reload_conf_period) {
/* as all rule will be rebuilt when conf is reload,
* so fsync_period > reload_conf_period will never
* cause rule to fsync it's file.
* fsync_period will be meaningless and down speed,
* so make it zero.
*/
zc_warn("fsync_period[%ld] >= reload_conf_period[%ld],"
"set fsync_period to zero");
a_conf->fsync_period = 0;
}
/* now build rotater and default_format
* from the unchanging global setting,
* for zlog_rule_new() */
a_conf->rotater = zlog_rotater_new(a_conf->rotate_lock_file);
if (!a_conf->rotater) {
zc_error("zlog_rotater_new fail");
return -1;
}
a_conf->default_format = zlog_format_new(a_conf->default_format_line,
&(a_conf->time_cache_count));
if (!a_conf->default_format) {
zc_error("zlog_format_new fail");
return -1;
}
}
return 0;
}
/* process detail */
switch (*section) {
case 1:
memset(name, 0x00, sizeof(name));
memset(value, 0x00, sizeof(value));
nscan = sscanf(line, " %[^=]= %s ", name, value);
if (nscan != 2) {
zc_error("sscanf [%s] fail, name or value is null", line);
return -1;
}
memset(word_1, 0x00, sizeof(word_1));
memset(word_2, 0x00, sizeof(word_2));
memset(word_3, 0x00, sizeof(word_3));
nread = 0;
nscan = sscanf(name, "%s%n%s%s", word_1, &nread, word_2, word_3);
if (STRCMP(word_1, ==, "strict") && STRCMP(word_2, ==, "init")) {
/* if environment variable ZLOG_STRICT_INIT is set
* then always make it strict
*/
if (STRICMP(value, ==, "false") && !getenv("ZLOG_STRICT_INIT")) {
a_conf->strict_init = 0;
} else {
a_conf->strict_init = 1;
}
} else if (STRCMP(word_1, ==, "log") && STRCMP(word_2, ==, "level")) {
strcpy(a_conf->log_level, value);
} else if (STRCMP(word_1, ==, "buffer") && STRCMP(word_2, ==, "min")) {
a_conf->buf_size_min = zc_parse_byte_size(value);
} else if (STRCMP(word_1, ==, "buffer") && STRCMP(word_2, ==, "max")) {
a_conf->buf_size_max = zc_parse_byte_size(value);
} else if (STRCMP(word_1, ==, "file") && STRCMP(word_2, ==, "perms")) {
sscanf(value, "%o", &(a_conf->file_perms));
} else if (STRCMP(word_1, ==, "rotate") &&
STRCMP(word_2, ==, "lock") && STRCMP(word_3, ==, "file")) {
/* may overwrite the inner default value, or last value */
if (STRCMP(value, ==, "self")) {
strcpy(a_conf->rotate_lock_file, a_conf->file);
} else {
strcpy(a_conf->rotate_lock_file, value);
}
} else if (STRCMP(word_1, ==, "default") && STRCMP(word_2, ==, "format")) {
/* so the input now is [format = "xxyy"], fit format's style */
strcpy(a_conf->default_format_line, line + nread);
} else if (STRCMP(word_1, ==, "reload") &&
STRCMP(word_2, ==, "conf") && STRCMP(word_3, ==, "period")) {
a_conf->reload_conf_period = zc_parse_byte_size(value);
} else if (STRCMP(word_1, ==, "fsync") && STRCMP(word_2, ==, "period")) {
a_conf->fsync_period = zc_parse_byte_size(value);
} else {
zc_error("name[%s] is not any one of global options", name);
if (a_conf->strict_init) return -1;
}
break;
case 2:
if (zlog_level_list_set(a_conf->levels, line)) {
zc_error("zlog_level_list_set fail");
if (a_conf->strict_init) return -1;
}
break;
case 3:
a_format = zlog_format_new(line, &(a_conf->time_cache_count));
if (!a_format) {
zc_error("zlog_format_new fail [%s]", line);
if (a_conf->strict_init) return -1;
else break;
}
if (zc_arraylist_add(a_conf->formats, a_format)) {
zlog_format_del(a_format);
zc_error("zc_arraylist_add fail");
return -1;
}
break;
case 4:
a_rule = zlog_rule_new(line,
a_conf->levels,
a_conf->default_format,
a_conf->formats,
a_conf->file_perms,
a_conf->fsync_period,
&(a_conf->time_cache_count));
if (!a_rule) {
zc_error("zlog_rule_new fail [%s]", line);
if (a_conf->strict_init) return -1;
else break;
}
if (zc_arraylist_add(a_conf->rules, a_rule)) {
zlog_rule_del(a_rule);
zc_error("zc_arraylist_add fail");
return -1;
}
break;
default:
zc_error("not in any section");
return -1;
}
return 0;
}
/*******************************************************************************/
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_conf_h
#define __zlog_conf_h
#include "zc_defs.h"
#include "format.h"
#include "rotater.h"
typedef struct zlog_conf_s {
char file[MAXLEN_PATH + 1];
char cfg_ptr[MAXLEN_CFG_LINE*MAXLINES_NO];
char mtime[20 + 1];
int strict_init;
size_t buf_size_min;
size_t buf_size_max;
char rotate_lock_file[MAXLEN_CFG_LINE + 1];
zlog_rotater_t *rotater;
char default_format_line[MAXLEN_CFG_LINE + 1];
zlog_format_t *default_format;
unsigned int file_perms;
size_t fsync_period;
size_t reload_conf_period;
zc_arraylist_t *levels;
zc_arraylist_t *formats;
zc_arraylist_t *rules;
int time_cache_count;
char log_level[MAXLEN_CFG_LINE + 1];
int level;
} zlog_conf_t;
extern zlog_conf_t * zlog_env_conf;
zlog_conf_t *zlog_conf_new(const char *config);
zlog_conf_t *zlog_conf_new_from_string(const char *config_string);
void zlog_conf_del(zlog_conf_t * a_conf);
void zlog_conf_profile(zlog_conf_t * a_conf, int flag);
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define _GNU_SOURCE // For distros like Centos for syscall interface
#include "fmacros.h"
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <stdint.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include "zc_defs.h"
#include "event.h"
#ifdef _WIN32
#include <Winsock2.h>
#endif
void zlog_event_profile(zlog_event_t * a_event, int flag)
{
zc_assert(a_event,);
zc_profile(flag, "---event[%p][%s,%s][%s(%ld),%s(%ld),%ld,%d][%p,%s][%ld,%ld][%ld,%ld][%d]---",
a_event,
a_event->category_name, a_event->host_name,
a_event->file, a_event->file_len,
a_event->func, a_event->func_len,
a_event->line, a_event->level,
a_event->hex_buf, a_event->str_format,
a_event->time_stamp.tv_sec, a_event->time_stamp.tv_usec,
(long)a_event->pid, (long)a_event->tid,
a_event->time_cache_count);
return;
}
/*******************************************************************************/
void zlog_event_del(zlog_event_t * a_event)
{
zc_assert(a_event,);
if (a_event->time_caches) free(a_event->time_caches);
zc_debug("zlog_event_del[%p]", a_event);
free(a_event);
return;
}
zlog_event_t *zlog_event_new(int time_cache_count)
{
zlog_event_t *a_event;
a_event = calloc(1, sizeof(zlog_event_t));
if (!a_event) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
a_event->time_caches = calloc(time_cache_count, sizeof(zlog_time_cache_t));
if (!a_event->time_caches) {
zc_error("calloc fail, errno[%d]", errno);
free(a_event);
return NULL;
}
a_event->time_cache_count = time_cache_count;
/*
* at the zlog_init we gethostname,
* u don't always change your hostname, eh?
*/
if (gethostname(a_event->host_name, sizeof(a_event->host_name) - 1)) {
zc_error("gethostname fail, errno[%d]", errno);
goto err;
}
a_event->host_name_len = strlen(a_event->host_name);
/* tid is bound to a_event
* as in whole lifecycle event persists
* even fork to oth pid, tid not change
*/
a_event->tid = pthread_self();
a_event->tid_str_len = sprintf(a_event->tid_str, "%lu", (unsigned long)a_event->tid);
a_event->tid_hex_str_len = sprintf(a_event->tid_hex_str, "%x", (unsigned int)a_event->tid);
#ifdef __linux__
a_event->ktid = syscall(SYS_gettid);
#elif __APPLE__
uint64_t tid64;
pthread_threadid_np(NULL, &tid64);
a_event->tid = (pthread_t)tid64;
#endif
#if defined __linux__ || __APPLE__
a_event->ktid_str_len = sprintf(a_event->ktid_str, "%u", (unsigned int)a_event->ktid);
#endif
//zlog_event_profile(a_event, ZC_DEBUG);
return a_event;
err:
zlog_event_del(a_event);
return NULL;
}
/*******************************************************************************/
void zlog_event_set_fmt(zlog_event_t * a_event,
char *category_name, size_t category_name_len,
const char *file, size_t file_len, const char *func, size_t func_len, long line, int level,
const char *str_format, va_list str_args)
{
/*
* category_name point to zlog_category_output's category.name
*/
a_event->category_name = category_name;
a_event->category_name_len = category_name_len;
a_event->file = (char *) file;
a_event->file_len = file_len;
a_event->func = (char *) func;
a_event->func_len = func_len;
a_event->line = line;
a_event->level = level;
a_event->generate_cmd = ZLOG_FMT;
a_event->str_format = str_format;
va_copy(a_event->str_args, str_args);
/* pid should fetch eveytime, as no one knows,
* when does user fork his process
* so clean here, and fetch at spec.c
*/
a_event->pid = (pid_t) 0;
/* in a event's life cycle, time will be get when spec need,
* and keep unchange though all event's life cycle
* zlog_spec_write_time gettimeofday
*/
a_event->time_stamp.tv_sec = 0;
return;
}
void zlog_event_set_hex(zlog_event_t * a_event,
char *category_name, size_t category_name_len,
const char *file, size_t file_len, const char *func, size_t func_len, long line, int level,
const void *hex_buf, size_t hex_buf_len)
{
/*
* category_name point to zlog_category_output's category.name
*/
a_event->category_name = category_name;
a_event->category_name_len = category_name_len;
a_event->file = (char *) file;
a_event->file_len = file_len;
a_event->func = (char *) func;
a_event->func_len = func_len;
a_event->line = line;
a_event->level = level;
a_event->generate_cmd = ZLOG_HEX;
a_event->hex_buf = hex_buf;
a_event->hex_buf_len = hex_buf_len;
/* pid should fetch eveytime, as no one knows,
* when does user fork his process
* so clean here, and fetch at spec.c
*/
a_event->pid = (pid_t) 0;
/* in a event's life cycle, time will be get when spec need,
* and keep unchange though all event's life cycle
*/
a_event->time_stamp.tv_sec = 0;
return;
}
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_event_h
#define __zlog_event_h
#include <sys/types.h> /* for pid_t */
#include <sys/time.h> /* for struct timeval */
#include <pthread.h> /* for pthread_t */
#include <stdarg.h> /* for va_list */
#include "zc_defs.h"
typedef enum {
ZLOG_FMT = 0,
ZLOG_HEX = 1,
} zlog_event_cmd;
typedef struct zlog_time_cache_s {
char str[MAXLEN_CFG_LINE + 1];
size_t len;
time_t sec;
} zlog_time_cache_t;
typedef struct {
char *category_name;
size_t category_name_len;
char host_name[256 + 1];
size_t host_name_len;
const char *file;
size_t file_len;
const char *func;
size_t func_len;
long line;
int level;
const void *hex_buf;
size_t hex_buf_len;
const char *str_format;
va_list str_args;
zlog_event_cmd generate_cmd;
struct timeval time_stamp;
time_t time_utc_sec;
struct tm time_utc;
time_t time_local_sec;
struct tm time_local;
zlog_time_cache_t *time_caches;
int time_cache_count;
pid_t pid;
pid_t last_pid;
char pid_str[30 + 1];
size_t pid_str_len;
pthread_t tid;
char tid_str[30 + 1];
size_t tid_str_len;
char tid_hex_str[30 + 1];
size_t tid_hex_str_len;
#if defined __linux__ || __APPLE__
pid_t ktid;
char ktid_str[30+1];
size_t ktid_str_len;
#endif
} zlog_event_t;
zlog_event_t *zlog_event_new(int time_cache_count);
void zlog_event_del(zlog_event_t * a_event);
void zlog_event_profile(zlog_event_t * a_event, int flag);
void zlog_event_set_fmt(zlog_event_t * a_event,
char *category_name, size_t category_name_len,
const char *file, size_t file_len, const char *func, size_t func_len, long line, int level,
const char *str_format, va_list str_args);
void zlog_event_set_hex(zlog_event_t * a_event,
char *category_name, size_t category_name_len,
const char *file, size_t file_len, const char *func, size_t func_len, long line, int level,
const void *hex_buf, size_t hex_buf_len);
#endif
#ifndef __zlog_fmacro_h
#define __zlog_fmacro_h
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif
#ifndef _DEFAULT_SOURCE
#define _DEFAULT_SOURCE
#endif
#if defined(__linux__) || defined(__OpenBSD__) || defined(_AIX)
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 700
#endif
#ifndef _XOPEN_SOURCE_EXTENDED
#define _XOPEN_SOURCE_EXTENDED
#endif
#if defined(__APPLE__)
#include <AvailabilityMacros.h>
#else
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809L
#endif
#endif
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE
#endif
#endif
#ifndef _LARGEFILE_SOURCE
#define _LARGEFILE_SOURCE
#endif
#ifndef _LARGEFILE_SOURCE
#define _LARGEFILE_SOURCE
#endif
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include "zc_defs.h"
#include "thread.h"
#include "spec.h"
#include "format.h"
void zlog_format_profile(zlog_format_t * a_format, int flag)
{
zc_assert(a_format,);
zc_profile(flag, "---format[%p][%s = %s(%p)]---",
a_format,
a_format->name,
a_format->pattern,
a_format->pattern_specs);
#if 0
int i;
zlog_spec_t *a_spec;
zc_arraylist_foreach(a_format->pattern_specs, i, a_spec) {
zlog_spec_profile(a_spec, flag);
}
#endif
return;
}
/*******************************************************************************/
void zlog_format_del(zlog_format_t * a_format)
{
zc_assert(a_format,);
if (a_format->pattern_specs) {
zc_arraylist_del(a_format->pattern_specs);
}
zc_debug("zlog_format_del[%p]", a_format);
free(a_format);
return;
}
zlog_format_t *zlog_format_new(char *line, int * time_cache_count)
{
int nscan = 0;
zlog_format_t *a_format = NULL;
int nread = 0;
const char *p_start;
const char *p_end;
char *p;
char *q;
zlog_spec_t *a_spec;
zc_assert(line, NULL);
a_format = calloc(1, sizeof(zlog_format_t));
if (!a_format) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
/* line default = "%d(%F %X.%l) %-6V (%c:%F:%L) - %m%n"
* name default
* pattern %d(%F %X.%l) %-6V (%c:%F:%L) - %m%n
*/
memset(a_format->name, 0x00, sizeof(a_format->name));
nread = 0;
nscan = sscanf(line, " %[^= \t] = %n", a_format->name, &nread);
if (nscan != 1) {
zc_error("format[%s], syntax wrong", line);
goto err;
}
if (*(line + nread) != '"') {
zc_error("the 1st char of pattern is not \", line+nread[%s]", line+nread);
goto err;
}
for (p = a_format->name; *p != '\0'; p++) {
if ((!isalnum(*p)) && (*p != '_')) {
zc_error("a_format->name[%s] character is not in [a-Z][0-9][_]", a_format->name);
goto err;
}
}
p_start = line + nread + 1;
p_end = strrchr(p_start, '"');
if (!p_end) {
zc_error("there is no \" at end of pattern, line[%s]", line);
goto err;
}
if (p_end - p_start > sizeof(a_format->pattern) - 1) {
zc_error("pattern is too long");
goto err;
}
memset(a_format->pattern, 0x00, sizeof(a_format->pattern));
memcpy(a_format->pattern, p_start, p_end - p_start);
if (zc_str_replace_env(a_format->pattern, sizeof(a_format->pattern))) {
zc_error("zc_str_replace_env fail");
goto err;
}
a_format->pattern_specs =
zc_arraylist_new((zc_arraylist_del_fn) zlog_spec_del);
if (!(a_format->pattern_specs)) {
zc_error("zc_arraylist_new fail");
goto err;
}
for (p = a_format->pattern; *p != '\0'; p = q) {
a_spec = zlog_spec_new(p, &q, time_cache_count);
if (!a_spec) {
zc_error("zlog_spec_new fail");
goto err;
}
if (zc_arraylist_add(a_format->pattern_specs, a_spec)) {
zlog_spec_del(a_spec);
zc_error("zc_arraylist_add fail");
goto err;
}
}
zlog_format_profile(a_format, ZC_DEBUG);
return a_format;
err:
zlog_format_del(a_format);
return NULL;
}
/*******************************************************************************/
/* return 0 success, or buf is full
* return -1 fail
*/
int zlog_format_gen_msg(zlog_format_t * a_format, zlog_thread_t * a_thread)
{
int i;
zlog_spec_t *a_spec;
zlog_buf_restart(a_thread->msg_buf);
zc_arraylist_foreach(a_format->pattern_specs, i, a_spec) {
if (zlog_spec_gen_msg(a_spec, a_thread) == 0) {
continue;
} else {
return -1;
}
}
return 0;
}
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_format_h
#define __zlog_format_h
#include "thread.h"
#include "zc_defs.h"
typedef struct zlog_format_s zlog_format_t;
struct zlog_format_s {
char name[MAXLEN_CFG_LINE + 1];
char pattern[MAXLEN_CFG_LINE + 1];
zc_arraylist_t *pattern_specs;
};
zlog_format_t *zlog_format_new(char *line, int * time_cache_count);
void zlog_format_del(zlog_format_t * a_format);
void zlog_format_profile(zlog_format_t * a_format, int flag);
int zlog_format_gen_msg(zlog_format_t * a_format, zlog_thread_t * a_thread);
#define zlog_format_has_name(a_format, fname) \
STRCMP(a_format->name, ==, fname)
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#ifndef _WIN32
#include <syslog.h>
#else
#include "zlog_win.h"
#endif
#include "zc_defs.h"
#include "level.h"
void zlog_level_profile(zlog_level_t *a_level, int flag)
{
zc_assert(a_level,);
zc_profile(flag, "---level[%p][%d,%s,%s,%d,%d]---",
a_level,
a_level->int_level,
a_level->str_uppercase,
a_level->str_lowercase,
(int) a_level->str_len,
a_level->syslog_level);
return;
}
/*******************************************************************************/
void zlog_level_del(zlog_level_t *a_level)
{
zc_assert(a_level,);
zc_debug("zlog_level_del[%p]", a_level);
free(a_level);
return;
}
static int syslog_level_atoi(char *str)
{
/* guess no unix system will choose -187
* as its syslog level, so it is a safe return value
*/
zc_assert(str, -187);
if (STRICMP(str, ==, "LOG_EMERG"))
return LOG_EMERG;
if (STRICMP(str, ==, "LOG_ALERT"))
return LOG_ALERT;
if (STRICMP(str, ==, "LOG_CRIT"))
return LOG_CRIT;
if (STRICMP(str, ==, "LOG_ERR"))
return LOG_ERR;
if (STRICMP(str, ==, "LOG_WARNING"))
return LOG_WARNING;
if (STRICMP(str, ==, "LOG_NOTICE"))
return LOG_NOTICE;
if (STRICMP(str, ==, "LOG_INFO"))
return LOG_INFO;
if (STRICMP(str, ==, "LOG_DEBUG"))
return LOG_DEBUG;
zc_error("wrong syslog level[%s]", str);
return -187;
}
/* line: TRACE = 10, LOG_ERR */
zlog_level_t *zlog_level_new(char *line)
{
zlog_level_t *a_level = NULL;
int i;
int nscan;
char str[MAXLEN_CFG_LINE + 1];
int l = 0;
char sl[MAXLEN_CFG_LINE + 1];
zc_assert(line, NULL);
memset(str, 0x00, sizeof(str));
memset(sl, 0x00, sizeof(sl));
nscan = sscanf(line, " %[^= \t] = %d ,%s", str, &l, sl);
if (nscan < 2) {
zc_error("level[%s], syntax wrong", line);
return NULL;
}
/* check level and str */
if ((l < 0) || (l > 255)) {
zc_error("l[%d] not in [0,255], wrong", l);
return NULL;
}
if (str[0] == '\0') {
zc_error("str[0] = 0");
return NULL;
}
a_level = calloc(1, sizeof(zlog_level_t));
if (!a_level) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
a_level->int_level = l;
/* fill syslog level */
if (sl[0] == '\0') {
a_level->syslog_level = LOG_DEBUG;
} else {
a_level->syslog_level = syslog_level_atoi(sl);
if (a_level->syslog_level == -187) {
zc_error("syslog_level_atoi fail");
goto err;
}
}
/* strncpy and toupper(str) */
for (i = 0; (i < sizeof(a_level->str_uppercase) - 1) && str[i] != '\0'; i++) {
(a_level->str_uppercase)[i] = toupper(str[i]);
(a_level->str_lowercase)[i] = tolower(str[i]);
}
if (str[i] != '\0') {
/* overflow */
zc_error("not enough space for str, str[%s] > %d", str, i);
goto err;
} else {
(a_level->str_uppercase)[i] = '\0';
(a_level->str_lowercase)[i] = '\0';
}
a_level->str_len = i;
//zlog_level_profile(a_level, ZC_DEBUG);
return a_level;
err:
zc_error("line[%s]", line);
zlog_level_del(a_level);
return NULL;
}
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_level_h
#define __zlog_level_h
#include "zc_defs.h"
typedef struct zlog_level_s {
int int_level;
char str_uppercase[MAXLEN_PATH + 1];
char str_lowercase[MAXLEN_PATH + 1];
size_t str_len;
int syslog_level;
} zlog_level_t;
zlog_level_t *zlog_level_new(char *line);
void zlog_level_del(zlog_level_t *a_level);
void zlog_level_profile(zlog_level_t *a_level, int flag);
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#ifdef _WIN32
#include "zlog_win.h"
#endif
#include "zc_defs.h"
#include "level.h"
#include "level_list.h"
/* zlog_level_list == zc_arraylist_t<zlog_level_t> */
void zlog_level_list_profile(zc_arraylist_t *levels, int flag)
{
int i;
zlog_level_t *a_level;
zc_assert(levels,);
zc_profile(flag, "--level_list[%p]--", levels);
zc_arraylist_foreach(levels, i, a_level) {
/* skip empty slots */
if (a_level) zlog_level_profile(a_level, flag);
}
return;
}
/*******************************************************************************/
void zlog_level_list_del(zc_arraylist_t *levels)
{
zc_assert(levels,);
zc_arraylist_del(levels);
zc_debug("zc_level_list_del[%p]", levels);
return;
}
static int zlog_level_list_set_default(zc_arraylist_t *levels)
{
return zlog_level_list_set(levels, "* = 0, LOG_INFO")
|| zlog_level_list_set(levels, "DEBUG = 20, LOG_DEBUG")
|| zlog_level_list_set(levels, "INFO = 40, LOG_INFO")
|| zlog_level_list_set(levels, "NOTICE = 60, LOG_NOTICE")
|| zlog_level_list_set(levels, "WARN = 80, LOG_WARNING")
|| zlog_level_list_set(levels, "ERROR = 100, LOG_ERR")
|| zlog_level_list_set(levels, "FATAL = 120, LOG_ALERT")
|| zlog_level_list_set(levels, "UNKNOWN = 254, LOG_ERR")
|| zlog_level_list_set(levels, "! = 255, LOG_INFO");
}
zc_arraylist_t *zlog_level_list_new(void)
{
zc_arraylist_t *levels;
levels = zc_arraylist_new((zc_arraylist_del_fn)zlog_level_del);
if (!levels) {
zc_error("zc_arraylist_new fail");
return NULL;
}
if (zlog_level_list_set_default(levels)) {
zc_error("zlog_level_set_default fail");
goto err;
}
//zlog_level_list_profile(levels, ZC_DEBUG);
return levels;
err:
zc_arraylist_del(levels);
return NULL;
}
/*******************************************************************************/
int zlog_level_list_set(zc_arraylist_t *levels, char *line)
{
zlog_level_t *a_level;
a_level = zlog_level_new(line);
if (!a_level) {
zc_error("zlog_level_new fail");
return -1;
}
if (zc_arraylist_set(levels, a_level->int_level, a_level)) {
zc_error("zc_arraylist_set fail");
goto err;
}
return 0;
err:
zc_error("line[%s]", line);
zlog_level_del(a_level);
return -1;
}
zlog_level_t *zlog_level_list_get(zc_arraylist_t *levels, int l)
{
zlog_level_t *a_level;
#if 0
if ((l <= 0) || (l > 254)) {
/* illegal input from zlog() */
zc_error("l[%d] not in (0,254), set to UNKOWN", l);
l = 254;
}
#endif
a_level = zc_arraylist_get(levels, l);
if (a_level) {
return a_level;
} else {
/* empty slot */
zc_error("l[%d] not in (0,254), or has no level defined,"
"see configure file define, set to UNKOWN", l);
return zc_arraylist_get(levels, 254);
}
}
/*******************************************************************************/
int zlog_level_list_atoi(zc_arraylist_t *levels, char *str)
{
int i;
zlog_level_t *a_level;
if (str == NULL || *str == '\0') {
zc_error("str is [%s], can't find level", str);
return -1;
}
zc_arraylist_foreach(levels, i, a_level) {
if (a_level && STRICMP(str, ==, a_level->str_uppercase)) {
return i;
}
}
zc_error("str[%s] can't found in level list", str);
return -1;
}
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_level_list_h
#define __zlog_level_list_h
#include "zc_defs.h"
#include "level.h"
zc_arraylist_t *zlog_level_list_new(void);
void zlog_level_list_del(zc_arraylist_t *levels);
void zlog_level_list_profile(zc_arraylist_t *levels, int flag);
/* conf init use, slow */
/* if l is wrong or str=="", return -1 */
int zlog_level_list_set(zc_arraylist_t *levels, char *line);
/* spec output use, fast */
/* rule output use, fast */
/* if not found, return levels[254] */
zlog_level_t *zlog_level_list_get(zc_arraylist_t *levels, int l);
/* rule init use, slow */
/* if not found, return -1 */
int zlog_level_list_atoi(zc_arraylist_t *levels, char *str);
#endif
/**
* =============================================================================
*
* \file lockfile.c
* \breif
* \version 1.0
* \date 2013-07-07 11:55:38
* \author Song min.Li (Li), lisongmin@126.com
* \copyright Copyright (c) 2013, skybility
*
* =============================================================================
*/
#include "lockfile.h"
#include "zc_profile.h"
LOCK_FD lock_file(char* path) {
if (!path || strlen(path) <= 0) {
return INVALID_LOCK_FD;
}
#ifdef _WIN32
LOCK_FD fd = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (fd == INVALID_LOCK_FD) {
DWORD err = GetLastError();
zc_error("lock file error : %d ", err);
}
#else
LOCK_FD fd = open(path, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
if (fd == INVALID_LOCK_FD) {
zc_error("lock file error : %s ", strerror(errno));
}
#endif
return fd;
}
bool unlock_file(LOCK_FD fd) {
if (fd == INVALID_LOCK_FD) {
return true;
}
#ifdef _WIN32
bool ret = CloseHandle(fd);
if (ret == false) {
DWORD err = GetLastError();
zc_error("unlock file error : %d ", err);
}
#else
bool ret = close(fd) == 0;
if (ret == false) {
zc_error("unlock file error : %s ", strerror(errno));
}
#endif
return ret;
}
/**
* =============================================================================
*
* \file lockfile.h
* \breif
* \version 1.0
* \date 2013-07-07 12:34:20
* \author Song min.Li (Li), lisongmin@126.com
* \copyright Copyright (c) 2013, skybility
*
* =============================================================================
*/
#ifndef __ZLOG_LOCK_FILE_H__
#define __ZLOG_LOCK_FILE_H__
#ifdef _WIN32
#include <Windows.h>
#include <WinBase.h>
#define LOCK_FD HANDLE
#define INVALID_LOCK_FD INVALID_HANDLE_VALUE
#else //_WIN32
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#define LOCK_FD int
#define INVALID_LOCK_FD -1
#endif
#include <stdbool.h>
/**
* lock file.
*/
LOCK_FD lock_file(char* path);
/**
* unlock file.
*/
bool unlock_file(LOCK_FD fd);
#endif //__ZLOG_LOCK_FILE_H__
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include "mdc.h"
#include "zc_defs.h"
void zlog_mdc_profile(zlog_mdc_t *a_mdc, int flag)
{
zc_hashtable_entry_t *a_entry;
zlog_mdc_kv_t *a_mdc_kv;
zc_assert(a_mdc,);
zc_profile(flag, "---mdc[%p]---", a_mdc);
zc_hashtable_foreach(a_mdc->tab, a_entry) {
a_mdc_kv = a_entry->value;
zc_profile(flag, "----mdc_kv[%p][%s]-[%s]----",
a_mdc_kv,
a_mdc_kv->key, a_mdc_kv->value);
}
return;
}
/*******************************************************************************/
void zlog_mdc_del(zlog_mdc_t * a_mdc)
{
zc_assert(a_mdc,);
if (a_mdc->tab) zc_hashtable_del(a_mdc->tab);
zc_debug("zlog_mdc_del[%p]", a_mdc);
free(a_mdc);
return;
}
static void zlog_mdc_kv_del(zlog_mdc_kv_t * a_mdc_kv)
{
zc_debug("zlog_mdc_kv_del[%p]", a_mdc_kv);
free(a_mdc_kv);
}
static zlog_mdc_kv_t *zlog_mdc_kv_new(const char *key, const char *value)
{
zlog_mdc_kv_t *a_mdc_kv;
a_mdc_kv = calloc(1, sizeof(zlog_mdc_kv_t));
if (!a_mdc_kv) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
snprintf(a_mdc_kv->key, sizeof(a_mdc_kv->key), "%s", key);
a_mdc_kv->value_len = snprintf(a_mdc_kv->value, sizeof(a_mdc_kv->value), "%s", value);
return a_mdc_kv;
}
zlog_mdc_t *zlog_mdc_new(void)
{
zlog_mdc_t *a_mdc;
a_mdc = calloc(1, sizeof(zlog_mdc_t));
if (!a_mdc) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
a_mdc->tab = zc_hashtable_new(20,
zc_hashtable_str_hash,
zc_hashtable_str_equal, NULL,
(zc_hashtable_del_fn) zlog_mdc_kv_del);
if (!a_mdc->tab) {
zc_error("zc_hashtable_new fail");
goto err;
}
//zlog_mdc_profile(a_mdc, ZC_DEBUG);
return a_mdc;
err:
zlog_mdc_del(a_mdc);
return NULL;
}
/*******************************************************************************/
int zlog_mdc_put(zlog_mdc_t * a_mdc, const char *key, const char *value)
{
zlog_mdc_kv_t *a_mdc_kv;
a_mdc_kv = zlog_mdc_kv_new(key, value);
if (!a_mdc_kv) {
zc_error("zlog_mdc_kv_new failed");
return -1;
}
if (zc_hashtable_put(a_mdc->tab, a_mdc_kv->key, a_mdc_kv)) {
zc_error("zc_hashtable_put fail");
zlog_mdc_kv_del(a_mdc_kv);
return -1;
}
return 0;
}
void zlog_mdc_clean(zlog_mdc_t * a_mdc)
{
zc_hashtable_clean(a_mdc->tab);
return;
}
char *zlog_mdc_get(zlog_mdc_t * a_mdc, const char *key)
{
zlog_mdc_kv_t *a_mdc_kv;
a_mdc_kv = zc_hashtable_get(a_mdc->tab, key);
if (!a_mdc_kv) {
zc_error("zc_hashtable_get fail");
return NULL;
} else {
return a_mdc_kv->value;
}
}
zlog_mdc_kv_t *zlog_mdc_get_kv(zlog_mdc_t * a_mdc, const char *key)
{
zlog_mdc_kv_t *a_mdc_kv;
a_mdc_kv = zc_hashtable_get(a_mdc->tab, key);
if (!a_mdc_kv) {
zc_error("zc_hashtable_get fail");
return NULL;
} else {
return a_mdc_kv;
}
}
void zlog_mdc_remove(zlog_mdc_t * a_mdc, const char *key)
{
zc_hashtable_remove(a_mdc->tab, key);
return;
}
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_mdc_h
#define __zlog_mdc_h
#include "zc_defs.h"
typedef struct zlog_mdc_s zlog_mdc_t;
struct zlog_mdc_s {
zc_hashtable_t *tab;
};
zlog_mdc_t *zlog_mdc_new(void);
void zlog_mdc_del(zlog_mdc_t * a_mdc);
void zlog_mdc_profile(zlog_mdc_t *a_mdc, int flag);
void zlog_mdc_clean(zlog_mdc_t * a_mdc);
int zlog_mdc_put(zlog_mdc_t * a_mdc, const char *key, const char *value);
char *zlog_mdc_get(zlog_mdc_t * a_mdc, const char *key);
void zlog_mdc_remove(zlog_mdc_t * a_mdc, const char *key);
typedef struct zlog_mdc_kv_s {
char key[MAXLEN_PATH + 1];
char value[MAXLEN_PATH + 1];
size_t value_len;
} zlog_mdc_kv_t;
zlog_mdc_kv_t *zlog_mdc_get_kv(zlog_mdc_t * a_mdc, const char *key);
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "errno.h"
#include "zc_defs.h"
#include "record.h"
void zlog_record_profile(zlog_record_t *a_record, int flag)
{
zc_assert(a_record,);
zc_profile(flag, "--record:[%p][%s:%p]--", a_record, a_record->name, a_record->output);
return;
}
void zlog_record_del(zlog_record_t *a_record)
{
zc_assert(a_record,);
zc_debug("zlog_record_del[%p]", a_record);
free(a_record);
return;
}
zlog_record_t *zlog_record_new(const char *name, zlog_record_fn output)
{
zlog_record_t *a_record;
zc_assert(name, NULL);
zc_assert(output, NULL);
a_record = calloc(1, sizeof(zlog_record_t));
if (!a_record) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
if (strlen(name) > sizeof(a_record->name) - 1) {
zc_error("name[%s] is too long", name);
goto err;
}
strcpy(a_record->name, name);
a_record->output = output;
zlog_record_profile(a_record, ZC_DEBUG);
return a_record;
err:
zlog_record_del(a_record);
return NULL;
}
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_record_h
#define __zlog_record_h
#include "zc_defs.h"
/* record is user-defined output function and it's name from configure file */
typedef struct zlog_msg_s {
char *buf;
size_t len;
char *path;
} zlog_msg_t; /* 3 of this first, see need thread or not later */
typedef int (*zlog_record_fn)(zlog_msg_t * msg);
typedef struct zlog_record_s {
char name[MAXLEN_PATH + 1];
zlog_record_fn output;
} zlog_record_t;
zlog_record_t *zlog_record_new(const char *name, zlog_record_fn output);
void zlog_record_del(zlog_record_t *a_record);
void zlog_record_profile(zlog_record_t *a_record, int flag);
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "zc_defs.h"
#include "record_table.h"
void zlog_record_table_profile(zc_hashtable_t * records, int flag)
{
zc_hashtable_entry_t *a_entry;
zlog_record_t *a_record;
zc_assert(records,);
zc_profile(flag, "-record_table[%p]-", records);
zc_hashtable_foreach(records, a_entry) {
a_record = (zlog_record_t *) a_entry->value;
zlog_record_profile(a_record, flag);
}
return;
}
/*******************************************************************************/
void zlog_record_table_del(zc_hashtable_t * records)
{
zc_assert(records,);
zc_hashtable_del(records);
zc_debug("zlog_record_table_del[%p]", records);
return;
}
zc_hashtable_t *zlog_record_table_new(void)
{
zc_hashtable_t *records;
records = zc_hashtable_new(20,
(zc_hashtable_hash_fn) zc_hashtable_str_hash,
(zc_hashtable_equal_fn) zc_hashtable_str_equal,
NULL, (zc_hashtable_del_fn) zlog_record_del);
if (!records) {
zc_error("zc_hashtable_new fail");
return NULL;
} else {
zlog_record_table_profile(records, ZC_DEBUG);
return records;
}
}
/*******************************************************************************/
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_record_table_h
#define __zlog_record_table_h
#include "zc_defs.h"
#include "record.h"
zc_hashtable_t *zlog_record_table_new(void);
void zlog_record_table_del(zc_hashtable_t * records);
void zlog_record_table_profile(zc_hashtable_t * records, int flag);
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#ifdef _WIN32
#include <unixem/glob.h>
#endif
#include <glob.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include "zc_defs.h"
#include "rotater.h"
#define ROLLING 1 /* aa.02->aa.03, aa.01->aa.02, aa->aa.01 */
#define SEQUENCE 2 /* aa->aa.03 */
typedef struct {
int index;
char path[MAXLEN_PATH + 1];
} zlog_file_t;
void zlog_rotater_profile(zlog_rotater_t * a_rotater, int flag)
{
zc_assert(a_rotater,);
zc_profile(flag, "--rotater[%p][%p,%s,%d][%s,%s,%s,%ld,%ld,%d,%d,%d]--",
a_rotater,
&(a_rotater->lock_mutex),
a_rotater->lock_file,
a_rotater->lock_fd,
a_rotater->base_path,
a_rotater->archive_path,
a_rotater->glob_path,
(long)a_rotater->num_start_len,
(long)a_rotater->num_end_len,
a_rotater->num_width,
a_rotater->mv_type,
a_rotater->max_count
);
if (a_rotater->files) {
int i;
zlog_file_t *a_file;
zc_arraylist_foreach(a_rotater->files, i, a_file) {
zc_profile(flag, "[%s,%d]->", a_file->path, a_file->index);
}
}
return;
}
/*******************************************************************************/
void zlog_rotater_del(zlog_rotater_t *a_rotater)
{
zc_assert(a_rotater,);
if (a_rotater->lock_fd != INVALID_LOCK_FD) {
if (!unlock_file(a_rotater->lock_fd)) {
zc_error("close fail, errno[%d]", errno);
}
a_rotater->lock_fd = INVALID_LOCK_FD;
}
if (pthread_mutex_destroy(&(a_rotater->lock_mutex))) {
zc_error("pthread_mutex_destroy fail, errno[%d]", errno);
}
zc_debug("zlog_rotater_del[%p]", a_rotater);
free(a_rotater);
return;
}
zlog_rotater_t *zlog_rotater_new(char *lock_file)
{
zlog_rotater_t *a_rotater;
zc_assert(lock_file, NULL);
a_rotater = calloc(1, sizeof(zlog_rotater_t));
if (!a_rotater) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
if (pthread_mutex_init(&(a_rotater->lock_mutex), NULL)) {
zc_error("pthread_mutex_init fail, errno[%d]", errno);
free(a_rotater);
return NULL;
}
a_rotater->lock_fd = INVALID_LOCK_FD;
a_rotater->lock_file = lock_file;
//zlog_rotater_profile(a_rotater, ZC_DEBUG);
return a_rotater;
zlog_rotater_del(a_rotater);
return NULL;
}
/*******************************************************************************/
static void zlog_file_del(zlog_file_t * a_file)
{
zc_debug("del onefile[%p]", a_file);
zc_debug("a_file->path[%s]", a_file->path);
free(a_file);
}
static zlog_file_t *zlog_file_check_new(zlog_rotater_t * a_rotater, const char *path)
{
int nwrite;
int nread;
zlog_file_t *a_file;
/* base_path will not be in list */
if (STRCMP(a_rotater->base_path, ==, path)) {
return NULL;
}
/* omit dirs */
if ((path)[strlen(path) - 1] == '/') {
return NULL;
}
a_file = calloc(1, sizeof(zlog_file_t));
if (!a_file) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
nwrite = snprintf(a_file->path, sizeof(a_file->path), "%s", path);
if (nwrite < 0 || nwrite >= sizeof(a_file->path)) {
zc_error("snprintf fail or overflow, nwrite=[%d], errno[%d]", nwrite, errno);
goto err;
}
nread = 0;
sscanf(a_file->path + a_rotater->num_start_len, "%d%n", &(a_file->index), &(nread));
if (a_rotater->num_width != 0) {
if (nread < a_rotater->num_width) {
zc_warn("aa.1.log is not expect, need aa.01.log");
goto err;
}
} /* else all file is ok */
return a_file;
err:
free(a_file);
return NULL;
}
static int zlog_file_cmp(zlog_file_t * a_file_1, zlog_file_t * a_file_2)
{
return (a_file_1->index > a_file_2->index);
}
static int zlog_rotater_add_archive_files(zlog_rotater_t * a_rotater)
{
int rc = 0;
glob_t glob_buf;
size_t pathc;
char **pathv;
zlog_file_t *a_file;
a_rotater->files = zc_arraylist_new((zc_arraylist_del_fn)zlog_file_del);
if (!a_rotater->files) {
zc_error("zc_arraylist_new fail");
return -1;
}
/* scan file which is aa.*.log and aa */
rc = glob(a_rotater->glob_path, GLOB_ERR | GLOB_MARK | GLOB_NOSORT, NULL, &glob_buf);
if (rc == GLOB_NOMATCH) {
goto exit;
} else if (rc) {
zc_error("glob err, rc=[%d], errno[%d]", rc, errno);
return -1;
}
pathv = glob_buf.gl_pathv;
pathc = glob_buf.gl_pathc;
/* check and find match aa.[0-9]*.log, depend on num_width */
for (; pathc-- > 0; pathv++) {
a_file = zlog_file_check_new(a_rotater, *pathv);
if (!a_file) {
zc_warn("not the expect pattern file");
continue;
}
/* file in list aa.00, aa.01, aa.02... */
rc = zc_arraylist_sortadd(a_rotater->files,
(zc_arraylist_cmp_fn)zlog_file_cmp, a_file);
if (rc) {
zc_error("zc_arraylist_sortadd fail");
goto err;
}
}
exit:
globfree(&glob_buf);
return 0;
err:
globfree(&glob_buf);
return -1;
}
static int zlog_rotater_seq_files(zlog_rotater_t * a_rotater)
{
int rc = 0;
int nwrite = 0;
int i, j;
zlog_file_t *a_file;
char new_path[MAXLEN_PATH + 1];
zc_arraylist_foreach(a_rotater->files, i, a_file) {
if (a_rotater->max_count > 0
&& i < zc_arraylist_len(a_rotater->files) - a_rotater->max_count) {
/* unlink aa.0 aa.1 .. aa.(n-c) */
rc = unlink(a_file->path);
if (rc) {
zc_error("unlink[%s] fail, errno[%d]",a_file->path , errno);
return -1;
}
continue;
}
}
if (zc_arraylist_len(a_rotater->files) > 0) { /* list is not empty */
a_file = zc_arraylist_get(a_rotater->files, zc_arraylist_len(a_rotater->files)-1);
if (!a_file) {
zc_error("zc_arraylist_get fail");
return -1;
}
j = zc_max(zc_arraylist_len(a_rotater->files)-1, a_file->index) + 1;
} else {
j = 0;
}
/* do the base_path mv */
memset(new_path, 0x00, sizeof(new_path));
nwrite = snprintf(new_path, sizeof(new_path), "%.*s%0*d%s",
(int) a_rotater->num_start_len, a_rotater->glob_path,
a_rotater->num_width, j,
a_rotater->glob_path + a_rotater->num_end_len);
if (nwrite < 0 || nwrite >= sizeof(new_path)) {
zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno);
return -1;
}
if (rename(a_rotater->base_path, new_path)) {
zc_error("rename[%s]->[%s] fail, errno[%d]", a_rotater->base_path, new_path, errno);
return -1;
}
return 0;
}
static int zlog_rotater_roll_files(zlog_rotater_t * a_rotater)
{
int i;
int rc = 0;
int nwrite;
char new_path[MAXLEN_PATH + 1];
zlog_file_t *a_file;
/* now in the list, aa.0 aa.1 aa.2 aa.02... */
for (i = zc_arraylist_len(a_rotater->files) - 1; i > -1; i--) {
a_file = zc_arraylist_get(a_rotater->files, i);
if (!a_file) {
zc_error("zc_arraylist_get fail");
return -1;
}
if (a_rotater->max_count > 0 && i >= a_rotater->max_count - 1) {
/* remove file.3 >= 3*/
rc = unlink(a_file->path);
if (rc) {
zc_error("unlink[%s] fail, errno[%d]",a_file->path , errno);
return -1;
}
continue;
}
/* begin rename aa.01.log -> aa.02.log , using i, as index in list maybe repeat */
memset(new_path, 0x00, sizeof(new_path));
nwrite = snprintf(new_path, sizeof(new_path), "%.*s%0*d%s",
(int) a_rotater->num_start_len, a_rotater->glob_path,
a_rotater->num_width, i + 1,
a_rotater->glob_path + a_rotater->num_end_len);
if (nwrite < 0 || nwrite >= sizeof(new_path)) {
zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno);
return -1;
}
if (rename(a_file->path, new_path)) {
zc_error("rename[%s]->[%s] fail, errno[%d]", a_file->path, new_path, errno);
return -1;
}
}
/* do the base_path mv */
memset(new_path, 0x00, sizeof(new_path));
nwrite = snprintf(new_path, sizeof(new_path), "%.*s%0*d%s",
(int) a_rotater->num_start_len, a_rotater->glob_path,
a_rotater->num_width, 0,
a_rotater->glob_path + a_rotater->num_end_len);
if (nwrite < 0 || nwrite >= sizeof(new_path)) {
zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno);
return -1;
}
if (rename(a_rotater->base_path, new_path)) {
zc_error("rename[%s]->[%s] fail, errno[%d]", a_rotater->base_path, new_path, errno);
return -1;
}
return 0;
}
static int zlog_rotater_parse_archive_path(zlog_rotater_t * a_rotater)
{
int nwrite;
int nread;
char *p;
size_t len;
/* no archive path is set */
if (a_rotater->archive_path[0] == '\0') {
nwrite = snprintf(a_rotater->glob_path, sizeof(a_rotater->glob_path),
"%s.*", a_rotater->base_path);
if (nwrite < 0 || nwrite > sizeof(a_rotater->glob_path)) {
zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno);
return -1;
}
a_rotater->mv_type = ROLLING;
a_rotater->num_width = 0;
a_rotater->num_start_len = strlen(a_rotater->base_path) + 1;
a_rotater->num_end_len = strlen(a_rotater->base_path) + 2;
return 0;
} else {
/* find the 1st # */
p = strchr(a_rotater->archive_path, '#');
if (!p) {
zc_error("no # in archive_path[%s]", a_rotater->archive_path);
return -1;
}
nread = 0;
sscanf(p, "#%d%n", &(a_rotater->num_width), &nread);
if (nread == 0) nread = 1;
if (*(p+nread) == 'r') {
a_rotater->mv_type = ROLLING;
} else if (*(p+nread) == 's') {
a_rotater->mv_type = SEQUENCE;
} else {
zc_error("#r or #s not found");
return -1;
}
/* copy and substitue #i to * in glob_path*/
len = p - a_rotater->archive_path;
if (len > sizeof(a_rotater->glob_path) - 1) {
zc_error("sizeof glob_path not enough,len[%ld]", (long) len);
return -1;
}
memcpy(a_rotater->glob_path, a_rotater->archive_path, len);
nwrite = snprintf(a_rotater->glob_path + len, sizeof(a_rotater->glob_path) - len,
"*%s", p + nread + 1);
if (nwrite < 0 || nwrite > sizeof(a_rotater->glob_path) - len) {
zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno);
return -1;
}
a_rotater->num_start_len = len;
a_rotater->num_end_len = len + 1;
}
return 0;
}
static void zlog_rotater_clean(zlog_rotater_t *a_rotater)
{
a_rotater->base_path = NULL;
a_rotater->archive_path = NULL;
a_rotater->max_count = 0;
a_rotater->mv_type = 0;
a_rotater->num_width = 0;
a_rotater->num_start_len = 0;
a_rotater->num_end_len = 0;
memset(a_rotater->glob_path, 0x00, sizeof(a_rotater->glob_path));
if (a_rotater->files) zc_arraylist_del(a_rotater->files);
a_rotater->files = NULL;
}
static int zlog_rotater_lsmv(zlog_rotater_t *a_rotater,
char *base_path, char *archive_path, int archive_max_count)
{
int rc = 0;
a_rotater->base_path = base_path;
a_rotater->archive_path = archive_path;
a_rotater->max_count = archive_max_count;
rc = zlog_rotater_parse_archive_path(a_rotater);
if (rc) {
zc_error("zlog_rotater_parse_archive_path fail");
goto err;
}
rc = zlog_rotater_add_archive_files(a_rotater);
if (rc) {
zc_error("zlog_rotater_add_archive_files fail");
goto err;
}
if (a_rotater->mv_type == ROLLING) {
rc = zlog_rotater_roll_files(a_rotater);
if (rc) {
zc_error("zlog_rotater_roll_files fail");
goto err;
}
} else if (a_rotater->mv_type == SEQUENCE) {
rc = zlog_rotater_seq_files(a_rotater);
if (rc) {
zc_error("zlog_rotater_seq_files fail");
goto err;
}
}
zlog_rotater_clean(a_rotater);
return 0;
err:
zlog_rotater_clean(a_rotater);
return -1;
}
/*******************************************************************************/
static int zlog_rotater_trylock(zlog_rotater_t *a_rotater)
{
int rc;
rc = pthread_mutex_trylock(&(a_rotater->lock_mutex));
if (rc == EBUSY) {
zc_warn("pthread_mutex_trylock fail, as lock_mutex is locked by other threads");
return -1;
} else if (rc != 0) {
zc_error("pthread_mutex_trylock fail, rc[%d]", rc);
return -1;
}
a_rotater->lock_fd = lock_file(a_rotater->lock_file);
if (a_rotater->lock_fd == INVALID_LOCK_FD) {
return -1;
}
return 0;
}
static int zlog_rotater_unlock(zlog_rotater_t *a_rotater)
{
int rc = 0;
if (!unlock_file(a_rotater->lock_fd)) {
rc = -1;
} else {
a_rotater->lock_fd = INVALID_LOCK_FD;
}
if (pthread_mutex_unlock(&(a_rotater->lock_mutex))) {
rc = -1;
zc_error("pthread_mutext_unlock fail, errno[%d]", errno);
}
return rc;
}
int zlog_rotater_rotate(zlog_rotater_t *a_rotater,
char *base_path, size_t msg_len,
char *archive_path, long archive_max_size, int archive_max_count)
{
int rc = 0;
struct zlog_stat info;
zc_assert(base_path, -1);
if (zlog_rotater_trylock(a_rotater)) {
zc_warn("zlog_rotater_trylock fail, maybe lock by other process or threads");
return 0;
}
if (stat(base_path, &info)) {
rc = -1;
zc_error("stat [%s] fail, errno[%d]", base_path, errno);
goto exit;
}
if (info.st_size + msg_len <= archive_max_size) {
/* file not so big,
* may alread rotate by oth process or thread,
* return */
rc = 0;
goto exit;
}
/* begin list and move files */
rc = zlog_rotater_lsmv(a_rotater, base_path, archive_path, archive_max_count);
if (rc) {
zc_error("zlog_rotater_lsmv [%s] fail, return", base_path);
rc = -1;
} /* else if (rc == 0) */
//zc_debug("zlog_rotater_file_ls_mv success");
exit:
/* unlock file */
if (zlog_rotater_unlock(a_rotater)) {
zc_error("zlog_rotater_unlock fail");
}
return rc;
}
/*******************************************************************************/
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_rotater_h
#define __zlog_rotater_h
#include "zc_defs.h"
#include "lockfile.h"
typedef struct zlog_rotater_s {
pthread_mutex_t lock_mutex;
char *lock_file;
LOCK_FD lock_fd;
/* single-use members */
char *base_path; /* aa.log */
char *archive_path; /* aa.#5i.log */
char glob_path[MAXLEN_PATH + 1]; /* aa.*.log */
size_t num_start_len; /* 3, offset to glob_path */
size_t num_end_len; /* 6, offset to glob_path */
int num_width; /* 5 */
int mv_type; /* ROLLING or SEQUENCE */
int max_count;
zc_arraylist_t *files;
} zlog_rotater_t;
zlog_rotater_t *zlog_rotater_new(char *lock_file);
void zlog_rotater_del(zlog_rotater_t *a_rotater);
/*
* return
* -1 fail
* 0 no rotate, or rotate and success
*/
int zlog_rotater_rotate(zlog_rotater_t *a_rotater,
char *base_path, size_t msg_len,
char *archive_path, long archive_max_size, int archive_max_count);
void zlog_rotater_profile(zlog_rotater_t *a_rotater, int flag);
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fmacros.h"
#include <string.h>
#include <ctype.h>
#ifndef _WIN32
#include <syslog.h>
#else
#include "zlog_win.h"
#endif
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include "rule.h"
#include "format.h"
#include "buf.h"
#include "thread.h"
#include "level_list.h"
#include "rotater.h"
#include "spec.h"
#include "conf.h"
#include "zc_defs.h"
void zlog_rule_profile(zlog_rule_t * a_rule, int flag)
{
int i;
zlog_spec_t *a_spec;
zc_assert(a_rule,);
zc_profile(flag, "---rule:[%p][%s%c%d]-[%d,%d][%s,%p,%d:%ld*%d~%s][%d][%d][%s:%s:%p];[%p]---",
a_rule,
a_rule->category,
a_rule->compare_char,
a_rule->level,
a_rule->file_perms,
a_rule->file_open_flags,
a_rule->file_path,
a_rule->dynamic_specs,
a_rule->static_fd,
a_rule->archive_max_size,
a_rule->archive_max_count,
a_rule->archive_path,
a_rule->pipe_fd,
a_rule->syslog_facility,
a_rule->record_name,
a_rule->record_path,
a_rule->record_func,
a_rule->format);
if (a_rule->dynamic_specs) {
zc_arraylist_foreach(a_rule->dynamic_specs, i, a_spec) {
zlog_spec_profile(a_spec, flag);
}
}
return;
}
/*******************************************************************************/
static int zlog_rule_output_static_file_single(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
{
struct stat stb;
int do_file_reload = 0;
int redo_inode_stat = 0;
if (zlog_format_gen_msg(a_rule->format, a_thread)) {
zc_error("zlog_format_gen_msg fail");
return -1;
}
/* check if the output file was changed by an external tool by comparing the inode to our saved off one */
if (stat(a_rule->file_path, &stb)) {
if (errno != ENOENT) {
zc_error("stat fail on [%s], errno[%d]", a_rule->file_path, errno);
return -1;
} else {
do_file_reload = 1;
redo_inode_stat = 1; /* we'll have to restat the newly created file to get the inode info */
}
} else {
do_file_reload = (stb.st_ino != a_rule->static_ino || stb.st_dev != a_rule->static_dev);
}
if (do_file_reload) {
close(a_rule->static_fd);
a_rule->static_fd = open(a_rule->file_path,
O_WRONLY | O_APPEND | O_CREAT | a_rule->file_open_flags,
a_rule->file_perms);
if (a_rule->static_fd < 0) {
zc_error("open file[%s] fail, errno[%d]", a_rule->file_path, errno);
return -1;
}
/* save off the new dev/inode info from the stat call we already did */
if (redo_inode_stat) {
if (stat(a_rule->file_path, &stb)) {
zc_error("stat fail on new file[%s], errno[%d]", a_rule->file_path, errno);
return -1;
}
}
a_rule->static_dev = stb.st_dev;
a_rule->static_ino = stb.st_ino;
}
if (write(a_rule->static_fd,
zlog_buf_str(a_thread->msg_buf),
zlog_buf_len(a_thread->msg_buf)) < 0) {
zc_error("write fail, errno[%d]", errno);
return -1;
}
/* not so thread safe here, as multiple thread may ++fsync_count at the same time */
if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) {
a_rule->fsync_count = 0;
if (fsync(a_rule->static_fd)) {
zc_error("fsync[%d] fail, errno[%d]", a_rule->static_fd, errno);
}
}
return 0;
}
static char * zlog_rule_gen_archive_path(zlog_rule_t *a_rule, zlog_thread_t *a_thread)
{
int i;
zlog_spec_t *a_spec;
if (!a_rule->archive_specs) return a_rule->archive_path;
zlog_buf_restart(a_thread->archive_path_buf);
zc_arraylist_foreach(a_rule->archive_specs, i, a_spec) {
if (zlog_spec_gen_archive_path(a_spec, a_thread)) {
zc_error("zlog_spec_gen_path fail");
return NULL;
}
}
zlog_buf_seal(a_thread->archive_path_buf);
return zlog_buf_str(a_thread->archive_path_buf);
}
static int zlog_rule_output_static_file_rotate(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
{
size_t len;
struct zlog_stat info;
int fd;
if (zlog_format_gen_msg(a_rule->format, a_thread)) {
zc_error("zlog_format_gen_msg fail");
return -1;
}
fd = open(a_rule->file_path,
a_rule->file_open_flags | O_WRONLY | O_APPEND | O_CREAT, a_rule->file_perms);
if (fd < 0) {
zc_error("open file[%s] fail, errno[%d]", a_rule->file_path, errno);
return -1;
}
len = zlog_buf_len(a_thread->msg_buf);
if (write(fd, zlog_buf_str(a_thread->msg_buf), len) < 0) {
zc_error("write fail, errno[%d]", errno);
close(fd);
return -1;
}
if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) {
a_rule->fsync_count = 0;
if (fsync(fd)) zc_error("fsync[%d] fail, errno[%d]", fd, errno);
}
if (close(fd) < 0) {
zc_error("close fail, maybe cause by write, errno[%d]", errno);
return -1;
}
if (len > a_rule->archive_max_size) {
zc_debug("one msg's len[%ld] > archive_max_size[%ld], no rotate",
(long)len, (long)a_rule->archive_max_size);
return 0;
}
if (stat(a_rule->file_path, &info)) {
zc_warn("stat [%s] fail, errno[%d], maybe in rotating", a_rule->file_path, errno);
return 0;
}
/* file not so big, return */
if (info.st_size + len < a_rule->archive_max_size) return 0;
if (zlog_rotater_rotate(zlog_env_conf->rotater,
a_rule->file_path, len,
zlog_rule_gen_archive_path(a_rule, a_thread),
a_rule->archive_max_size, a_rule->archive_max_count)
) {
zc_error("zlog_rotater_rotate fail");
return -1;
} /* success or no rotation do nothing */
return 0;
}
/* return path success
* return NULL fail
*/
#define zlog_rule_gen_path(a_rule, a_thread) do { \
int i; \
zlog_spec_t *a_spec; \
\
zlog_buf_restart(a_thread->path_buf); \
\
zc_arraylist_foreach(a_rule->dynamic_specs, i, a_spec) { \
if (zlog_spec_gen_path(a_spec, a_thread)) { \
zc_error("zlog_spec_gen_path fail"); \
return -1; \
} \
} \
\
zlog_buf_seal(a_thread->path_buf); \
} while(0)
static int zlog_rule_output_dynamic_file_single(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
{
int fd;
zlog_rule_gen_path(a_rule, a_thread);
if (zlog_format_gen_msg(a_rule->format, a_thread)) {
zc_error("zlog_format_output fail");
return -1;
}
fd = open(zlog_buf_str(a_thread->path_buf),
a_rule->file_open_flags | O_WRONLY | O_APPEND | O_CREAT, a_rule->file_perms);
if (fd < 0) {
zc_error("open file[%s] fail, errno[%d]", zlog_buf_str(a_thread->path_buf), errno);
return -1;
}
if (write(fd, zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg_buf)) < 0) {
zc_error("write fail, errno[%d]", errno);
close(fd);
return -1;
}
if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) {
a_rule->fsync_count = 0;
if (fsync(fd)) zc_error("fsync[%d] fail, errno[%d]", fd, errno);
}
if (close(fd) < 0) {
zc_error("close fail, maybe cause by write, errno[%d]", errno);
return -1;
}
return 0;
}
static int zlog_rule_output_dynamic_file_rotate(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
{
int fd;
char *path;
size_t len;
struct zlog_stat info;
zlog_rule_gen_path(a_rule, a_thread);
if (zlog_format_gen_msg(a_rule->format, a_thread)) {
zc_error("zlog_format_output fail");
return -1;
}
path = zlog_buf_str(a_thread->path_buf);
fd = open(path, a_rule->file_open_flags | O_WRONLY | O_APPEND | O_CREAT, a_rule->file_perms);
if (fd < 0) {
zc_error("open file[%s] fail, errno[%d]", zlog_buf_str(a_thread->path_buf), errno);
return -1;
}
len = zlog_buf_len(a_thread->msg_buf);
if (write(fd, zlog_buf_str(a_thread->msg_buf), len) < 0) {
zc_error("write fail, errno[%d]", errno);
close(fd);
return -1;
}
if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) {
a_rule->fsync_count = 0;
if (fsync(fd)) zc_error("fsync[%d] fail, errno[%d]", fd, errno);
}
if (close(fd) < 0) {
zc_error("write fail, maybe cause by write, errno[%d]", errno);
return -1;
}
if (len > a_rule->archive_max_size) {
zc_debug("one msg's len[%ld] > archive_max_size[%ld], no rotate",
(long)len, (long) a_rule->archive_max_size);
return 0;
}
if (stat(path, &info)) {
zc_warn("stat [%s] fail, errno[%d], maybe in rotating", path, errno);
return 0;
}
/* file not so big, return */
if (info.st_size + len < a_rule->archive_max_size) return 0;
if (zlog_rotater_rotate(zlog_env_conf->rotater,
path, len,
zlog_rule_gen_archive_path(a_rule, a_thread),
a_rule->archive_max_size, a_rule->archive_max_count)
) {
zc_error("zlog_rotater_rotate fail");
return -1;
} /* success or no rotation do nothing */
return 0;
}
static int zlog_rule_output_pipe(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
{
if (zlog_format_gen_msg(a_rule->format, a_thread)) {
zc_error("zlog_format_gen_msg fail");
return -1;
}
if (write(a_rule->pipe_fd,
zlog_buf_str(a_thread->msg_buf),
zlog_buf_len(a_thread->msg_buf)) < 0) {
zc_error("write fail, errno[%d]", errno);
return -1;
}
return 0;
}
static int zlog_rule_output_syslog(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
{
#ifndef _WIN32
zlog_level_t *a_level;
if (zlog_format_gen_msg(a_rule->format, a_thread)) {
zc_error("zlog_format_gen_msg fail");
return -1;
}
/*
msg = a_thread->msg_buf->start;
msg_len = a_thread->msg_buf->end - a_thread->msg_buf->start;
*/
a_level = zlog_level_list_get(zlog_env_conf->levels, a_thread->event->level);
zlog_buf_seal(a_thread->msg_buf);
syslog(a_rule->syslog_facility | a_level->syslog_level,
"%s", zlog_buf_str(a_thread->msg_buf));
#endif
return 0;
}
static int zlog_rule_output_static_record(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
{
zlog_msg_t msg;
if (!a_rule->record_func) {
zc_error("user defined record funcion for [%s] not set, no output",
a_rule->record_name);
return -1;
}
if (zlog_format_gen_msg(a_rule->format, a_thread)) {
zc_error("zlog_format_gen_msg fail");
return -1;
}
zlog_buf_seal(a_thread->msg_buf);
msg.buf = zlog_buf_str(a_thread->msg_buf);
msg.len = zlog_buf_len(a_thread->msg_buf);
msg.path = a_rule->record_path;
if (a_rule->record_func(&msg)) {
zc_error("a_rule->record fail");
return -1;
}
return 0;
}
static int zlog_rule_output_dynamic_record(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
{
zlog_msg_t msg;
if (!a_rule->record_func) {
zc_error("user defined record funcion for [%s] not set, no output",
a_rule->record_name);
return -1;
}
zlog_rule_gen_path(a_rule, a_thread);
if (zlog_format_gen_msg(a_rule->format, a_thread)) {
zc_error("zlog_format_gen_msg fail");
return -1;
}
zlog_buf_seal(a_thread->msg_buf);
msg.buf = zlog_buf_str(a_thread->msg_buf);
msg.len = zlog_buf_len(a_thread->msg_buf);
msg.path = zlog_buf_str(a_thread->path_buf);
if (a_rule->record_func(&msg)) {
zc_error("a_rule->record fail");
return -1;
}
return 0;
}
static int zlog_rule_output_stdout(zlog_rule_t * a_rule,
zlog_thread_t * a_thread)
{
if (zlog_format_gen_msg(a_rule->format, a_thread)) {
zc_error("zlog_format_gen_msg fail");
return -1;
}
if (write(STDOUT_FILENO,
zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg_buf)) < 0) {
zc_error("write fail, errno[%d]", errno);
return -1;
}
return 0;
}
static int zlog_rule_output_stderr(zlog_rule_t * a_rule,
zlog_thread_t * a_thread)
{
if (zlog_format_gen_msg(a_rule->format, a_thread)) {
zc_error("zlog_format_gen_msg fail");
return -1;
}
if (write(STDERR_FILENO,
zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg_buf)) < 0) {
zc_error("write fail, errno[%d]", errno);
return -1;
}
return 0;
}
/*******************************************************************************/
static int syslog_facility_atoi(char *facility)
{
#ifndef _WIN32
/* guess no unix system will choose -187
* as its syslog facility, so it is a safe return value
*/
zc_assert(facility, -187);
if (STRICMP(facility, ==, "LOG_LOCAL0")) return LOG_LOCAL0;
if (STRICMP(facility, ==, "LOG_LOCAL1")) return LOG_LOCAL1;
if (STRICMP(facility, ==, "LOG_LOCAL2")) return LOG_LOCAL2;
if (STRICMP(facility, ==, "LOG_LOCAL3")) return LOG_LOCAL3;
if (STRICMP(facility, ==, "LOG_LOCAL4")) return LOG_LOCAL4;
if (STRICMP(facility, ==, "LOG_LOCAL5")) return LOG_LOCAL5;
if (STRICMP(facility, ==, "LOG_LOCAL6")) return LOG_LOCAL6;
if (STRICMP(facility, ==, "LOG_LOCAL7")) return LOG_LOCAL7;
if (STRICMP(facility, ==, "LOG_USER")) return LOG_USER;
if (STRICMP(facility, ==, "LOG_AUTHPRIV")) return LOG_AUTHPRIV;
if (STRICMP(facility, ==, "LOG_CRON")) return LOG_CRON;
if (STRICMP(facility, ==, "LOG_DAEMON")) return LOG_DAEMON;
if (STRICMP(facility, ==, "LOG_FTP")) return LOG_FTP;
if (STRICMP(facility, ==, "LOG_KERN")) return LOG_KERN;
if (STRICMP(facility, ==, "LOG_LPR")) return LOG_LPR;
if (STRICMP(facility, ==, "LOG_MAIL")) return LOG_MAIL;
if (STRICMP(facility, ==, "LOG_NEWS")) return LOG_NEWS;
if (STRICMP(facility, ==, "LOG_SYSLOG")) return LOG_SYSLOG;
return LOG_AUTHPRIV;
#endif
zc_error("wrong syslog facility[%s], must in LOG_LOCAL[0-7] or LOG_USER", facility);
return -187;
}
static int zlog_rule_parse_path(char *path_start, /* start with a " */
char *path_str, size_t path_size, zc_arraylist_t **path_specs,
int *time_cache_count)
{
char *p, *q;
size_t len;
zlog_spec_t *a_spec;
zc_arraylist_t *specs;
p = path_start + 1;
q = strrchr(p, '"');
if (!q) {
zc_error("matching \" not found in conf line[%s]", path_start);
return -1;
}
len = q - p;
if (len > path_size - 1) {
zc_error("file_path too long %ld > %ld", len, path_size - 1);
return -1;
}
memcpy(path_str, p, len);
/* replace any environment variables like %E(HOME) */
if (zc_str_replace_env(path_str, path_size)) {
zc_error("zc_str_replace_env fail");
return -1;
}
if (strchr(path_str, '%') == NULL) {
/* static, no need create specs */
return 0;
}
specs = zc_arraylist_new((zc_arraylist_del_fn)zlog_spec_del);
if (!path_specs) {
zc_error("zc_arraylist_new fail");
return -1;
}
for (p = path_str; *p != '\0'; p = q) {
a_spec = zlog_spec_new(p, &q, time_cache_count);
if (!a_spec) {
zc_error("zlog_spec_new fail");
goto err;
}
if (zc_arraylist_add(specs, a_spec)) {
zc_error("zc_arraylist_add fail");
goto err;
}
}
*path_specs = specs;
return 0;
err:
if (specs) zc_arraylist_del(specs);
if (a_spec) zlog_spec_del(a_spec);
return -1;
}
zlog_rule_t *zlog_rule_new(char *line,
zc_arraylist_t *levels,
zlog_format_t * default_format,
zc_arraylist_t * formats,
unsigned int file_perms,
size_t fsync_period,
int * time_cache_count)
{
int rc = 0;
int nscan = 0;
int nread = 0;
zlog_rule_t *a_rule;
char selector[MAXLEN_CFG_LINE + 1];
char category[MAXLEN_CFG_LINE + 1];
char level[MAXLEN_CFG_LINE + 1];
char *action;
char output[MAXLEN_CFG_LINE + 1];
char format_name[MAXLEN_CFG_LINE + 1];
char file_path[MAXLEN_CFG_LINE + 1];
char archive_max_size[MAXLEN_CFG_LINE + 1];
char *file_limit;
char *p;
char *q;
size_t len;
zc_assert(line, NULL);
zc_assert(default_format, NULL);
zc_assert(formats, NULL);
a_rule = calloc(1, sizeof(zlog_rule_t));
if (!a_rule) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
a_rule->file_perms = file_perms;
a_rule->fsync_period = fsync_period;
/* line [f.INFO "%H/log/aa.log", 20MB * 12; MyTemplate]
* selector [f.INFO]
* *action ["%H/log/aa.log", 20MB * 12; MyTemplate]
*/
memset(&selector, 0x00, sizeof(selector));
nscan = sscanf(line, "%s %n", selector, &nread);
if (nscan != 1) {
zc_error("sscanf [%s] fail, selector", line);
goto err;
}
action = line + nread;
/*
* selector [f.INFO]
* category [f]
* level [.INFO]
*/
memset(category, 0x00, sizeof(category));
memset(level, 0x00, sizeof(level));
nscan = sscanf(selector, " %[^.].%s", category, level);
if (nscan != 2) {
zc_error("sscanf [%s] fail, category or level is null",
selector);
goto err;
}
/* check and set category */
for (p = category; *p != '\0'; p++) {
if ((!isalnum(*p)) && (*p != '_') && (*p != '-') && (*p != '*') && (*p != '!')) {
zc_error("category name[%s] character is not in [a-Z][0-9][_!*-]", category);
goto err;
}
}
/* as one line can't be longer than MAXLEN_CFG_LINE, same as category */
strcpy(a_rule->category, category);
/* check and set level */
switch (level[0]) {
case '=':
/* aa.=debug */
a_rule->compare_char = '=';
p = level + 1;
break;
case '!':
/* aa.!debug */
a_rule->compare_char = '!';
p = level + 1;
break;
case '*':
/* aa.* */
a_rule->compare_char = '*';
p = level;
break;
default:
/* aa.debug */
a_rule->compare_char = '.';
p = level;
break;
}
a_rule->level = zlog_level_list_atoi(levels, p);
/* level_bit is a bitmap represents which level can be output
* 32bytes, [0-255] levels, see level.c
* which bit field is 1 means allow output and 0 not
*/
switch (a_rule->compare_char) {
case '=':
memset(a_rule->level_bitmap, 0x00, sizeof(a_rule->level_bitmap));
a_rule->level_bitmap[a_rule->level / 8] |= (1 << (7 - a_rule->level % 8));
break;
case '!':
memset(a_rule->level_bitmap, 0xFF, sizeof(a_rule->level_bitmap));
a_rule->level_bitmap[a_rule->level / 8] &= ~(1 << (7 - a_rule->level % 8));
break;
case '*':
memset(a_rule->level_bitmap, 0xFF, sizeof(a_rule->level_bitmap));
break;
case '.':
memset(a_rule->level_bitmap, 0x00, sizeof(a_rule->level_bitmap));
a_rule->level_bitmap[a_rule->level / 8] |= ~(0xFF << (8 - a_rule->level % 8));
memset(a_rule->level_bitmap + a_rule->level / 8 + 1, 0xFF,
sizeof(a_rule->level_bitmap) - a_rule->level / 8 - 1);
break;
}
/* action ["%H/log/aa.log", 20MB * 12 ; MyTemplate]
* output ["%H/log/aa.log", 20MB * 12]
* format [MyTemplate]
*/
memset(output, 0x00, sizeof(output));
memset(format_name, 0x00, sizeof(format_name));
nscan = sscanf(action, " %[^;];%s", output, format_name);
if (nscan < 1) {
zc_error("sscanf [%s] fail", action);
goto err;
}
/* check and get format */
if (STRCMP(format_name, ==, "")) {
zc_debug("no format specified, use default");
a_rule->format = default_format;
} else {
int i;
int find_flag = 0;
zlog_format_t *a_format;
zc_arraylist_foreach(formats, i, a_format) {
if (zlog_format_has_name(a_format, format_name)) {
a_rule->format = a_format;
find_flag = 1;
break;
}
}
if (!find_flag) {
zc_error("in conf file can't find format[%s], pls check",
format_name);
goto err;
}
}
/* output [-"%E(HOME)/log/aa.log" , 20MB*12] [>syslog , LOG_LOCAL0 ]
* file_path [-"%E(HOME)/log/aa.log" ] [>syslog ]
* *file_limit [20MB * 12 ~ "aa.#i.log" ] [LOG_LOCAL0]
*/
memset(file_path, 0x00, sizeof(file_path));
nscan = sscanf(output, " %[^,],", file_path);
if (nscan < 1) {
zc_error("sscanf [%s] fail", action);
goto err;
}
file_limit = strchr(output, ',');
if (file_limit) {
file_limit++; /* skip the , */
while( isspace(*file_limit) ) {
file_limit++;
}
}
p = NULL;
switch (file_path[0]) {
case '-' :
/* sync file each time write log */
if (file_path[1] != '"') {
zc_error(" - must set before a file output");
goto err;
}
/* no need to fsync, as file is opened by O_SYNC, write immediately */
a_rule->fsync_period = 0;
p = file_path + 1;
#ifndef _WIN32
a_rule->file_open_flags = O_SYNC;
/* fall through */
#endif
case '"' :
if (!p) p = file_path;
rc = zlog_rule_parse_path(p, a_rule->file_path, sizeof(a_rule->file_path),
&(a_rule->dynamic_specs), time_cache_count);
if (rc) {
zc_error("zlog_rule_parse_path fail");
goto err;
}
if (file_limit) {
memset(archive_max_size, 0x00, sizeof(archive_max_size));
nscan = sscanf(file_limit, " %[0-9GgMmKkBb] * %d ~",
archive_max_size, &(a_rule->archive_max_count));
if (nscan) {
a_rule->archive_max_size = zc_parse_byte_size(archive_max_size);
}
p = strchr(file_limit, '"');
if (p) { /* archive file path exist */
rc = zlog_rule_parse_path(p,
a_rule->archive_path, sizeof(a_rule->file_path),
&(a_rule->archive_specs), time_cache_count);
if (rc) {
zc_error("zlog_rule_parse_path fail");
goto err;
}
p = strchr(a_rule->archive_path, '#');
if ( (p == NULL) || ((strchr(p, 'r') == NULL) && (strchr(p, 's') == NULL))) {
zc_error("archive_path must contain #r or #s");
goto err;
}
}
}
/* try to figure out if the log file path is dynamic or static */
if (a_rule->dynamic_specs) {
if (a_rule->archive_max_size <= 0) {
a_rule->output = zlog_rule_output_dynamic_file_single;
} else {
a_rule->output = zlog_rule_output_dynamic_file_rotate;
}
} else {
struct stat stb;
if (a_rule->archive_max_size <= 0) {
a_rule->output = zlog_rule_output_static_file_single;
} else {
/* as rotate, so need to reopen everytime */
a_rule->output = zlog_rule_output_static_file_rotate;
}
a_rule->static_fd = open(a_rule->file_path,
O_WRONLY | O_APPEND | O_CREAT | a_rule->file_open_flags,
a_rule->file_perms);
if (a_rule->static_fd < 0) {
zc_error("open file[%s] fail, errno[%d]", a_rule->file_path, errno);
goto err;
}
/* save off the inode information for checking for a changed file later on */
if (fstat(a_rule->static_fd, &stb)) {
zc_error("stat [%s] fail, errno[%d], failing to open static_fd", a_rule->file_path, errno);
goto err;
}
if (a_rule->archive_max_size > 0) {
close(a_rule->static_fd);
a_rule->static_fd = -1;
}
a_rule->static_dev = stb.st_dev;
a_rule->static_ino = stb.st_ino;
}
break;
case '|' :
a_rule->pipe_fp = popen(output + 1, "w");
if (!a_rule->pipe_fp) {
zc_error("popen fail, errno[%d]", errno);
goto err;
}
a_rule->pipe_fd = fileno(a_rule->pipe_fp);
if (a_rule->pipe_fd < 0 ) {
zc_error("fileno fail, errno[%d]", errno);
goto err;
}
a_rule->output = zlog_rule_output_pipe;
break;
case '>' :
if (STRNCMP(file_path + 1, ==, "syslog", 6)) {
a_rule->syslog_facility = syslog_facility_atoi(file_limit);
#ifdef _WIN32
zc_error("syslog not support under windows!");
#else
if (a_rule->syslog_facility == -187) {
zc_error("-187 get");
goto err;
}
a_rule->output = zlog_rule_output_syslog;
openlog(NULL, LOG_NDELAY | LOG_NOWAIT | LOG_PID, LOG_USER);
#endif
} else if (STRNCMP(file_path + 1, ==, "stdout", 6)) {
a_rule->output = zlog_rule_output_stdout;
} else if (STRNCMP(file_path + 1, ==, "stderr", 6)) {
a_rule->output = zlog_rule_output_stderr;
} else {
zc_error
("[%s]the string after is not syslog, stdout or stderr", output);
goto err;
}
break;
case '$' :
// read only MAXLEN_PATH characters from the file_path + 1
strncpy(a_rule->record_name, file_path + 1, MAXLEN_PATH);
a_rule->record_name[MAXLEN_PATH] = '\0';
if (file_limit) { /* record path exists */
p = strchr(file_limit, '"');
if (!p) {
zc_error("record_path not start with \", [%s]", file_limit);
goto err;
}
p++; /* skip 1st " */
q = strrchr(p, '"');
if (!q) {
zc_error("matching \" not found in conf line[%s]", p);
goto err;
}
len = q - p;
if (len > sizeof(a_rule->record_path) - 1) {
zc_error("record_path too long %ld > %ld", len, sizeof(a_rule->record_path) - 1);
goto err;
}
memcpy(a_rule->record_path, p, len);
}
/* replace any environment variables like %E(HOME) */
rc = zc_str_replace_env(a_rule->record_path, sizeof(a_rule->record_path));
if (rc) {
zc_error("zc_str_replace_env fail");
goto err;
}
/* try to figure out if the log file path is dynamic or static */
if (strchr(a_rule->record_path, '%') == NULL) {
a_rule->output = zlog_rule_output_static_record;
} else {
zlog_spec_t *a_spec;
a_rule->output = zlog_rule_output_dynamic_record;
a_rule->dynamic_specs = zc_arraylist_new((zc_arraylist_del_fn)zlog_spec_del);
if (!(a_rule->dynamic_specs)) {
zc_error("zc_arraylist_new fail");
goto err;
}
for (p = a_rule->record_path; *p != '\0'; p = q) {
a_spec = zlog_spec_new(p, &q, time_cache_count);
if (!a_spec) {
zc_error("zlog_spec_new fail");
goto err;
}
rc = zc_arraylist_add(a_rule->dynamic_specs, a_spec);
if (rc) {
zlog_spec_del(a_spec);
zc_error("zc_arraylist_add fail");
goto err;
}
}
}
break;
default :
zc_error("the 1st char[%c] of file_path[%s] is wrong",
file_path[0], file_path);
goto err;
}
return a_rule;
err:
zlog_rule_del(a_rule);
return NULL;
}
void zlog_rule_del(zlog_rule_t * a_rule)
{
zc_assert(a_rule,);
if (a_rule->dynamic_specs) {
zc_arraylist_del(a_rule->dynamic_specs);
a_rule->dynamic_specs = NULL;
}
if (a_rule->static_fd > 0) {
if (close(a_rule->static_fd)) {
zc_error("close fail, maybe cause by write, errno[%d]", errno);
}
}
#ifndef _WIN32
if (a_rule->pipe_fp) {
if (pclose(a_rule->pipe_fp) == -1) {
zc_error("pclose fail, errno[%d]", errno);
}
}
#endif
if (a_rule->archive_specs) {
zc_arraylist_del(a_rule->archive_specs);
a_rule->archive_specs = NULL;
}
zc_debug("zlog_rule_del[%p]", a_rule);
free(a_rule);
return;
}
/*******************************************************************************/
int zlog_rule_output(zlog_rule_t * a_rule, zlog_thread_t * a_thread)
{
switch (a_rule->compare_char) {
case '*' :
return a_rule->output(a_rule, a_thread);
break;
case '.' :
if (a_thread->event->level >= a_rule->level) {
return a_rule->output(a_rule, a_thread);
} else {
return 0;
}
break;
case '=' :
if (a_thread->event->level == a_rule->level) {
return a_rule->output(a_rule, a_thread);
} else {
return 0;
}
break;
case '!' :
if (a_thread->event->level != a_rule->level) {
return a_rule->output(a_rule, a_thread);
} else {
return 0;
}
break;
}
return 0;
}
/*******************************************************************************/
int zlog_rule_is_wastebin(zlog_rule_t * a_rule)
{
zc_assert(a_rule, -1);
if (STRCMP(a_rule->category, ==, "!")) {
return 1;
}
return 0;
}
/*******************************************************************************/
int zlog_rule_match_category(zlog_rule_t * a_rule, char *category)
{
zc_assert(a_rule, -1);
zc_assert(category, -1);
if (STRCMP(a_rule->category, ==, "*")) {
/* '*' match anything, so go on */
return 1;
} else if (STRCMP(a_rule->category, ==, category)) {
/* accurate compare */
return 1;
} else {
/* aa_ match aa_xx & aa, but not match aa1_xx */
size_t len;
len = strlen(a_rule->category);
if (a_rule->category[len - 1] == '_') {
if (strlen(category) == len - 1) {
len--;
}
if (STRNCMP(a_rule->category, ==, category, len)) {
return 1;
}
}
}
return 0;
}
/*******************************************************************************/
int zlog_rule_set_record(zlog_rule_t * a_rule, zc_hashtable_t *records)
{
zlog_record_t *a_record;
if (a_rule->output != zlog_rule_output_static_record
&& a_rule->output != zlog_rule_output_dynamic_record) {
return 0; /* fliter, may go through not record rule */
}
a_record = zc_hashtable_get(records, a_rule->record_name);
if (a_record) {
a_rule->record_func = a_record->output;
}
return 0;
}
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file rule.h
* @brief rule decide to output in format by category & level
*/
#ifndef __zlog_rule_h
#define __zlog_rule_h
#include <stdio.h>
#include <pthread.h>
#include "zc_defs.h"
#include "format.h"
#include "thread.h"
#include "rotater.h"
#include "record.h"
typedef struct zlog_rule_s zlog_rule_t;
typedef int (*zlog_rule_output_fn) (zlog_rule_t * a_rule, zlog_thread_t * a_thread);
struct zlog_rule_s {
char category[MAXLEN_CFG_LINE + 1];
char compare_char;
/*
* [*] log all level
* [.] log level >= rule level, default
* [=] log level == rule level
* [!] log level != rule level
*/
int level;
unsigned char level_bitmap[32]; /* for category determine whether output or not */
unsigned int file_perms;
int file_open_flags;
char file_path[MAXLEN_PATH + 1];
zc_arraylist_t *dynamic_specs;
int static_fd;
dev_t static_dev;
ino_t static_ino;
long archive_max_size;
int archive_max_count;
char archive_path[MAXLEN_PATH + 1];
zc_arraylist_t *archive_specs;
FILE *pipe_fp;
int pipe_fd;
size_t fsync_period;
size_t fsync_count;
zc_arraylist_t *levels;
int syslog_facility;
zlog_format_t *format;
zlog_rule_output_fn output;
char record_name[MAXLEN_PATH + 1];
char record_path[MAXLEN_PATH + 1];
zlog_record_fn record_func;
};
zlog_rule_t *zlog_rule_new(char * line,
zc_arraylist_t * levels,
zlog_format_t * default_format,
zc_arraylist_t * formats,
unsigned int file_perms,
size_t fsync_period,
int * time_cache_count);
void zlog_rule_del(zlog_rule_t * a_rule);
void zlog_rule_profile(zlog_rule_t * a_rule, int flag);
int zlog_rule_match_category(zlog_rule_t * a_rule, char *category);
int zlog_rule_is_wastebin(zlog_rule_t * a_rule);
int zlog_rule_set_record(zlog_rule_t * a_rule, zc_hashtable_t *records);
int zlog_rule_output(zlog_rule_t * a_rule, zlog_thread_t * a_thread);
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fmacros.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include "conf.h"
#include "spec.h"
#include "level_list.h"
#include "zc_defs.h"
#ifdef _WIN32
#define ZLOG_DEFAULT_TIME_FMT "%Y-%m-%d %H:%M:%S"
#else
#define ZLOG_DEFAULT_TIME_FMT "%F %T"
#endif
#define ZLOG_HEX_HEAD \
"\n 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF"
/*******************************************************************************/
void zlog_spec_profile(zlog_spec_t * a_spec, int flag)
{
zc_assert(a_spec,);
zc_profile(flag, "----spec[%p][%.*s][%s|%d][%s,%ld,%ld,%s][%s]----",
a_spec,
a_spec->len, a_spec->str,
a_spec->time_fmt,
a_spec->time_cache_index,
a_spec->print_fmt, (long)a_spec->max_width, (long)a_spec->min_width, a_spec->left_fill_zeros ? "true" : "false",
a_spec->mdc_key);
return;
}
/*******************************************************************************/
/* implementation of write function */
static int zlog_spec_write_time_internal(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf, short use_utc)
{
zlog_time_cache_t * a_cache = a_thread->event->time_caches + a_spec->time_cache_index;
time_t now_sec = a_thread->event->time_stamp.tv_sec;
struct tm *time;
time_t *time_sec;
typedef struct tm *(*zlog_spec_time_fn) (const time_t*, struct tm *);
zlog_spec_time_fn time_stamp_convert_function;
if( use_utc ) {
time = &(a_thread->event->time_utc);
time_sec = &(a_thread->event->time_utc_sec);
time_stamp_convert_function = gmtime_r;
} else {
time = &(a_thread->event->time_local);
time_sec = &(a_thread->event->time_local_sec);
time_stamp_convert_function = localtime_r;
}
/* the event meet the 1st time_spec in his life cycle */
if (!now_sec) {
gettimeofday(&(a_thread->event->time_stamp), NULL);
now_sec = a_thread->event->time_stamp.tv_sec;
}
/* When this event's last cached time_local is not now */
if (*time_sec != now_sec) {
time_stamp_convert_function(&(now_sec), time);
*time_sec = now_sec;
}
/* When this spec's last cache time string is not now */
if (a_cache->sec != now_sec) {
a_cache->len = strftime(a_cache->str, sizeof(a_cache->str), a_spec->time_fmt, time);
a_cache->sec = now_sec;
}
return zlog_buf_append(a_buf, a_cache->str, a_cache->len);
}
static int zlog_spec_write_time_UTC(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
return zlog_spec_write_time_internal(a_spec, a_thread, a_buf, 1);
}
static int zlog_spec_write_time_local(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
return zlog_spec_write_time_internal(a_spec, a_thread, a_buf, 0);
}
#if 0
static int zlog_spec_write_time_D(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
if (!a_thread->event->time_stamp.tv_sec) {
gettimeofday(&(a_thread->event->time_stamp), NULL);
}
/*
* It is modified when time slips one second.
* So it is a strong cache, as Default time format is always %F %T.
* That's why I said %D is faster than %d()
*/
if (a_thread->event->time_stamp.tv_sec != a_thread->event->time_last_D) {
a_thread->event->time_last_D = a_thread->event->time_stamp.tv_sec;
localtime_r(&(a_thread->event->time_stamp.tv_sec),
&(a_thread->event->time_local));
strftime(a_thread->event->time_cache_D,
sizeof(a_thread->event->time_cache_D),
ZLOG_DEFAULT_TIME_FMT, &(a_thread->event->time_local) );
}
return zlog_buf_append(a_buf, a_thread->event->time_cache_D, sizeof(a_thread->event->time_cache_D) - 1);
}
#endif
static int zlog_spec_write_ms(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
if (!a_thread->event->time_stamp.tv_sec) {
gettimeofday(&(a_thread->event->time_stamp), NULL);
}
return zlog_buf_printf_dec32(a_buf, (a_thread->event->time_stamp.tv_usec / 1000), 3);
}
static int zlog_spec_write_us(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
if (!a_thread->event->time_stamp.tv_sec) {
gettimeofday(&(a_thread->event->time_stamp), NULL);
}
return zlog_buf_printf_dec32(a_buf, a_thread->event->time_stamp.tv_usec, 6);
}
static int zlog_spec_write_mdc(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
zlog_mdc_kv_t *a_mdc_kv;
a_mdc_kv = zlog_mdc_get_kv(a_thread->mdc, a_spec->mdc_key);
if (!a_mdc_kv) {
zc_error("zlog_mdc_get_kv key[%s] fail", a_spec->mdc_key);
return 0;
}
return zlog_buf_append(a_buf, a_mdc_kv->value, a_mdc_kv->value_len);
}
static int zlog_spec_write_str(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
return zlog_buf_append(a_buf, a_spec->str, a_spec->len);
}
static int zlog_spec_write_category(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
return zlog_buf_append(a_buf, a_thread->event->category_name, a_thread->event->category_name_len);
}
static int zlog_spec_write_srcfile(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
if (!a_thread->event->file) {
return zlog_buf_append(a_buf, "(file=null)", sizeof("(file=null)") - 1);
} else {
return zlog_buf_append(a_buf, a_thread->event->file, a_thread->event->file_len);
}
}
static int zlog_spec_write_srcfile_neat(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
char *p;
if ((p = strrchr(a_thread->event->file, '/')) != NULL) {
return zlog_buf_append(a_buf, p + 1,
(char*)a_thread->event->file + a_thread->event->file_len - p - 1);
} else {
if (!a_thread->event->file) {
return zlog_buf_append(a_buf, "(file=null)", sizeof("(file=null)") - 1);
} else {
return zlog_buf_append(a_buf, a_thread->event->file, a_thread->event->file_len);
}
}
}
static int zlog_spec_write_srcline(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
return zlog_buf_printf_dec64(a_buf, a_thread->event->line, 0);
}
static int zlog_spec_write_srcfunc(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
if (!a_thread->event->file) {
return zlog_buf_append(a_buf, "(func=null)", sizeof("(func=null)") - 1);
} else {
return zlog_buf_append(a_buf, a_thread->event->func, a_thread->event->func_len);
}
}
static int zlog_spec_write_hostname(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
return zlog_buf_append(a_buf, a_thread->event->host_name, a_thread->event->host_name_len);
}
static int zlog_spec_write_newline(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
return zlog_buf_append(a_buf, FILE_NEWLINE, FILE_NEWLINE_LEN);
}
static int zlog_spec_write_cr(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
return zlog_buf_append(a_buf, "\r", 1);
}
static int zlog_spec_write_percent(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
return zlog_buf_append(a_buf, "%", 1);
}
static int zlog_spec_write_pid(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
/* 1st in event lifecycle */
if (!a_thread->event->pid) {
a_thread->event->pid = getpid();
/* compare with previous event */
if (a_thread->event->pid != a_thread->event->last_pid) {
a_thread->event->last_pid = a_thread->event->pid;
a_thread->event->pid_str_len
= sprintf(a_thread->event->pid_str, "%u", a_thread->event->pid);
}
}
return zlog_buf_append(a_buf, a_thread->event->pid_str, a_thread->event->pid_str_len);
}
static int zlog_spec_write_tid_hex(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
/* don't need to get tid again, as tmap_new_thread fetched it already */
/* and fork not change tid */
return zlog_buf_append(a_buf, a_thread->event->tid_hex_str, a_thread->event->tid_hex_str_len);
}
static int zlog_spec_write_tid_long(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
/* don't need to get tid again, as tmap_new_thread fetched it already */
/* and fork not change tid */
return zlog_buf_append(a_buf, a_thread->event->tid_str, a_thread->event->tid_str_len);
}
static int zlog_spec_write_ktid(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
/* don't need to get ktid again, as tmap_new_thread fetched it already */
/* and fork not change tid */
return zlog_buf_append(a_buf, a_thread->event->ktid_str, a_thread->event->ktid_str_len);
}
static int zlog_spec_write_level_lowercase(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
zlog_level_t *a_level;
a_level = zlog_level_list_get(zlog_env_conf->levels, a_thread->event->level);
return zlog_buf_append(a_buf, a_level->str_lowercase, a_level->str_len);
}
static int zlog_spec_write_level_uppercase(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
zlog_level_t *a_level;
a_level = zlog_level_list_get(zlog_env_conf->levels, a_thread->event->level);
return zlog_buf_append(a_buf, a_level->str_uppercase, a_level->str_len);
}
static int zlog_spec_write_usrmsg(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf)
{
if (a_thread->event->generate_cmd == ZLOG_FMT) {
if (a_thread->event->str_format) {
return zlog_buf_vprintf(a_buf,
a_thread->event->str_format,
a_thread->event->str_args);
} else {
return zlog_buf_append(a_buf, "format=(null)", sizeof("format=(null)")-1);
}
} else if (a_thread->event->generate_cmd == ZLOG_HEX) {
int rc;
long line_offset;
long byte_offset;
/* thread buf start == null or len <= 0 */
if (a_thread->event->hex_buf == NULL) {
rc = zlog_buf_append(a_buf, "buf=(null)", sizeof("buf=(null)")-1);
goto zlog_hex_exit;
}
rc = zlog_buf_append(a_buf, ZLOG_HEX_HEAD, sizeof(ZLOG_HEX_HEAD)-1);
if (rc) {
goto zlog_hex_exit;
}
line_offset = 0;
//byte_offset = 0;
while (1) {
unsigned char c;
rc = zlog_buf_append(a_buf, "\n", 1);
if (rc) goto zlog_hex_exit;
rc = zlog_buf_printf_dec64(a_buf, line_offset + 1, 10);
if (rc) goto zlog_hex_exit;
rc = zlog_buf_append(a_buf, " ", 3);
if (rc) goto zlog_hex_exit;
for (byte_offset = 0; byte_offset < 16; byte_offset++) {
if (line_offset * 16 + byte_offset < a_thread->event->hex_buf_len) {
c = *((unsigned char *)a_thread->event->hex_buf
+ line_offset * 16 + byte_offset);
rc = zlog_buf_printf_hex(a_buf, c, 2);
if (rc) goto zlog_hex_exit;
rc = zlog_buf_append(a_buf, " ", 1);
if (rc) goto zlog_hex_exit;
} else {
rc = zlog_buf_append(a_buf, " ", 3);
if (rc) goto zlog_hex_exit;
}
}
rc = zlog_buf_append(a_buf, " ", 2);
if (rc) goto zlog_hex_exit;
for (byte_offset = 0; byte_offset < 16; byte_offset++) {
if (line_offset * 16 + byte_offset < a_thread->event->hex_buf_len) {
c = *((unsigned char *)a_thread->event->hex_buf
+ line_offset * 16 + byte_offset);
if (c >= 32 && c <= 126) {
rc = zlog_buf_append(a_buf,(char*)&c, 1);
if (rc) goto zlog_hex_exit;
} else {
rc = zlog_buf_append(a_buf, ".", 1);
if (rc) goto zlog_hex_exit;
}
} else {
rc = zlog_buf_append(a_buf, " ", 1);
if (rc) goto zlog_hex_exit;
}
}
if (line_offset * 16 + byte_offset >= a_thread->event->hex_buf_len) {
break;
}
line_offset++;
}
zlog_hex_exit:
if (rc < 0) {
zc_error("write hex msg fail");
return -1;
} else if (rc > 0) {
zc_error("write hex msg, buf is full");
return 1;
}
return 0;
}
return 0;
}
/*******************************************************************************/
/* implementation of gen function */
static int zlog_spec_gen_msg_direct(zlog_spec_t * a_spec, zlog_thread_t * a_thread)
{
/* no need to reprint %1.2d here */
return a_spec->write_buf(a_spec, a_thread, a_thread->msg_buf);
}
static int zlog_spec_gen_msg_reformat(zlog_spec_t * a_spec, zlog_thread_t * a_thread)
{
int rc;
zlog_buf_restart(a_thread->pre_msg_buf);
rc = a_spec->write_buf(a_spec, a_thread, a_thread->pre_msg_buf);
if (rc < 0) {
zc_error("a_spec->gen_buf fail");
return -1;
} else if (rc > 0) {
/* buf is full, try printf */
}
return zlog_buf_adjust_append(a_thread->msg_buf,
zlog_buf_str(a_thread->pre_msg_buf), zlog_buf_len(a_thread->pre_msg_buf),
a_spec->left_adjust, a_spec->left_fill_zeros, a_spec->min_width, a_spec->max_width);
}
/*******************************************************************************/
static int zlog_spec_gen_path_direct(zlog_spec_t * a_spec, zlog_thread_t * a_thread)
{
/* no need to reprint %1.2d here */
return a_spec->write_buf(a_spec, a_thread, a_thread->path_buf);
}
static int zlog_spec_gen_path_reformat(zlog_spec_t * a_spec, zlog_thread_t * a_thread)
{
int rc;
zlog_buf_restart(a_thread->pre_path_buf);
rc = a_spec->write_buf(a_spec, a_thread, a_thread->pre_path_buf);
if (rc < 0) {
zc_error("a_spec->gen_buf fail");
return -1;
} else if (rc > 0) {
/* buf is full, try printf */
}
return zlog_buf_adjust_append(a_thread->path_buf,
zlog_buf_str(a_thread->pre_path_buf), zlog_buf_len(a_thread->pre_path_buf),
a_spec->left_adjust, a_spec->left_fill_zeros, a_spec->min_width, a_spec->max_width);
}
/*******************************************************************************/
static int zlog_spec_gen_archive_path_direct(zlog_spec_t * a_spec, zlog_thread_t * a_thread)
{
/* no need to reprint %1.2d here */
return a_spec->write_buf(a_spec, a_thread, a_thread->archive_path_buf);
}
static int zlog_spec_gen_archive_path_reformat(zlog_spec_t * a_spec, zlog_thread_t * a_thread)
{
int rc;
zlog_buf_restart(a_thread->pre_path_buf);
rc = a_spec->write_buf(a_spec, a_thread, a_thread->pre_path_buf);
if (rc < 0) {
zc_error("a_spec->gen_buf fail");
return -1;
} else if (rc > 0) {
/* buf is full, try printf */
}
return zlog_buf_adjust_append(a_thread->archive_path_buf,
zlog_buf_str(a_thread->pre_path_buf), zlog_buf_len(a_thread->pre_path_buf),
a_spec->left_adjust, a_spec->left_fill_zeros, a_spec->min_width, a_spec->max_width);
}
/*******************************************************************************/
static int zlog_spec_parse_print_fmt(zlog_spec_t * a_spec)
{
/* -12.35 12 .35 */
char *p, *q;
long i, j;
p = a_spec->print_fmt;
if (*p == '-') {
a_spec->left_adjust = 1;
p++;
} else {
if (*p == '0') {
a_spec->left_fill_zeros = 1;
}
a_spec->left_adjust = 0;
}
i = j = 0;
sscanf(p, "%ld.", &i);
q = strchr(p, '.');
if (q) sscanf(q, ".%ld", &j);
a_spec->min_width = (size_t) i;
a_spec->max_width = (size_t) j;
return 0;
}
/*******************************************************************************/
void zlog_spec_del(zlog_spec_t * a_spec)
{
zc_assert(a_spec,);
zc_debug("zlog_spec_del[%p]", a_spec);
free(a_spec);
}
/* a spec may consist of
* a const string: /home/bb
* a string begin with %: %12.35d(%F %X,%l)
*/
zlog_spec_t *zlog_spec_new(char *pattern_start, char **pattern_next, int *time_cache_count)
{
char *p;
int nscan = 0;
int nread = 0;
zlog_spec_t *a_spec;
zc_assert(pattern_start, NULL);
zc_assert(pattern_next, NULL);
a_spec = calloc(1, sizeof(zlog_spec_t));
if (!a_spec) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
a_spec->str = p = pattern_start;
switch (*p) {
case '%':
/* a string begin with %: %12.35d(%F %X) */
/* process width and precision char in %-12.35P */
nread = 0;
nscan = sscanf(p, "%%%[.0-9-]%n", a_spec->print_fmt, &nread);
if (nscan == 1) {
a_spec->gen_msg = zlog_spec_gen_msg_reformat;
a_spec->gen_path = zlog_spec_gen_path_reformat;
a_spec->gen_archive_path = zlog_spec_gen_archive_path_reformat;
if (zlog_spec_parse_print_fmt(a_spec)) {
zc_error("zlog_spec_parse_print_fmt fail");
goto err;
}
} else {
nread = 1; /* skip the % char */
a_spec->gen_msg = zlog_spec_gen_msg_direct;
a_spec->gen_path = zlog_spec_gen_path_direct;
a_spec->gen_archive_path = zlog_spec_gen_archive_path_direct;
}
p += nread;
if (*p == 'd' || *p == 'g') {
short use_utc = *p == 'g';
if (*(p+1) != '(') {
/* without '(' , use default */
strcpy(a_spec->time_fmt, ZLOG_DEFAULT_TIME_FMT);
p++;
} else if (STRNCMP(p, ==, "d()", 3)) {
/* with () but without detail time format,
* keep a_spec->time_fmt=="" */
strcpy(a_spec->time_fmt, ZLOG_DEFAULT_TIME_FMT);
p += 3;
} else {
nread = 0;
p++;
nscan = sscanf(p, "(%[^)])%n", a_spec->time_fmt, &nread);
if (nscan != 1) {
nread = 0;
}
p += nread;
if (*(p - 1) != ')') {
zc_error("in string[%s] can't find match \')\'", a_spec->str);
goto err;
}
}
a_spec->time_cache_index = *time_cache_count;
(*time_cache_count)++;
if (use_utc) {
a_spec->write_buf = zlog_spec_write_time_UTC;
} else {
a_spec->write_buf = zlog_spec_write_time_local;
}
*pattern_next = p;
a_spec->len = p - a_spec->str;
break;
}
if (*p == 'M') {
nread = 0;
nscan = sscanf(p, "M(%[^)])%n", a_spec->mdc_key, &nread);
if (nscan != 1) {
nread = 0;
if (STRNCMP(p, ==, "M()", 3)) {
nread = 3;
}
}
p += nread;
if (*(p - 1) != ')') {
zc_error("in string[%s] can't find match \')\'", a_spec->str);
goto err;
}
*pattern_next = p;
a_spec->len = p - a_spec->str;
a_spec->write_buf = zlog_spec_write_mdc;
break;
}
if (STRNCMP(p, ==, "ms", 2)) {
p += 2;
*pattern_next = p;
a_spec->len = p - a_spec->str;
a_spec->write_buf = zlog_spec_write_ms;
break;
} else if (STRNCMP(p, ==, "us", 2)) {
p += 2;
*pattern_next = p;
a_spec->len = p - a_spec->str;
a_spec->write_buf = zlog_spec_write_us;
break;
}
*pattern_next = p + 1;
a_spec->len = p - a_spec->str + 1;
switch (*p) {
case 'c':
a_spec->write_buf = zlog_spec_write_category;
break;
case 'D':
strcpy(a_spec->time_fmt, ZLOG_DEFAULT_TIME_FMT);
a_spec->time_cache_index = *time_cache_count;
(*time_cache_count)++;
a_spec->write_buf = zlog_spec_write_time_local;
break;
case 'F':
a_spec->write_buf = zlog_spec_write_srcfile;
break;
case 'f':
a_spec->write_buf = zlog_spec_write_srcfile_neat;
break;
case 'G':
strcpy(a_spec->time_fmt, ZLOG_DEFAULT_TIME_FMT);
a_spec->time_cache_index = *time_cache_count;
(*time_cache_count)++;
a_spec->write_buf = zlog_spec_write_time_UTC;
break;
case 'H':
a_spec->write_buf = zlog_spec_write_hostname;
break;
case 'k':
a_spec->write_buf = zlog_spec_write_ktid;
break;
case 'L':
a_spec->write_buf = zlog_spec_write_srcline;
break;
case 'm':
a_spec->write_buf = zlog_spec_write_usrmsg;
break;
case 'n':
a_spec->write_buf = zlog_spec_write_newline;
break;
case 'r':
a_spec->write_buf = zlog_spec_write_cr;
break;
case 'p':
a_spec->write_buf = zlog_spec_write_pid;
break;
case 'U':
a_spec->write_buf = zlog_spec_write_srcfunc;
break;
case 'v':
a_spec->write_buf = zlog_spec_write_level_lowercase;
break;
case 'V':
a_spec->write_buf = zlog_spec_write_level_uppercase;
break;
case 't':
a_spec->write_buf = zlog_spec_write_tid_hex;
break;
case 'T':
a_spec->write_buf = zlog_spec_write_tid_long;
break;
case '%':
a_spec->write_buf = zlog_spec_write_percent;
break;
default:
zc_error("str[%s] in wrong format, p[%c]", a_spec->str, *p);
goto err;
}
break;
default:
/* a const string: /home/bb */
*pattern_next = strchr(p, '%');
if (*pattern_next) {
a_spec->len = *pattern_next - p;
} else {
a_spec->len = strlen(p);
*pattern_next = p + a_spec->len;
}
a_spec->write_buf = zlog_spec_write_str;
a_spec->gen_msg = zlog_spec_gen_msg_direct;
a_spec->gen_path = zlog_spec_gen_path_direct;
a_spec->gen_archive_path = zlog_spec_gen_archive_path_direct;
}
zlog_spec_profile(a_spec, ZC_DEBUG);
return a_spec;
err:
zlog_spec_del(a_spec);
return NULL;
}
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_spec_h
#define __zlog_spec_h
#include "event.h"
#include "buf.h"
#include "thread.h"
typedef struct zlog_spec_s zlog_spec_t;
/* write buf, according to each spec's Conversion Characters */
typedef int (*zlog_spec_write_fn) (zlog_spec_t * a_spec,
zlog_thread_t * a_thread,
zlog_buf_t * a_buf);
/* gen a_thread->msg or gen a_thread->path by using write_fn */
typedef int (*zlog_spec_gen_fn) (zlog_spec_t * a_spec,
zlog_thread_t * a_thread);
struct zlog_spec_s {
char *str;
int len;
char time_fmt[MAXLEN_CFG_LINE + 1];
int time_cache_index;
char mdc_key[MAXLEN_PATH + 1];
char print_fmt[MAXLEN_CFG_LINE + 1];
int left_adjust;
int left_fill_zeros;
size_t max_width;
size_t min_width;
zlog_spec_write_fn write_buf;
zlog_spec_gen_fn gen_msg;
zlog_spec_gen_fn gen_path;
zlog_spec_gen_fn gen_archive_path;
};
zlog_spec_t *zlog_spec_new(char *pattern_start, char **pattern_end, int * time_cache_count);
void zlog_spec_del(zlog_spec_t * a_spec);
void zlog_spec_profile(zlog_spec_t * a_spec, int flag);
#define zlog_spec_gen_msg(a_spec, a_thread) \
a_spec->gen_msg(a_spec, a_thread)
#define zlog_spec_gen_path(a_spec, a_thread) \
a_spec->gen_path(a_spec, a_thread)
#define zlog_spec_gen_archive_path(a_spec, a_thread) \
a_spec->gen_archive_path(a_spec, a_thread)
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <pthread.h>
#include <errno.h>
#include "zc_defs.h"
#include "event.h"
#include "buf.h"
#include "thread.h"
#include "mdc.h"
void zlog_thread_profile(zlog_thread_t * a_thread, int flag)
{
zc_assert(a_thread,);
zc_profile(flag, "--thread[%p][%p][%p][%p,%p,%p,%p,%p]--",
a_thread,
a_thread->mdc,
a_thread->event,
a_thread->pre_path_buf,
a_thread->path_buf,
a_thread->archive_path_buf,
a_thread->pre_msg_buf,
a_thread->msg_buf);
zlog_mdc_profile(a_thread->mdc, flag);
zlog_event_profile(a_thread->event, flag);
zlog_buf_profile(a_thread->pre_path_buf, flag);
zlog_buf_profile(a_thread->path_buf, flag);
zlog_buf_profile(a_thread->archive_path_buf, flag);
zlog_buf_profile(a_thread->pre_msg_buf, flag);
zlog_buf_profile(a_thread->msg_buf, flag);
return;
}
/*******************************************************************************/
void zlog_thread_del(zlog_thread_t * a_thread)
{
zc_assert(a_thread,);
if (a_thread->mdc)
zlog_mdc_del(a_thread->mdc);
if (a_thread->event)
zlog_event_del(a_thread->event);
if (a_thread->pre_path_buf)
zlog_buf_del(a_thread->pre_path_buf);
if (a_thread->path_buf)
zlog_buf_del(a_thread->path_buf);
if (a_thread->archive_path_buf)
zlog_buf_del(a_thread->archive_path_buf);
if (a_thread->pre_msg_buf)
zlog_buf_del(a_thread->pre_msg_buf);
if (a_thread->msg_buf)
zlog_buf_del(a_thread->msg_buf);
zc_debug("zlog_thread_del[%p]", a_thread);
free(a_thread);
return;
}
zlog_thread_t *zlog_thread_new(int init_version, size_t buf_size_min, size_t buf_size_max, int time_cache_count)
{
zlog_thread_t *a_thread;
a_thread = calloc(1, sizeof(zlog_thread_t));
if (!a_thread) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
a_thread->init_version = init_version;
a_thread->mdc = zlog_mdc_new();
if (!a_thread->mdc) {
zc_error("zlog_mdc_new fail");
goto err;
}
a_thread->event = zlog_event_new(time_cache_count);
if (!a_thread->event) {
zc_error("zlog_event_new fail");
goto err;
}
a_thread->pre_path_buf = zlog_buf_new(MAXLEN_PATH + 1, MAXLEN_PATH + 1, NULL);
if (!a_thread->pre_path_buf) {
zc_error("zlog_buf_new fail");
goto err;
}
a_thread->path_buf = zlog_buf_new(MAXLEN_PATH + 1, MAXLEN_PATH + 1, NULL);
if (!a_thread->path_buf) {
zc_error("zlog_buf_new fail");
goto err;
}
a_thread->archive_path_buf = zlog_buf_new(MAXLEN_PATH + 1, MAXLEN_PATH + 1, NULL);
if (!a_thread->archive_path_buf) {
zc_error("zlog_buf_new fail");
goto err;
}
a_thread->pre_msg_buf = zlog_buf_new(buf_size_min, buf_size_max, "..." FILE_NEWLINE);
if (!a_thread->pre_msg_buf) {
zc_error("zlog_buf_new fail");
goto err;
}
a_thread->msg_buf = zlog_buf_new(buf_size_min, buf_size_max, "..." FILE_NEWLINE);
if (!a_thread->msg_buf) {
zc_error("zlog_buf_new fail");
goto err;
}
//zlog_thread_profile(a_thread, ZC_DEBUG);
return a_thread;
err:
zlog_thread_del(a_thread);
return NULL;
}
/*******************************************************************************/
int zlog_thread_rebuild_msg_buf(zlog_thread_t * a_thread, size_t buf_size_min, size_t buf_size_max)
{
zlog_buf_t *pre_msg_buf_new = NULL;
zlog_buf_t *msg_buf_new = NULL;
zc_assert(a_thread, -1);
if ( (a_thread->msg_buf->size_min == buf_size_min)
&& (a_thread->msg_buf->size_max == buf_size_max)) {
zc_debug("buf size not changed, no need rebuild");
return 0;
}
pre_msg_buf_new = zlog_buf_new(buf_size_min, buf_size_max, "..." FILE_NEWLINE);
if (!pre_msg_buf_new) {
zc_error("zlog_buf_new fail");
goto err;
}
msg_buf_new = zlog_buf_new(buf_size_min, buf_size_max, "..." FILE_NEWLINE);
if (!msg_buf_new) {
zc_error("zlog_buf_new fail");
goto err;
}
zlog_buf_del(a_thread->pre_msg_buf);
a_thread->pre_msg_buf = pre_msg_buf_new;
zlog_buf_del(a_thread->msg_buf);
a_thread->msg_buf = msg_buf_new;
return 0;
err:
if (pre_msg_buf_new) zlog_buf_del(pre_msg_buf_new);
if (msg_buf_new) zlog_buf_del(msg_buf_new);
return -1;
}
int zlog_thread_rebuild_event(zlog_thread_t * a_thread, int time_cache_count)
{
zlog_event_t *event_new = NULL;
zc_assert(a_thread, -1);
event_new = zlog_event_new(time_cache_count);
if (!event_new) {
zc_error("zlog_event_new fail");
goto err;
}
zlog_event_del(a_thread->event);
a_thread->event = event_new;
return 0;
err:
if (event_new) zlog_event_del(event_new);
return -1;
}
/*******************************************************************************/
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_thread_h
#define __zlog_thread_h
#include "zc_defs.h"
#include "event.h"
#include "buf.h"
#include "mdc.h"
typedef struct {
int init_version;
zlog_mdc_t *mdc;
zlog_event_t *event;
zlog_buf_t *pre_path_buf;
zlog_buf_t *path_buf;
zlog_buf_t *archive_path_buf;
zlog_buf_t *pre_msg_buf;
zlog_buf_t *msg_buf;
} zlog_thread_t;
void zlog_thread_del(zlog_thread_t * a_thread);
void zlog_thread_profile(zlog_thread_t * a_thread, int flag);
zlog_thread_t *zlog_thread_new(int init_version,
size_t buf_size_min, size_t buf_size_max, int time_cache_count);
int zlog_thread_rebuild_msg_buf(zlog_thread_t * a_thread, size_t buf_size_min, size_t buf_size_max);
int zlog_thread_rebuild_event(zlog_thread_t * a_thread, int time_cache_count);
#endif
#define ZLOG_VERSION "1.2.12"
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include "zc_defs.h"
zc_arraylist_t *zc_arraylist_new(zc_arraylist_del_fn del)
{
zc_arraylist_t *a_list;
a_list = (zc_arraylist_t *) calloc(1, sizeof(zc_arraylist_t));
if (!a_list) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
a_list->size = ARRAY_LIST_DEFAULT_SIZE;
a_list->len = 0;
/* this could be NULL */
a_list->del = del;
a_list->array = (void **)calloc(a_list->size, sizeof(void *));
if (!a_list->array) {
zc_error("calloc fail, errno[%d]", errno);
free(a_list);
return NULL;
}
return a_list;
}
void zc_arraylist_del(zc_arraylist_t * a_list)
{
int i;
if (!a_list)
return;
if (a_list->del) {
for (i = 0; i < a_list->len; i++) {
if (a_list->array[i])
a_list->del(a_list->array[i]);
}
}
if (a_list->array)
free(a_list->array);
free(a_list);
return;
}
static int zc_arraylist_expand_inner(zc_arraylist_t * a_list, int max)
{
void *tmp;
int new_size;
int diff_size;
new_size = zc_max(a_list->size * 2, max);
tmp = realloc(a_list->array, new_size * sizeof(void *));
if (!tmp) {
zc_error("realloc fail, errno[%d]", errno);
return -1;
}
a_list->array = (void **)tmp;
diff_size = new_size - a_list->size;
if (diff_size) memset(a_list->array + a_list->size, 0x00, diff_size * sizeof(void *));
a_list->size = new_size;
return 0;
}
int zc_arraylist_set(zc_arraylist_t * a_list, int idx, void *data)
{
if (idx > a_list->size - 1) {
if (zc_arraylist_expand_inner(a_list, idx)) {
zc_error("expand_internal fail");
return -1;
}
}
if (a_list->array[idx] && a_list->del) a_list->del(a_list->array[idx]);
a_list->array[idx] = data;
if (a_list->len <= idx)
a_list->len = idx + 1;
return 0;
}
int zc_arraylist_add(zc_arraylist_t * a_list, void *data)
{
return zc_arraylist_set(a_list, a_list->len, data);
}
/* assum idx < len */
static int zc_arraylist_insert_inner(zc_arraylist_t * a_list, int idx,
void *data)
{
if (a_list->array[idx] == NULL) {
a_list->array[idx] = data;
return 0;
}
if (a_list->len > a_list->size - 1) {
if (zc_arraylist_expand_inner(a_list, 0)) {
zc_error("expand_internal fail");
return -1;
}
}
memmove(a_list->array + idx + 1, a_list->array + idx,
(a_list->len - idx) * sizeof(void *));
a_list->array[idx] = data;
a_list->len++;
return 0;
}
int zc_arraylist_sortadd(zc_arraylist_t * a_list, zc_arraylist_cmp_fn cmp,
void *data)
{
int i;
for (i = 0; i < a_list->len; i++) {
if ((*cmp) (a_list->array[i], data) > 0)
break;
}
if (i == a_list->len)
return zc_arraylist_add(a_list, data);
else
return zc_arraylist_insert_inner(a_list, i, data);
}
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zc_arraylist_h
#define __zc_arraylist_h
#define ARRAY_LIST_DEFAULT_SIZE 32
typedef void (*zc_arraylist_del_fn) (void *data);
typedef int (*zc_arraylist_cmp_fn) (void *data1, void *data2);
/* make zc_arraylist_foreach speed up, so keep struct defination here */
typedef struct {
void **array;
int len;
int size;
zc_arraylist_del_fn del;
} zc_arraylist_t;
zc_arraylist_t *zc_arraylist_new(zc_arraylist_del_fn del);
void zc_arraylist_del(zc_arraylist_t * a_list);
int zc_arraylist_set(zc_arraylist_t * a_list, int i, void *data);
int zc_arraylist_add(zc_arraylist_t * a_list, void *data);
int zc_arraylist_sortadd(zc_arraylist_t * a_list, zc_arraylist_cmp_fn cmp,
void *data);
#define zc_arraylist_len(a_list) (a_list->len)
#define zc_arraylist_get(a_list, i) \
((i >= a_list->len) ? NULL : a_list->array[i])
#define zc_arraylist_foreach(a_list, i, a_unit) \
for(i = 0, a_unit = a_list->array[0]; (i < a_list->len) && (a_unit = a_list->array[i], 1) ; i++)
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zc_defs_h
#define __zc_defs_h
#include "zc_profile.h"
#include "zc_arraylist.h"
#include "zc_hashtable.h"
#include "zc_xplatform.h"
#include "zc_util.h"
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include "zc_defs.h"
#include "zc_hashtable.h"
struct zc_hashtable_s {
size_t nelem;
zc_hashtable_entry_t **tab;
size_t tab_size;
zc_hashtable_hash_fn hash;
zc_hashtable_equal_fn equal;
zc_hashtable_del_fn key_del;
zc_hashtable_del_fn value_del;
};
zc_hashtable_t *zc_hashtable_new(size_t a_size,
zc_hashtable_hash_fn hash,
zc_hashtable_equal_fn equal,
zc_hashtable_del_fn key_del,
zc_hashtable_del_fn value_del)
{
zc_hashtable_t *a_table;
a_table = calloc(1, sizeof(*a_table));
if (!a_table) {
zc_error("calloc fail, errno[%d]", errno);
return NULL;
}
a_table->tab = calloc(a_size, sizeof(*(a_table->tab)));
if (!a_table->tab) {
zc_error("calloc fail, errno[%d]", errno);
free(a_table);
return NULL;
}
a_table->tab_size = a_size;
a_table->nelem = 0;
a_table->hash = hash;
a_table->equal = equal;
/* these two could be NULL */
a_table->key_del = key_del;
a_table->value_del = value_del;
return a_table;
}
void zc_hashtable_del(zc_hashtable_t * a_table)
{
size_t i;
zc_hashtable_entry_t *p;
zc_hashtable_entry_t *q;
if (!a_table) {
zc_error("a_table[%p] is NULL, just do nothing", a_table);
return;
}
for (i = 0; i < a_table->tab_size; i++) {
for (p = (a_table->tab)[i]; p; p = q) {
q = p->next;
if (a_table->key_del) {
a_table->key_del(p->key);
}
if (a_table->value_del) {
a_table->value_del(p->value);
}
free(p);
}
}
if (a_table->tab)
free(a_table->tab);
free(a_table);
return;
}
void zc_hashtable_clean(zc_hashtable_t * a_table)
{
size_t i;
zc_hashtable_entry_t *p;
zc_hashtable_entry_t *q;
for (i = 0; i < a_table->tab_size; i++) {
for (p = (a_table->tab)[i]; p; p = q) {
q = p->next;
if (a_table->key_del) {
a_table->key_del(p->key);
}
if (a_table->value_del) {
a_table->value_del(p->value);
}
free(p);
}
(a_table->tab)[i] = NULL;
}
a_table->nelem = 0;
return;
}
static int zc_hashtable_rehash(zc_hashtable_t * a_table)
{
size_t i;
size_t j;
size_t tab_size;
zc_hashtable_entry_t **tab;
zc_hashtable_entry_t *p;
zc_hashtable_entry_t *q;
tab_size = 2 * a_table->tab_size;
tab = calloc(tab_size, sizeof(*tab));
if (!tab) {
zc_error("calloc fail, errno[%d]", errno);
return -1;
}
for (i = 0; i < a_table->tab_size; i++) {
for (p = (a_table->tab)[i]; p; p = q) {
q = p->next;
p->next = NULL;
p->prev = NULL;
j = p->hash_key % tab_size;
if (tab[j]) {
tab[j]->prev = p;
p->next = tab[j];
}
tab[j] = p;
}
}
free(a_table->tab);
a_table->tab = tab;
a_table->tab_size = tab_size;
return 0;
}
zc_hashtable_entry_t *zc_hashtable_get_entry(zc_hashtable_t * a_table, const void *a_key)
{
unsigned int i;
zc_hashtable_entry_t *p;
i = a_table->hash(a_key) % a_table->tab_size;
for (p = (a_table->tab)[i]; p; p = p->next) {
if (a_table->equal(a_key, p->key))
return p;
}
return NULL;
}
void *zc_hashtable_get(zc_hashtable_t * a_table, const void *a_key)
{
unsigned int i;
zc_hashtable_entry_t *p;
i = a_table->hash(a_key) % a_table->tab_size;
for (p = (a_table->tab)[i]; p; p = p->next) {
if (a_table->equal(a_key, p->key))
return p->value;
}
return NULL;
}
int zc_hashtable_put(zc_hashtable_t * a_table, void *a_key, void *a_value)
{
int rc = 0;
unsigned int i;
zc_hashtable_entry_t *p = NULL;
i = a_table->hash(a_key) % a_table->tab_size;
for (p = (a_table->tab)[i]; p; p = p->next) {
if (a_table->equal(a_key, p->key))
break;
}
if (p) {
if (a_table->key_del) {
a_table->key_del(p->key);
}
if (a_table->value_del) {
a_table->value_del(p->value);
}
p->key = a_key;
p->value = a_value;
return 0;
} else {
if (a_table->nelem > a_table->tab_size * 1.3) {
rc = zc_hashtable_rehash(a_table);
if (rc) {
zc_error("rehash fail");
return -1;
}
}
p = calloc(1, sizeof(*p));
if (!p) {
zc_error("calloc fail, errno[%d]", errno);
return -1;
}
p->hash_key = a_table->hash(a_key);
p->key = a_key;
p->value = a_value;
p->next = NULL;
p->prev = NULL;
i = p->hash_key % a_table->tab_size;
if ((a_table->tab)[i]) {
(a_table->tab)[i]->prev = p;
p->next = (a_table->tab)[i];
}
(a_table->tab)[i] = p;
a_table->nelem++;
}
return 0;
}
void zc_hashtable_remove(zc_hashtable_t * a_table, const void *a_key)
{
zc_hashtable_entry_t *p;
unsigned int i;
if (!a_table || !a_key) {
zc_error("a_table[%p] or a_key[%p] is NULL, just do nothing", a_table, a_key);
return;
}
i = a_table->hash(a_key) % a_table->tab_size;
for (p = (a_table->tab)[i]; p; p = p->next) {
if (a_table->equal(a_key, p->key))
break;
}
if (!p) {
zc_error("p[%p] not found in hashtable", p);
return;
}
if (a_table->key_del) {
a_table->key_del(p->key);
}
if (a_table->value_del) {
a_table->value_del(p->value);
}
if (p->next) {
p->next->prev = p->prev;
}
if (p->prev) {
p->prev->next = p->next;
} else {
unsigned int i;
i = p->hash_key % a_table->tab_size;
a_table->tab[i] = p->next;
}
free(p);
a_table->nelem--;
return;
}
zc_hashtable_entry_t *zc_hashtable_begin(zc_hashtable_t * a_table)
{
size_t i;
zc_hashtable_entry_t *p;
for (i = 0; i < a_table->tab_size; i++) {
for (p = (a_table->tab)[i]; p; p = p->next) {
if (p)
return p;
}
}
return NULL;
}
zc_hashtable_entry_t *zc_hashtable_next(zc_hashtable_t * a_table, zc_hashtable_entry_t * a_entry)
{
size_t i;
size_t j;
if (a_entry->next)
return a_entry->next;
i = a_entry->hash_key % a_table->tab_size;
for (j = i + 1; j < a_table->tab_size; j++) {
if ((a_table->tab)[j]) {
return (a_table->tab)[j];
}
}
return NULL;
}
/*******************************************************************************/
unsigned int zc_hashtable_str_hash(const void *str)
{
unsigned int h = 5381;
const char *p = (const char *)str;
while (*p != '\0')
h = ((h << 5) + h) + (*p++); /* hash * 33 + c */
return h;
}
int zc_hashtable_str_equal(const void *key1, const void *key2)
{
return (STRCMP((const char *)key1, ==, (const char *)key2));
}
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zc_hashtalbe_h
#define __zc_hashtalbe_h
#include <stdlib.h>
typedef struct zc_hashtable_entry_s {
unsigned int hash_key;
void *key;
void *value;
struct zc_hashtable_entry_s *prev;
struct zc_hashtable_entry_s *next;
} zc_hashtable_entry_t;
typedef struct zc_hashtable_s zc_hashtable_t;
typedef unsigned int (*zc_hashtable_hash_fn) (const void *key);
typedef int (*zc_hashtable_equal_fn) (const void *key1, const void *key2);
typedef void (*zc_hashtable_del_fn) (void *kv);
zc_hashtable_t *zc_hashtable_new(size_t a_size,
zc_hashtable_hash_fn hash_fn,
zc_hashtable_equal_fn equal_fn,
zc_hashtable_del_fn key_del_fn,
zc_hashtable_del_fn value_del_fn);
void zc_hashtable_del(zc_hashtable_t * a_table);
void zc_hashtable_clean(zc_hashtable_t * a_table);
int zc_hashtable_put(zc_hashtable_t * a_table, void *a_key, void *a_value);
zc_hashtable_entry_t *zc_hashtable_get_entry(zc_hashtable_t * a_table, const void *a_key);
void *zc_hashtable_get(zc_hashtable_t * a_table, const void *a_key);
void zc_hashtable_remove(zc_hashtable_t * a_table, const void *a_key);
zc_hashtable_entry_t *zc_hashtable_begin(zc_hashtable_t * a_table);
zc_hashtable_entry_t *zc_hashtable_next(zc_hashtable_t * a_table, zc_hashtable_entry_t * a_entry);
#define zc_hashtable_foreach(a_table, a_entry) \
for(a_entry = zc_hashtable_begin(a_table); a_entry; a_entry = zc_hashtable_next(a_table, a_entry))
unsigned int zc_hashtable_str_hash(const void *str);
int zc_hashtable_str_equal(const void *key1, const void *key2);
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fmacros.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>
#include "zc_profile.h"
#include "zc_xplatform.h"
static void zc_time(char *time_str, size_t time_str_size)
{
time_t tt;
time(&tt);
#ifdef _WIN32
struct tm *local_time;
local_time = localtime(&tt);
strftime(time_str, time_str_size, "%m-%d %H:%M:%S", local_time);
#else
struct tm local_time;
localtime_r(&tt, &local_time);
strftime(time_str, time_str_size, "%m-%d %H:%M:%S", &local_time);
#endif
return;
}
int zc_profile_inner(int flag, const char *file, const long line, const char *fmt, ...)
{
va_list args;
char time_str[20 + 1];
FILE *fp = NULL;
static char *debug_log = NULL;
static char *error_log = NULL;
static size_t init_flag = 0;
if (!init_flag) {
init_flag = 1;
debug_log = getenv("ZLOG_PROFILE_DEBUG");
error_log = getenv("ZLOG_PROFILE_ERROR");
}
switch (flag) {
case ZC_DEBUG:
if (debug_log == NULL) return 0;
fp = fopen(debug_log, "a");
if (!fp) return -1;
zc_time(time_str, sizeof(time_str));
fprintf(fp, "%s DEBUG (%d:%s:%ld) ", time_str, getpid(), file, line);
break;
case ZC_WARN:
if (error_log == NULL) return 0;
fp = fopen(error_log, "a");
if (!fp) return -1;
zc_time(time_str, sizeof(time_str));
fprintf(fp, "%s WARN (%d:%s:%ld) ", time_str, getpid(), file, line);
break;
case ZC_ERROR:
if (error_log == NULL) return 0;
fp = fopen(error_log, "a");
if (!fp) return -1;
zc_time(time_str, sizeof(time_str));
fprintf(fp, "%s ERROR (%d:%s:%ld) ", time_str, getpid(), file, line);
break;
}
/* writing file twice(time & msg) is not atomic
* may cause cross
* but avoid log size limit */
va_start(args, fmt);
vfprintf(fp, fmt, args);
va_end(args);
fprintf(fp, "\n");
fclose(fp);
return 0;
}
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zc_profile_h
#define __zc_profile_h
#include <stdarg.h>
#define EMPTY()
#define zc_assert(expr, rv) \
if(!(expr)) { \
zc_error(#expr" is null or 0"); \
return rv; \
}
enum zc_profile_flag {
ZC_DEBUG = 0,
ZC_WARN = 1,
ZC_ERROR = 2
};
#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
#define zc_debug(...) \
zc_profile_inner(ZC_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
#define zc_warn(...) \
zc_profile_inner(ZC_WARN, __FILE__, __LINE__, __VA_ARGS__)
#define zc_error(...) \
zc_profile_inner(ZC_ERROR, __FILE__, __LINE__, __VA_ARGS__)
#define zc_profile(flag, ...) \
zc_profile_inner(flag, __FILE__, __LINE__, __VA_ARGS__)
#elif defined __GNUC__
#define zc_debug(fmt, args...) \
zc_profile_inner(ZC_DEBUG, __FILE__, __LINE__, fmt, ## args)
#define zc_warn(fmt, args...) \
zc_profile_inner(ZC_WARN, __FILE__, __LINE__, fmt, ## args)
#define zc_error(fmt, args...) \
zc_profile_inner(ZC_ERROR, __FILE__, __LINE__, fmt, ## args)
#define zc_profile(flag, fmt, args...) \
zc_profile_inner(flag, __FILE__, __LINE__, fmt, ## args)
#endif
int zc_profile_inner(int flag,
const char *file, const long line,
const char *fmt, ...);
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include "zc_defs.h"
size_t zc_parse_byte_size(char *astring)
{
/* Parse size in bytes depending on the suffix. Valid suffixes are KB, MB and GB */
char *p;
char *q;
size_t sz;
long res;
int c, m;
zc_assert(astring, 0);
/* clear space */
for (p = q = astring; *p != '\0'; p++) {
if (isspace(*p)) {
continue;
} else {
*q = *p;
q++;
}
}
*q = '\0';
sz = strlen(astring);
res = strtol(astring, (char **)NULL, 10);
if (res <= 0)
return 0;
if (astring[sz - 1] == 'B' || astring[sz - 1] == 'b') {
c = astring[sz - 2];
m = 1024;
} else {
c = astring[sz - 1];
m = 1000;
}
switch (c) {
case 'K':
case 'k':
res *= m;
break;
case 'M':
case 'm':
res *= m * m;
break;
case 'G':
case 'g':
res *= m * m * m;
break;
default:
if (!isdigit(c)) {
zc_error("Wrong suffix parsing " "size in bytes for string [%s], ignoring suffix",
astring);
}
break;
}
return (res);
}
/*******************************************************************************/
int zc_str_replace_env(char *str, size_t str_size)
{
char *p;
char *q;
char fmt[MAXLEN_CFG_LINE + 1];
char env_key[MAXLEN_CFG_LINE + 1];
char env_value[MAXLEN_CFG_LINE + 1];
int str_len;
int env_value_len;
int nscan;
int nread;
str_len = strlen(str);
q = str;
do {
p = strchr(q, '%');
if (!p) {
/* can't find more % */
break;
}
memset(fmt, 0x00, sizeof(fmt));
memset(env_key, 0x00, sizeof(env_key));
memset(env_value, 0x00, sizeof(env_value));
nread = 0;
nscan = sscanf(p + 1, "%[.0-9-]%n", fmt + 1, &nread);
if (nscan == 1) {
fmt[0] = '%';
fmt[nread + 1] = 's';
} else {
nread = 0;
strcpy(fmt, "%s");
}
q = p + 1 + nread;
nscan = sscanf(q, "E(%[^)])%n", env_key, &nread);
if (nscan == 0) {
continue;
}
q += nread;
if (*(q - 1) != ')') {
zc_error("in string[%s] can't find match )", p);
return -1;
}
env_value_len = snprintf(env_value, sizeof(env_value), fmt, getenv(env_key));
if (env_value_len < 0 || env_value_len >= sizeof(env_value)) {
zc_error("snprintf fail, errno[%d], evn_value_len[%d]",
errno, env_value_len);
return -1;
}
str_len = str_len - (q - p) + env_value_len;
if (str_len > str_size - 1) {
zc_error("repalce env_value[%s] cause overlap", env_value);
return -1;
}
memmove(p + env_value_len, q, strlen(q) + 1);
memcpy(p, env_value, env_value_len);
} while (1);
return 0;
}
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zc_util_h
#define __zc_util_h
size_t zc_parse_byte_size(char *astring);
int zc_str_replace_env(char *str, size_t str_size);
#define zc_max(a,b) ((a) > (b) ? (a) : (b))
#define zc_min(a,b) ((a) < (b) ? (a) : (b))
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zc_xplatform_h
#define __zc_xplatform_h
#include <limits.h>
#define ZLOG_INT32_LEN sizeof("-2147483648") - 1
#define ZLOG_INT64_LEN sizeof("-9223372036854775808") - 1
#if ((__GNU__ == 2) && (__GNUC_MINOR__ < 8))
#define ZLOG_MAX_UINT32_VALUE (uint32_t) 0xffffffffLL
#else
#define ZLOG_MAX_UINT32_VALUE (uint32_t) 0xffffffff
#endif
#define ZLOG_MAX_INT32_VALUE (uint32_t) 0x7fffffff
#define MAXLEN_PATH 1024
#define MAXLEN_CFG_LINE (MAXLEN_PATH * 4)
#define MAXLINES_NO 128
#define FILE_NEWLINE "\n"
#define FILE_NEWLINE_LEN 1
#include <string.h>
#include <strings.h>
#define STRCMP(_a_,_C_,_b_) ( strcmp(_a_,_b_) _C_ 0 )
#define STRNCMP(_a_,_C_,_b_,_n_) ( strncmp(_a_,_b_,_n_) _C_ 0 )
#define STRICMP(_a_,_C_,_b_) ( strcasecmp(_a_,_b_) _C_ 0 )
#define STRNICMP(_a_,_C_,_b_,_n_) ( strncasecmp(_a_,_b_,_n_) _C_ 0 )
#ifdef __APPLE__
#include <AvailabilityMacros.h>
#endif
/* Define zlog_fstat to fstat or fstat64() */
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
#define zlog_fstat fstat64
#define zlog_stat stat64
#elif defined(_WIN32)
#define zlog_fstat _fstat
#define zlog_stat _stat
#else
#define zlog_fstat fstat
#define zlog_stat stat
#endif
/* Define zlog_fsync to fdatasync() in Linux and fsync() for all the rest */
#ifdef __linux__
#define zlog_fsync fdatasync
#else
#define zlog_fsync fsync
#endif
#endif
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fmacros.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include "zlog.h"
#include "version.h"
int main(int argc, char *argv[])
{
int rc = 0;
int op;
int quiet = 0;
static const char *help =
"usage: zlog-chk-conf [conf files]...\n"
"\t-q,\tsuppress non-error message\n"
"\t-h,\tshow help message\n"
"zlog version: " ZLOG_VERSION "\n";
while((op = getopt(argc, argv, "qhv")) > 0) {
if (op == 'h') {
fputs(help, stdout);
return 0;
} else if (op == 'q') {
quiet = 1;
}
}
argc -= optind;
argv += optind;
if (argc == 0) {
fputs(help, stdout);
return -1;
}
setenv("ZLOG_PROFILE_ERROR", "/dev/stderr", 1);
setenv("ZLOG_CHECK_FORMAT_RULE", "1", 1);
while (argc > 0) {
rc = zlog_init(*argv);
if (rc) {
printf("\n---[%s] syntax error, see error message above\n",
*argv);
exit(2);
} else {
zlog_fini();
if (!quiet) {
printf("--[%s] syntax right\n", *argv);
}
}
argc--;
argv++;
}
exit(0);
}
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fmacros.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <pthread.h>
#include "conf.h"
#include "category_table.h"
#include "record_table.h"
#include "mdc.h"
#include "zc_defs.h"
#include "rule.h"
#include "version.h"
/*******************************************************************************/
extern char *zlog_git_sha1;
/*******************************************************************************/
static pthread_rwlock_t zlog_env_lock = PTHREAD_RWLOCK_INITIALIZER;
zlog_conf_t *zlog_env_conf;
static pthread_key_t zlog_thread_key;
static zc_hashtable_t *zlog_env_categories;
static zc_hashtable_t *zlog_env_records;
static zlog_category_t *zlog_default_category;
static size_t zlog_env_reload_conf_count;
static int zlog_env_is_init = 0;
static int zlog_env_init_version = 0;
/*******************************************************************************/
/* inner no need thread-safe */
static void zlog_fini_inner(void)
{
/* pthread_key_delete(zlog_thread_key); */
/* never use pthread_key_delete,
* it will cause other thread can't release zlog_thread_t
* after one thread call pthread_key_delete
* also key not init will cause a core dump
*/
if (zlog_env_categories) zlog_category_table_del(zlog_env_categories);
zlog_env_categories = NULL;
zlog_default_category = NULL;
if (zlog_env_records) zlog_record_table_del(zlog_env_records);
zlog_env_records = NULL;
if (zlog_env_conf) zlog_conf_del(zlog_env_conf);
zlog_env_conf = NULL;
return;
}
static void zlog_clean_rest_thread(void)
{
int rc;
zlog_thread_t *a_thread;
a_thread = pthread_getspecific(zlog_thread_key);
if (!a_thread) return;
zlog_thread_del(a_thread);
rc = pthread_setspecific(zlog_thread_key, NULL);
if (rc) {
zc_error("pthread_setspecific fail, rc[%d]", rc);
return;
}
return;
}
static int zlog_init_inner_from_string(const char *config_string)
{
int rc = 0;
/* the 1st time in the whole process do init */
if (zlog_env_init_version == 0) {
/* clean up is done by OS when a thread call pthread_exit */
rc = pthread_key_create(&zlog_thread_key, (void (*) (void *)) zlog_thread_del);
if (rc) {
zc_error("pthread_key_create fail, rc[%d]", rc);
goto err;
}
/* if some thread do not call pthread_exit, like main thread
* atexit will clean it
*/
rc = atexit(zlog_clean_rest_thread);
if (rc) {
zc_error("atexit fail, rc[%d]", rc);
goto err;
}
zlog_env_init_version++;
} /* else maybe after zlog_fini() and need not create pthread_key */
zlog_env_conf = zlog_conf_new_from_string(config_string);
if (!zlog_env_conf) {
zc_error("zlog_conf_new[%s] fail", config_string);
goto err;
}
zlog_env_categories = zlog_category_table_new();
if (!zlog_env_categories) {
zc_error("zlog_category_table_new fail");
goto err;
}
zlog_env_records = zlog_record_table_new();
if (!zlog_env_records) {
zc_error("zlog_record_table_new fail");
goto err;
}
return 0;
err:
zlog_fini_inner();
return -1;
}
static int zlog_init_inner(const char *config)
{
int rc = 0;
/* the 1st time in the whole process do init */
if (zlog_env_init_version == 0) {
/* clean up is done by OS when a thread call pthread_exit */
rc = pthread_key_create(&zlog_thread_key, (void (*) (void *)) zlog_thread_del);
if (rc) {
zc_error("pthread_key_create fail, rc[%d]", rc);
goto err;
}
/* if some thread do not call pthread_exit, like main thread
* atexit will clean it
*/
rc = atexit(zlog_clean_rest_thread);
if (rc) {
zc_error("atexit fail, rc[%d]", rc);
goto err;
}
zlog_env_init_version++;
} /* else maybe after zlog_fini() and need not create pthread_key */
zlog_env_conf = zlog_conf_new(config);
if (!zlog_env_conf) {
zc_error("zlog_conf_new[%s] fail", config);
goto err;
}
zlog_env_categories = zlog_category_table_new();
if (!zlog_env_categories) {
zc_error("zlog_category_table_new fail");
goto err;
}
zlog_env_records = zlog_record_table_new();
if (!zlog_env_records) {
zc_error("zlog_record_table_new fail");
goto err;
}
return 0;
err:
zlog_fini_inner();
return -1;
}
/*******************************************************************************/
int zlog_init(const char *config)
{
int rc;
zc_debug("------zlog_init start------");
zc_debug("------compile time[%s %s], version[%s]------", __DATE__, __TIME__, ZLOG_VERSION);
rc = pthread_rwlock_wrlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc);
return -1;
}
if (zlog_env_is_init) {
zc_error("already init, use zlog_reload pls");
goto err;
}
if (zlog_init_inner(config)) {
zc_error("zlog_init_inner[%s] fail", config);
goto err;
}
zlog_env_is_init = 1;
zlog_env_init_version++;
zc_debug("------zlog_init success end------");
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return 0;
err:
zc_error("------zlog_init fail end------");
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return -1;
}
int zlog_init_from_string(const char *config_string)
{
int rc;
zc_debug("------zlog_init start------");
zc_debug("------compile time[%s %s], version[%s]------", __DATE__, __TIME__, ZLOG_VERSION);
rc = pthread_rwlock_wrlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc);
return -1;
}
if (zlog_env_is_init) {
zc_error("already init, use zlog_reload pls");
goto err;
}
if (zlog_init_inner_from_string(config_string)) {
zc_error("zlog_init_inner[%s] fail", config_string);
goto err;
}
zlog_env_is_init = 1;
zlog_env_init_version++;
zc_debug("------zlog_init success end------");
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return 0;
err:
zc_error("------zlog_init fail end------");
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return -1;
}
int dzlog_init(const char *config, const char *cname)
{
int rc = 0;
zc_debug("------dzlog_init start------");
zc_debug("------compile time[%s %s], version[%s]------",
__DATE__, __TIME__, ZLOG_VERSION);
rc = pthread_rwlock_wrlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc);
return -1;
}
if (zlog_env_is_init) {
zc_error("already init, use zlog_reload pls");
goto err;
}
if (zlog_init_inner(config)) {
zc_error("zlog_init_inner[%s] fail", config);
goto err;
}
zlog_default_category = zlog_category_table_fetch_category(
zlog_env_categories,
cname,
zlog_env_conf->rules);
if (!zlog_default_category) {
zc_error("zlog_category_table_fetch_category[%s] fail", cname);
goto err;
}
zlog_env_is_init = 1;
zlog_env_init_version++;
zc_debug("------dzlog_init success end------");
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return 0;
err:
zc_error("------dzlog_init fail end------");
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return -1;
}
/*******************************************************************************/
int zlog_reload(const char *config)
{
int rc = 0;
int i = 0;
zlog_conf_t *new_conf = NULL;
zlog_rule_t *a_rule;
int c_up = 0;
zc_debug("------zlog_reload start------");
rc = pthread_rwlock_wrlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc);
return -1;
}
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
goto quit;
}
/* use last conf file */
if (config == NULL) config = zlog_env_conf->file;
/* reach reload period */
if (config == (char*)-1) {
/* test again, avoid other threads already reloaded */
if (zlog_env_reload_conf_count > zlog_env_conf->reload_conf_period) {
config = zlog_env_conf->file;
} else {
/* do nothing, already done */
goto quit;
}
}
/* reset counter, whether automaticlly or mannually */
zlog_env_reload_conf_count = 0;
new_conf = zlog_conf_new(config);
if (!new_conf) {
zc_error("zlog_conf_new fail");
goto err;
}
zc_arraylist_foreach(new_conf->rules, i, a_rule) {
zlog_rule_set_record(a_rule, zlog_env_records);
}
if (zlog_category_table_update_rules(zlog_env_categories, new_conf->rules)) {
c_up = 0;
zc_error("zlog_category_table_update fail");
goto err;
} else {
c_up = 1;
}
zlog_env_init_version++;
if (c_up) zlog_category_table_commit_rules(zlog_env_categories);
zlog_conf_del(zlog_env_conf);
zlog_env_conf = new_conf;
zc_debug("------zlog_reload success, total init verison[%d] ------", zlog_env_init_version);
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return 0;
err:
/* fail, roll back everything */
zc_warn("zlog_reload fail, use old conf file, still working");
if (new_conf) zlog_conf_del(new_conf);
if (c_up) zlog_category_table_rollback_rules(zlog_env_categories);
zc_error("------zlog_reload fail, total init version[%d] ------", zlog_env_init_version);
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return -1;
quit:
zc_debug("------zlog_reload do nothing------");
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return 0;
}
/*******************************************************************************/
int zlog_reload_from_string(const char *conf_string)
{
int rc = 0;
int i = 0;
zlog_conf_t *new_conf = NULL;
zlog_rule_t *a_rule;
int c_up = 0;
zc_debug("------zlog_reload start------");
rc = pthread_rwlock_wrlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc);
return -1;
}
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
goto quit;
}
if (conf_string == NULL) goto quit;
new_conf = zlog_conf_new_from_string(conf_string);
if (!new_conf) {
zc_error("zlog_conf_new fail");
goto err;
}
zc_arraylist_foreach(new_conf->rules, i, a_rule) {
zlog_rule_set_record(a_rule, zlog_env_records);
}
if (zlog_category_table_update_rules(zlog_env_categories, new_conf->rules)) {
c_up = 0;
zc_error("zlog_category_table_update fail");
goto err;
} else {
c_up = 1;
}
zlog_env_init_version++;
if (c_up) zlog_category_table_commit_rules(zlog_env_categories);
zlog_conf_del(zlog_env_conf);
zlog_env_conf = new_conf;
zc_debug("------zlog_reload success, total init verison[%d] ------", zlog_env_init_version);
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return 0;
err:
/* fail, roll back everything */
zc_warn("zlog_reload fail, use old conf file, still working");
if (new_conf) zlog_conf_del(new_conf);
if (c_up) zlog_category_table_rollback_rules(zlog_env_categories);
zc_error("------zlog_reload fail, total init version[%d] ------", zlog_env_init_version);
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return -1;
quit:
zc_debug("------zlog_reload do nothing------");
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return 0;
}
/*******************************************************************************/
void zlog_fini(void)
{
int rc = 0;
zc_debug("------zlog_fini start------");
rc = pthread_rwlock_wrlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc);
return;
}
if (!zlog_env_is_init) {
zc_error("before finish, must zlog_init() or dzlog_init() first");
goto exit;
}
zlog_fini_inner();
zlog_env_is_init = 0;
exit:
zc_debug("------zlog_fini end------");
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return;
}
return;
}
/*******************************************************************************/
zlog_category_t *zlog_get_category(const char *cname)
{
int rc = 0;
zlog_category_t *a_category = NULL;
zc_assert(cname, NULL);
zc_debug("------zlog_get_category[%s] start------", cname);
rc = pthread_rwlock_wrlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc);
return NULL;
}
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
a_category = NULL;
goto err;
}
a_category = zlog_category_table_fetch_category(
zlog_env_categories,
cname,
zlog_env_conf->rules);
if (!a_category) {
zc_error("zlog_category_table_fetch_category[%s] fail", cname);
goto err;
}
zc_debug("------zlog_get_category[%s] success, end------ ", cname);
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return NULL;
}
return a_category;
err:
zc_error("------zlog_get_category[%s] fail, end------ ", cname);
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return NULL;
}
return NULL;
}
int dzlog_set_category(const char *cname)
{
int rc = 0;
zc_assert(cname, -1);
zc_debug("------dzlog_set_category[%s] start------", cname);
rc = pthread_rwlock_wrlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc);
return -1;
}
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
goto err;
}
zlog_default_category = zlog_category_table_fetch_category(
zlog_env_categories,
cname,
zlog_env_conf->rules);
if (!zlog_default_category) {
zc_error("zlog_category_table_fetch_category[%s] fail", cname);
goto err;
}
zc_debug("------dzlog_set_category[%s] end, success------ ", cname);
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return 0;
err:
zc_error("------dzlog_set_category[%s] end, fail------ ", cname);
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return -1;
}
/*******************************************************************************/
#define zlog_fetch_thread(a_thread, fail_goto) do { \
int rd = 0; \
a_thread = pthread_getspecific(zlog_thread_key); \
if (!a_thread) { \
a_thread = zlog_thread_new(zlog_env_init_version, \
zlog_env_conf->buf_size_min, zlog_env_conf->buf_size_max, \
zlog_env_conf->time_cache_count); \
if (!a_thread) { \
zc_error("zlog_thread_new fail"); \
goto fail_goto; \
} \
\
rd = pthread_setspecific(zlog_thread_key, a_thread); \
if (rd) { \
zlog_thread_del(a_thread); \
zc_error("pthread_setspecific fail, rd[%d]", rd); \
goto fail_goto; \
} \
} \
\
if (a_thread->init_version != zlog_env_init_version) { \
/* as mdc is still here, so can not easily del and new */ \
rd = zlog_thread_rebuild_msg_buf(a_thread, \
zlog_env_conf->buf_size_min, \
zlog_env_conf->buf_size_max); \
if (rd) { \
zc_error("zlog_thread_resize_msg_buf fail, rd[%d]", rd); \
goto fail_goto; \
} \
\
rd = zlog_thread_rebuild_event(a_thread, zlog_env_conf->time_cache_count); \
if (rd) { \
zc_error("zlog_thread_resize_msg_buf fail, rd[%d]", rd); \
goto fail_goto; \
} \
a_thread->init_version = zlog_env_init_version; \
} \
} while (0)
/*******************************************************************************/
int zlog_put_mdc(const char *key, const char *value)
{
int rc = 0;
zlog_thread_t *a_thread;
zc_assert(key, -1);
zc_assert(value, -1);
rc = pthread_rwlock_rdlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc);
return -1;
}
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
goto err;
}
zlog_fetch_thread(a_thread, err);
if (zlog_mdc_put(a_thread->mdc, key, value)) {
zc_error("zlog_mdc_put fail, key[%s], value[%s]", key, value);
goto err;
}
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return 0;
err:
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return -1;
}
return -1;
}
char *zlog_get_mdc(char *key)
{
int rc = 0;
char *value = NULL;
zlog_thread_t *a_thread;
zc_assert(key, NULL);
rc = pthread_rwlock_rdlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_rdlock fail, rc[%d]", rc);
return NULL;
}
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
goto err;
}
a_thread = pthread_getspecific(zlog_thread_key);
if (!a_thread) {
zc_error("thread not found, maybe not use zlog_put_mdc before");
goto err;
}
value = zlog_mdc_get(a_thread->mdc, key);
if (!value) {
zc_error("key[%s] not found in mdc", key);
goto err;
}
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return NULL;
}
return value;
err:
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return NULL;
}
return NULL;
}
void zlog_remove_mdc(char *key)
{
int rc = 0;
zlog_thread_t *a_thread;
zc_assert(key, );
rc = pthread_rwlock_rdlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_rdlock fail, rc[%d]", rc);
return;
}
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
goto exit;
}
a_thread = pthread_getspecific(zlog_thread_key);
if (!a_thread) {
zc_error("thread not found, maybe not use zlog_put_mdc before");
goto exit;
}
zlog_mdc_remove(a_thread->mdc, key);
exit:
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return;
}
return;
}
void zlog_clean_mdc(void)
{
int rc = 0;
zlog_thread_t *a_thread;
rc = pthread_rwlock_rdlock(&zlog_env_lock);
if (rc) {;
zc_error("pthread_rwlock_rdlock fail, rc[%d]", rc);
return;
}
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
goto exit;
}
a_thread = pthread_getspecific(zlog_thread_key);
if (!a_thread) {
zc_error("thread not found, maybe not use zlog_put_mdc before");
goto exit;
}
zlog_mdc_clean(a_thread->mdc);
exit:
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return;
}
return;
}
int zlog_level_switch(zlog_category_t * category, int level)
{
// This is NOT thread safe.
memset(category->level_bitmap, 0x00, sizeof(category->level_bitmap));
category->level_bitmap[level / 8] |= ~(0xFF << (8 - level % 8));
memset(category->level_bitmap + level / 8 + 1, 0xFF,
sizeof(category->level_bitmap) - level / 8 - 1);
return 0;
}
/*******************************************************************************/
void vzlog(zlog_category_t * category,
const char *file, size_t filelen,
const char *func, size_t funclen,
long line, int level,
const char *format, va_list args)
{
zlog_thread_t *a_thread;
/* The bitmap determination here is not under the protection of rdlock.
* It may be changed by other CPU by zlog_reload() halfway.
*
* Old or strange value may be read here,
* but it is safe, the bitmap is valid as long as category exist,
* And will be the right value after zlog_reload()
*
* For speed up, if one log will not be output,
* There is no need to aquire rdlock.
*/
pthread_rwlock_rdlock(&zlog_env_lock);
if (zlog_category_needless_level(category, level)) goto exit;
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
goto exit;
}
zlog_fetch_thread(a_thread, exit);
zlog_event_set_fmt(a_thread->event,
category->name, category->name_len,
file, filelen, func, funclen, line, level,
format, args);
if (zlog_category_output(category, a_thread)) {
zc_error("zlog_output fail, srcfile[%s], srcline[%ld]", file, line);
goto exit;
}
if (zlog_env_conf->reload_conf_period &&
++zlog_env_reload_conf_count > zlog_env_conf->reload_conf_period ) {
/* under the protection of lock read env conf */
goto reload;
}
exit:
pthread_rwlock_unlock(&zlog_env_lock);
return;
reload:
pthread_rwlock_unlock(&zlog_env_lock);
/* will be wrlock, so after unlock */
if (zlog_reload((char *)-1)) {
zc_error("reach reload-conf-period but zlog_reload fail, zlog-chk-conf [file] see detail");
}
return;
}
void hzlog(zlog_category_t *category,
const char *file, size_t filelen,
const char *func, size_t funclen,
long line, int level,
const void *buf, size_t buflen)
{
zlog_thread_t *a_thread;
pthread_rwlock_rdlock(&zlog_env_lock);
if (zlog_category_needless_level(category, level)) goto exit;
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
goto exit;
}
zlog_fetch_thread(a_thread, exit);
zlog_event_set_hex(a_thread->event,
category->name, category->name_len,
file, filelen, func, funclen, line, level,
buf, buflen);
if (zlog_category_output(category, a_thread)) {
zc_error("zlog_output fail, srcfile[%s], srcline[%ld]", file, line);
goto exit;
}
if (zlog_env_conf->reload_conf_period &&
++zlog_env_reload_conf_count > zlog_env_conf->reload_conf_period ) {
/* under the protection of lock read env conf */
goto reload;
}
exit:
pthread_rwlock_unlock(&zlog_env_lock);
return;
reload:
pthread_rwlock_unlock(&zlog_env_lock);
/* will be wrlock, so after unlock */
if (zlog_reload((char *)-1)) {
zc_error("reach reload-conf-period but zlog_reload fail, zlog-chk-conf [file] see detail");
}
return;
}
/*******************************************************************************/
/* for speed up, copy from vzlog */
void vdzlog(const char *file, size_t filelen,
const char *func, size_t funclen,
long line, int level,
const char *format, va_list args)
{
zlog_thread_t *a_thread;
pthread_rwlock_rdlock(&zlog_env_lock);
if (zlog_category_needless_level(zlog_default_category, level)) goto exit;
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
goto exit;
}
/* that's the differnce, must judge default_category in lock */
if (!zlog_default_category) {
zc_error("zlog_default_category is null,"
"dzlog_init() or dzlog_set_cateogry() is not called above");
goto exit;
}
zlog_fetch_thread(a_thread, exit);
zlog_event_set_fmt(a_thread->event,
zlog_default_category->name, zlog_default_category->name_len,
file, filelen, func, funclen, line, level,
format, args);
if (zlog_category_output(zlog_default_category, a_thread)) {
zc_error("zlog_output fail, srcfile[%s], srcline[%ld]", file, line);
goto exit;
}
if (zlog_env_conf->reload_conf_period &&
++zlog_env_reload_conf_count > zlog_env_conf->reload_conf_period ) {
/* under the protection of lock read env conf */
goto reload;
}
exit:
pthread_rwlock_unlock(&zlog_env_lock);
return;
reload:
pthread_rwlock_unlock(&zlog_env_lock);
/* will be wrlock, so after unlock */
if (zlog_reload((char *)-1)) {
zc_error("reach reload-conf-period but zlog_reload fail, zlog-chk-conf [file] see detail");
}
return;
}
void hdzlog(const char *file, size_t filelen,
const char *func, size_t funclen,
long line, int level,
const void *buf, size_t buflen)
{
zlog_thread_t *a_thread;
pthread_rwlock_rdlock(&zlog_env_lock);
if (zlog_category_needless_level(zlog_default_category, level)) goto exit;
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
goto exit;
}
/* that's the differnce, must judge default_category in lock */
if (!zlog_default_category) {
zc_error("zlog_default_category is null,"
"dzlog_init() or dzlog_set_cateogry() is not called above");
goto exit;
}
zlog_fetch_thread(a_thread, exit);
zlog_event_set_hex(a_thread->event,
zlog_default_category->name, zlog_default_category->name_len,
file, filelen, func, funclen, line, level,
buf, buflen);
if (zlog_category_output(zlog_default_category, a_thread)) {
zc_error("zlog_output fail, srcfile[%s], srcline[%ld]", file, line);
goto exit;
}
if (zlog_env_conf->reload_conf_period &&
++zlog_env_reload_conf_count > zlog_env_conf->reload_conf_period ) {
/* under the protection of lock read env conf */
goto reload;
}
exit:
pthread_rwlock_unlock(&zlog_env_lock);
return;
reload:
pthread_rwlock_unlock(&zlog_env_lock);
/* will be wrlock, so after unlock */
if (zlog_reload((char *)-1)) {
zc_error("reach reload-conf-period but zlog_reload fail, zlog-chk-conf [file] see detail");
}
return;
}
/*******************************************************************************/
void zlog(zlog_category_t * category,
const char *file, size_t filelen, const char *func, size_t funclen,
long line, const int level,
const char *format, ...)
{
zlog_thread_t *a_thread;
va_list args;
pthread_rwlock_rdlock(&zlog_env_lock);
if (category && zlog_category_needless_level(category, level)) goto exit;
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
goto exit;
}
zlog_fetch_thread(a_thread, exit);
va_start(args, format);
zlog_event_set_fmt(a_thread->event, category->name, category->name_len,
file, filelen, func, funclen, line, level,
format, args);
if (zlog_category_output(category, a_thread)) {
zc_error("zlog_output fail, srcfile[%s], srcline[%ld]", file, line);
va_end(args);
goto exit;
}
va_end(args);
if (zlog_env_conf->reload_conf_period &&
++zlog_env_reload_conf_count > zlog_env_conf->reload_conf_period ) {
/* under the protection of lock read env conf */
goto reload;
}
exit:
pthread_rwlock_unlock(&zlog_env_lock);
return;
reload:
pthread_rwlock_unlock(&zlog_env_lock);
/* will be wrlock, so after unlock */
if (zlog_reload((char *)-1)) {
zc_error("reach reload-conf-period but zlog_reload fail, zlog-chk-conf [file] see detail");
}
return;
}
/*******************************************************************************/
void dzlog(const char *file, size_t filelen, const char *func, size_t funclen, long line, int level,
const char *format, ...)
{
zlog_thread_t *a_thread;
va_list args;
pthread_rwlock_rdlock(&zlog_env_lock);
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
goto exit;
}
/* that's the differnce, must judge default_category in lock */
if (!zlog_default_category) {
zc_error("zlog_default_category is null,"
"dzlog_init() or dzlog_set_cateogry() is not called above");
goto exit;
}
if (zlog_category_needless_level(zlog_default_category, level)) goto exit;
zlog_fetch_thread(a_thread, exit);
va_start(args, format);
zlog_event_set_fmt(a_thread->event,
zlog_default_category->name, zlog_default_category->name_len,
file, filelen, func, funclen, line, level,
format, args);
if (zlog_category_output(zlog_default_category, a_thread)) {
zc_error("zlog_output fail, srcfile[%s], srcline[%ld]", file, line);
va_end(args);
goto exit;
}
va_end(args);
if (zlog_env_conf->reload_conf_period &&
++zlog_env_reload_conf_count > zlog_env_conf->reload_conf_period ) {
/* under the protection of lock read env conf */
goto reload;
}
exit:
pthread_rwlock_unlock(&zlog_env_lock);
return;
reload:
pthread_rwlock_unlock(&zlog_env_lock);
/* will be wrlock, so after unlock */
if (zlog_reload((char *)-1)) {
zc_error("reach reload-conf-period but zlog_reload fail, zlog-chk-conf [file] see detail");
}
return;
}
/*******************************************************************************/
void zlog_profile(void)
{
int rc = 0;
rc = pthread_rwlock_rdlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc);
return;
}
zc_warn("------zlog_profile start------ ");
zc_warn("is init:[%d]", zlog_env_is_init);
zc_warn("init version:[%d]", zlog_env_init_version);
zlog_conf_profile(zlog_env_conf, ZC_WARN);
zlog_record_table_profile(zlog_env_records, ZC_WARN);
zlog_category_table_profile(zlog_env_categories, ZC_WARN);
if (zlog_default_category) {
zc_warn("-default_category-");
zlog_category_profile(zlog_default_category, ZC_WARN);
}
zc_warn("------zlog_profile end------ ");
rc = pthread_rwlock_unlock(&zlog_env_lock);
if (rc) {
zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc);
return;
}
return;
}
/*******************************************************************************/
int zlog_set_record(const char *rname, zlog_record_fn record_output)
{
int rc = 0;
int rd = 0;
zlog_rule_t *a_rule;
zlog_record_t *a_record;
int i = 0;
zc_assert(rname, -1);
zc_assert(record_output, -1);
rd = pthread_rwlock_wrlock(&zlog_env_lock);
if (rd) {
zc_error("pthread_rwlock_rdlock fail, rd[%d]", rd);
return -1;
}
if (!zlog_env_is_init) {
zc_error("never call zlog_init() or dzlog_init() before");
goto zlog_set_record_exit;
}
a_record = zlog_record_new(rname, record_output);
if (!a_record) {
rc = -1;
zc_error("zlog_record_new fail");
goto zlog_set_record_exit;
}
rc = zc_hashtable_put(zlog_env_records, a_record->name, a_record);
if (rc) {
zlog_record_del(a_record);
zc_error("zc_hashtable_put fail");
goto zlog_set_record_exit;
}
zc_arraylist_foreach(zlog_env_conf->rules, i, a_rule) {
zlog_rule_set_record(a_rule, zlog_env_records);
}
zlog_set_record_exit:
rd = pthread_rwlock_unlock(&zlog_env_lock);
if (rd) {
zc_error("pthread_rwlock_unlock fail, rd=[%d]", rd);
return -1;
}
return rc;
}
/*******************************************************************************/
int zlog_level_enabled(zlog_category_t *category, const int level)
{
int enable = 0;
pthread_rwlock_rdlock(&zlog_env_lock);
enable = category && ((zlog_category_needless_level(category, level) == 0));
pthread_rwlock_unlock(&zlog_env_lock);
return enable;
}
int dzlog_level_enabled(const int level)
{
return zlog_level_enabled(zlog_default_category, level);
}
const char *zlog_version(void) { return ZLOG_VERSION; }
/* Copyright (c) Hardy Simpson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __zlog_h
#define __zlog_h
#ifdef __cplusplus
extern "C" {
#endif
#include <stdarg.h> /* for va_list */
#include <stdio.h> /* for size_t */
# if defined __GNUC__
# define ZLOG_CHECK_PRINTF(m,n) __attribute__((format(printf,m,n)))
# else
# define ZLOG_CHECK_PRINTF(m,n)
# endif
typedef struct zlog_category_s zlog_category_t;
int zlog_init(const char *config);
int zlog_init_from_string(const char *config_string);
int zlog_reload(const char *config);
int zlog_reload_from_string(const char *conf_string);
void zlog_fini(void);
void zlog_profile(void);
zlog_category_t *zlog_get_category(const char *cname);
int zlog_level_enabled(zlog_category_t *category, const int level);
int zlog_put_mdc(const char *key, const char *value);
char *zlog_get_mdc(const char *key);
void zlog_remove_mdc(const char *key);
void zlog_clean_mdc(void);
int zlog_level_switch(zlog_category_t * category, int level);
int zlog_level_enabled(zlog_category_t * category, int level);
void zlog(zlog_category_t * category,
const char *file, size_t filelen,
const char *func, size_t funclen,
long line, int level,
const char *format, ...) ZLOG_CHECK_PRINTF(8,9);
void vzlog(zlog_category_t * category,
const char *file, size_t filelen,
const char *func, size_t funclen,
long line, int level,
const char *format, va_list args);
void hzlog(zlog_category_t * category,
const char *file, size_t filelen,
const char *func, size_t funclen,
long line, int level,
const void *buf, size_t buflen);
int dzlog_init(const char *confpath, const char *cname);
int dzlog_set_category(const char *cname);
int dzlog_level_enabled(const int level);
void dzlog(const char *file, size_t filelen,
const char *func, size_t funclen,
long line, int level,
const char *format, ...) ZLOG_CHECK_PRINTF(7,8);
void vdzlog(const char *file, size_t filelen,
const char *func, size_t funclen,
long line, int level,
const char *format, va_list args);
void hdzlog(const char *file, size_t filelen,
const char *func, size_t funclen,
long line, int level,
const void *buf, size_t buflen);
typedef struct zlog_msg_s {
char *buf;
size_t len;
char *path;
} zlog_msg_t;
typedef int (*zlog_record_fn)(zlog_msg_t *msg);
int zlog_set_record(const char *rname, zlog_record_fn record);
const char *zlog_version(void);
/******* useful macros, can be redefined at user's h file **********/
typedef enum {
ZLOG_LEVEL_DEBUG = 20,
ZLOG_LEVEL_INFO = 40,
ZLOG_LEVEL_NOTICE = 60,
ZLOG_LEVEL_WARN = 80,
ZLOG_LEVEL_ERROR = 100,
ZLOG_LEVEL_FATAL = 120
} zlog_level;
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
# if defined __GNUC__ && __GNUC__ >= 2
# define __func__ __FUNCTION__
# else
# define __func__ "<unknown>"
# endif
#endif
#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
/* zlog macros */
#define zlog_fatal(cat, ...) \
zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_FATAL, __VA_ARGS__)
#define zlog_error(cat, ...) \
zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_ERROR, __VA_ARGS__)
#define zlog_warn(cat, ...) \
zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_WARN, __VA_ARGS__)
#define zlog_notice(cat, ...) \
zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_NOTICE, __VA_ARGS__)
#define zlog_info(cat, ...) \
zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_INFO, __VA_ARGS__)
#define zlog_debug(cat, ...) \
zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_DEBUG, __VA_ARGS__)
/* dzlog macros */
#define dzlog_fatal(...) \
dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_FATAL, __VA_ARGS__)
#define dzlog_error(...) \
dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_ERROR, __VA_ARGS__)
#define dzlog_warn(...) \
dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_WARN, __VA_ARGS__)
#define dzlog_notice(...) \
dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_NOTICE, __VA_ARGS__)
#define dzlog_info(...) \
dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_INFO, __VA_ARGS__)
#define dzlog_debug(...) \
dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_DEBUG, __VA_ARGS__)
#elif defined __GNUC__
/* zlog macros */
#define zlog_fatal(cat, format, args...) \
zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_FATAL, format, ##args)
#define zlog_error(cat, format, args...) \
zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_ERROR, format, ##args)
#define zlog_warn(cat, format, args...) \
zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_WARN, format, ##args)
#define zlog_notice(cat, format, args...) \
zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_NOTICE, format, ##args)
#define zlog_info(cat, format, args...) \
zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_INFO, format, ##args)
#define zlog_debug(cat, format, args...) \
zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_DEBUG, format, ##args)
/* dzlog macros */
#define dzlog_fatal(format, args...) \
dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_FATAL, format, ##args)
#define dzlog_error(format, args...) \
dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_ERROR, format, ##args)
#define dzlog_warn(format, args...) \
dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_WARN, format, ##args)
#define dzlog_notice(format, args...) \
dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_NOTICE, format, ##args)
#define dzlog_info(format, args...) \
dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_INFO, format, ##args)
#define dzlog_debug(format, args...) \
dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_DEBUG, format, ##args)
#endif
/* vzlog macros */
#define vzlog_fatal(cat, format, args) \
vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_FATAL, format, args)
#define vzlog_error(cat, format, args) \
vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_ERROR, format, args)
#define vzlog_warn(cat, format, args) \
vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_WARN, format, args)
#define vzlog_notice(cat, format, args) \
vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_NOTICE, format, args)
#define vzlog_info(cat, format, args) \
vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_INFO, format, args)
#define vzlog_debug(cat, format, args) \
vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_DEBUG, format, args)
/* hzlog macros */
#define hzlog_fatal(cat, buf, buf_len) \
hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_FATAL, buf, buf_len)
#define hzlog_error(cat, buf, buf_len) \
hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_ERROR, buf, buf_len)
#define hzlog_warn(cat, buf, buf_len) \
hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_WARN, buf, buf_len)
#define hzlog_notice(cat, buf, buf_len) \
hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_NOTICE, buf, buf_len)
#define hzlog_info(cat, buf, buf_len) \
hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_INFO, buf, buf_len)
#define hzlog_debug(cat, buf, buf_len) \
hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_DEBUG, buf, buf_len)
/* vdzlog macros */
#define vdzlog_fatal(format, args) \
vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_FATAL, format, args)
#define vdzlog_error(format, args) \
vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_ERROR, format, args)
#define vdzlog_warn(format, args) \
vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_WARN, format, args)
#define vdzlog_notice(format, args) \
vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_NOTICE, format, args)
#define vdzlog_info(format, args) \
vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_INFO, format, args)
#define vdzlog_debug(format, args) \
vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_DEBUG, format, args)
/* hdzlog macros */
#define hdzlog_fatal(buf, buf_len) \
hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_FATAL, buf, buf_len)
#define hdzlog_error(buf, buf_len) \
hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_ERROR, buf, buf_len)
#define hdzlog_warn(buf, buf_len) \
hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_WARN, buf, buf_len)
#define hdzlog_notice(buf, buf_len) \
hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_NOTICE, buf, buf_len)
#define hdzlog_info(buf, buf_len) \
hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_INFO, buf, buf_len)
#define hdzlog_debug(buf, buf_len) \
hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \
ZLOG_LEVEL_DEBUG, buf, buf_len)
/* enabled macros */
#define zlog_fatal_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_FATAL)
#define zlog_error_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_ERROR)
#define zlog_warn_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_WARN)
#define zlog_notice_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_NOTICE)
#define zlog_info_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_INFO)
#define zlog_debug_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_DEBUG)
#ifdef __cplusplus
}
#endif
#endif
#include <string.h>
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <stdlib.h>
#include "zlog_win.h"
#include <errno.h>
#include <unistd.h>
int gethostname_w(char *name, size_t len)
{
int rc = gethostname(name, len);
DWORD newlen = len;
if (rc != 0) {
rc = GetComputerNameEx(ComputerNameDnsHostname, name, &newlen);
if (rc == 0) {
sprintf(name, "noname");
}
}
return 0;
}
#ifndef strcasecmp
int strcasecmp (const char *sz1, const char *sz2)
{
return stricmp (sz1, sz2);
}
#endif
#ifndef localtime_r
struct tm *localtime_r(const time_t *timep, struct tm *result)
{
struct tm *ret = localtime(timep);
if (ret)
{
memcpy(result, ret, sizeof(struct tm));
}
return ret;
}
#endif
int fsync (int fd)
{
HANDLE h = (HANDLE) _get_osfhandle (fd);
DWORD err;
if (h == INVALID_HANDLE_VALUE)
{
errno = EBADF;
return -1;
}
if (!FlushFileBuffers (h))
{
/* Translate some Windows errors into rough approximations of Unix
* errors. MSDN is useless as usual - in this case it doesn't
* document the full range of errors.
*/
err = GetLastError ();
switch (err)
{
/* eg. Trying to fsync a tty. */
case ERROR_INVALID_HANDLE:
errno = EINVAL;
break;
default:
errno = EIO;
}
return -1;
}
return 0;
}
void setenv(const char *name, const char *value)
{
#ifdef HAVE_SETENV
setenv(name, value, 1);
#else
int len = strlen(value)+1+strlen(value)+1;
char *str = malloc(len);
sprintf(str, "%s=%s", name, value);
putenv(str);
#endif
}
#ifndef _ZLOG_WIN_H_
#define _ZLOG_WIN_H_
#include <time.h>
#ifndef localtime_r
struct tm *localtime_r(const time_t *timep, struct tm *result);
#endif
#ifndef strcasecmp
int strcasecmp (const char *sz1, const char *sz2);
#endif
int fsync (int fd);
void setenv(const char *name, const char *value);
int gethostname_w(char *name, size_t len);
/* facility codes */
#define LOG_KERN (0<<3) /* kernel messages */
#define LOG_USER (1<<3) /* random user-level messages */
#define LOG_MAIL (2<<3) /* mail system */
#define LOG_DAEMON (3<<3) /* system daemons */
#define LOG_AUTH (4<<3) /* authorization messages */
#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */
#define LOG_LPR (6<<3) /* line printer subsystem */
#define LOG_NEWS (7<<3) /* network news subsystem */
#define LOG_UUCP (8<<3) /* UUCP subsystem */
#define LOG_CRON (9<<3) /* clock daemon */
#define LOG_AUTHPRIV (10<<3) /* authorization messages (private) */
/* Facility #10 clashes in DEC UNIX, where */
/* it's defined as LOG_MEGASAFE for AdvFS */
/* event logging. */
#define LOG_FTP (11<<3) /* ftp daemon */
#define LOG_NTP (12<<3) /* NTP subsystem */
#define LOG_SECURITY (13<<3) /* security subsystems (firewalling, etc.) */
#define LOG_CONSOLE (14<<3) /* /dev/console output */
/* other codes through 15 reserved for system use */
#define LOG_LOCAL0 (16<<3) /* reserved for local use */
#define LOG_LOCAL1 (17<<3) /* reserved for local use */
#define LOG_LOCAL2 (18<<3) /* reserved for local use */
#define LOG_LOCAL3 (19<<3) /* reserved for local use */
#define LOG_LOCAL4 (20<<3) /* reserved for local use */
#define LOG_LOCAL5 (21<<3) /* reserved for local use */
#define LOG_LOCAL6 (22<<3) /* reserved for local use */
#define LOG_LOCAL7 (23<<3) /* reserved for local use */
/*
* Option flags for openlog.
*
* LOG_ODELAY no longer does anything.
* LOG_NDELAY is the inverse of what it used to be.
*/
#define LOG_PID 0x01 /* log the pid with each message */
#define LOG_CONS 0x02 /* log on the console if errors in sending */
#define LOG_ODELAY 0x04 /* delay open until first syslog() (default) */
#define LOG_NDELAY 0x08 /* don't delay open */
#define LOG_NOWAIT 0x10 /* don't wait for console forks: DEPRECATED */
#define LOG_PERROR 0x20 /* log to stderr as well */
/*
* priorities/facilities are encoded into a single 32-bit quantity, where the
* bottom 3 bits are the priority (0-7) and the top 28 bits are the facility
* (0-big number). Both the priorities and the facilities map roughly
* one-to-one to strings in the syslogd(8) source code. This mapping is
* included in this file.
*
* priorities (these are ordered)
*/
#define LOG_EMERG 0 /* system is unusable */
#define LOG_ALERT 1 /* action must be taken immediately */
#define LOG_CRIT 2 /* critical conditions */
#define LOG_ERR 3 /* error conditions */
#define LOG_WARNING 4 /* warning conditions */
#define LOG_NOTICE 5 /* normal but significant condition */
#define LOG_INFO 6 /* informational */
#define LOG_DEBUG 7 /* debug-level messages */
#define LOG_PRIMASK 0x07 /* mask to extract priority part (internal) */
/* extract priority */
#define LOG_PRI(p) ((p) & LOG_PRIMASK)
#define LOG_MAKEPRI(fac, pri) ((fac) | (pri))
#endif
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment