blob: d3ca6f1c307a4de616102c5aef1871d096c0601a [file] [log] [blame]
#include <stdarg.h>
#include <stdio.h>
#include <syslog.h>
#include <haproxy/api.h>
#include <haproxy/applet-t.h>
#include <haproxy/cli.h>
#include <haproxy/errors.h>
#include <haproxy/global.h>
#include <haproxy/ring.h>
#include <haproxy/tools.h>
#include <haproxy/version.h>
/* A global buffer used to store all startup alerts/warnings. It will then be
* retrieve on the CLI. */
static struct ring *startup_logs = NULL;
/* Generic function to display messages prefixed by a label */
static void print_message(const char *label, const char *fmt, va_list argp)
{
char *head, *msg;
char prefix[11]; // '[' + 8 chars + ']' + 0.
*prefix = '[';
strncpy(prefix + 1, label, sizeof(prefix) - 2);
msg = prefix + strlen(prefix);
*msg++ = ']';
while (msg < prefix + sizeof(prefix) - 1)
*msg++ = ' ';
*msg = 0;
head = msg = NULL;
memprintf(&head, "%s (%u) : ", prefix, (uint)getpid());
memvprintf(&msg, fmt, argp);
if (global.mode & MODE_STARTING) {
if (unlikely(!startup_logs))
startup_logs = ring_new(STARTUP_LOG_SIZE);
if (likely(startup_logs)) {
struct ist m[2];
m[0] = ist(head);
m[1] = ist(msg);
/* trim the trailing '\n' */
if (m[1].len > 0 && m[1].ptr[m[1].len - 1] == '\n')
m[1].len--;
ring_write(startup_logs, ~0, 0, 0, m, 2);
}
}
fprintf(stderr, "%s%s", head, msg);
fflush(stderr);
free(head);
free(msg);
}
/*
* Displays the message on stderr with the date and pid. Overrides the quiet
* mode during startup.
*/
void ha_alert(const char *fmt, ...)
{
va_list argp;
if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
if (!(warned & WARN_EXEC_PATH)) {
const char *path = get_exec_path();
warned |= WARN_EXEC_PATH;
ha_notice("haproxy version is %s\n", haproxy_version);
if (path)
ha_notice("path to executable is %s\n", path);
}
va_start(argp, fmt);
print_message("ALERT", fmt, argp);
va_end(argp);
}
}
/*
* Displays the message on stderr with the date and pid.
*/
void ha_warning(const char *fmt, ...)
{
va_list argp;
warned |= WARN_ANY;
if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
va_start(argp, fmt);
print_message("WARNING", fmt, argp);
va_end(argp);
}
}
/*
* Variant of _ha_diag_warning with va_list.
* Use it only if MODE_DIAG has been previously checked.
*/
void _ha_vdiag_warning(const char *fmt, va_list argp)
{
print_message("DIAG", fmt, argp);
}
/*
* Output a diagnostic warning.
* Use it only if MODE_DIAG has been previously checked.
*/
void _ha_diag_warning(const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
_ha_vdiag_warning(fmt, argp);
va_end(argp);
}
/*
* Output a diagnostic warning. Do nothing of MODE_DIAG is not on.
*/
void ha_diag_warning(const char *fmt, ...)
{
va_list argp;
if (global.mode & MODE_DIAG) {
va_start(argp, fmt);
_ha_vdiag_warning(fmt, argp);
va_end(argp);
}
}
/*
* Displays the message on stderr with the date and pid.
*/
void ha_notice(const char *fmt, ...)
{
va_list argp;
if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
va_start(argp, fmt);
print_message("NOTICE", fmt, argp);
va_end(argp);
}
}
/*
* Displays the message on <out> only if quiet mode is not set.
*/
void qfprintf(FILE *out, const char *fmt, ...)
{
va_list argp;
if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
va_start(argp, fmt);
vfprintf(out, fmt, argp);
fflush(out);
va_end(argp);
}
}
/* parse the "show startup-logs" command, returns 1 if a message is returned, otherwise zero */
static int cli_parse_show_startup_logs(char **args, char *payload, struct appctx *appctx, void *private)
{
if (!cli_has_level(appctx, ACCESS_LVL_OPER))
return 1;
if (!startup_logs)
return cli_msg(appctx, LOG_INFO, "\n"); // nothing to print
return ring_attach_cli(startup_logs, appctx);
}
/* register cli keywords */
static struct cli_kw_list cli_kws = {{ },{
{ { "show", "startup-logs", NULL }, "show startup-logs : report logs emitted during HAProxy startup", cli_parse_show_startup_logs, NULL, NULL },
{{},}
}};
INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
static void deinit_errors_buffers()
{
ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
}
REGISTER_PER_THREAD_FREE(deinit_errors_buffers);