All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Verma, Vishal L" <vishal.l.verma@intel.com>
To: "linux-nvdimm@lists.01.org" <linux-nvdimm@lists.01.org>,
	"qi.fuli@jp.fujitsu.com" <qi.fuli@jp.fujitsu.com>
Cc: "tokunaga.keiich@jp.fujitsu.com" <tokunaga.keiich@jp.fujitsu.com>
Subject: Re: [ndctl PATCH v12 1/5] ndctl, monitor: add a new command - monitor
Date: Fri, 13 Jul 2018 18:58:12 +0000	[thread overview]
Message-ID: <1531508290.7574.138.camel@intel.com> (raw)
In-Reply-To: <20180713155403.30020-2-qi.fuli@jp.fujitsu.com>

Hi Qi,

On Sat, 2018-07-14 at 00:53 +0900, QI Fuli wrote:
> Ndctl monitor is used for monitoring the smart events of NVDIMMs.
> When a smart event fires, monitor will output the notifications which
> include dimm health status and event information to syslog, standard
> output or a file by setting [--log] option. The notifications follow
> json format and can be consumed by log collectors like Fluentd.
> 
> The objects to monitor can be selected by setting [--dimm] [--region]
> [--namespace] [--bus] options and the event type can be filtered by
> setting [--dimm-event] option. These options support multiple
> space-separated arguments.
> 
> Ndctl monitor can be forked as a daemon by using [--daemon] option,
> such as:
>    # ndctl monitor --daemon --log /var/log/ndctl/monitor.log
> 
> Signed-off-by: QI Fuli <qi.fuli@jp.fujitsu.com>
> ---
>  builtin.h              |   1 +
>  ndctl/Makefile.am      |   3 +-
>  ndctl/lib/libndctl.c   |  82 +++++++
>  ndctl/lib/libndctl.sym |   4 +
>  ndctl/libndctl.h       |  10 +
>  ndctl/monitor.c        | 539 +++++++++++++++++++++++++++++++++++++++++
>  ndctl/ndctl.c          |   1 +
>  util/filter.h          |   9 +
>  8 files changed, 648 insertions(+), 1 deletion(-)
>  create mode 100644 ndctl/monitor.c
> 

[..]

> +
> +#define fail(fmt, ...) \
> +do { \
> +	did_fail = 1; \
> +	dbg(ctx, "ndctl-%s:%s:%d: " fmt, \
> +			VERSION, __func__, __LINE__, ##__VA_ARGS__); \
> +} while (0)
> +
> +static void log_syslog(struct ndctl_ctx *ctx, int priority, const char *file,
> +		int line, const char *fn, const char *format, va_list args)
> +{
> +	char *buf;
> +
> +	if (vasprintf(&buf, format, args) < 0) {
> +		fail("vasprintf error\n");
> +		return;
> +	}
> +	syslog(priority, "%s\n", buf);

I think from each of the log functions, we should remove the '\n'.
Currently, this results in an extra newline for error messages like
unsupported dimms. For consistency, the newline is always added at the
'top level' when the string is being composed. All functions that pass
through or handle the string later shouldn't add newlines.

It is ok for the error messages in this function to have newlines, like
in the "vasprintf error" case.

> +
> +	free(buf);
> +	return;
> +}
> +
> +static void log_standard(struct ndctl_ctx *ctx, int priority, const char *file,
> +		int line, const char *fn, const char *format, va_list args)
> +{
> +	char *buf;
> +
> +	if (vasprintf(&buf, format, args) < 0) {
> +		fail("vasprintf error\n");
> +		return;
> +	}
> +
> +	if (priority == 6)
> +		fprintf(stdout, "%s\n", buf);
> +	else
> +		fprintf(stderr, "%s\n", buf);

Same as above for both fprintf statements.

> +
> +	free(buf);
> +	return;
> +}
> +
> +static void log_file(struct ndctl_ctx *ctx, int priority, const char *file,
> +		int line, const char *fn, const char *format, va_list args)
> +{
> +	FILE *f;
> +	char *buf;
> +
> +	if (vasprintf(&buf, format, args) < 0) {
> +		fail("vasprintf error\n");
> +		return;
> +	}
> +
> +	f = fopen(monitor.log, "a+");
> +	if (!f) {
> +		ndctl_set_log_fn(ctx, log_syslog);
> +		fail("open logfile %s failed\n%s", monitor.log, buf);
> +		goto end;
> +	}
> +	fprintf(f, "%s\n", buf);

Same as above.

> +	fflush(f);
> +	fclose(f);
> +end:
> +	free(buf);
> +	return;
> +}
> +

[..]

> +
> +static int notify_dimm_event(struct monitor_dimm *mdimm)
> +{
> +	struct json_object *jmsg, *jdimm, *jobj;
> +	struct timespec ts;
> +	char timestamp[32];
> +	struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(mdimm->dimm);
> +
> +	jmsg = json_object_new_object();
> +	if (!jmsg) {
> +		fail("\n");
> +		return -1;
> +	}
> +
> +	clock_gettime(CLOCK_REALTIME, &ts);
> +	sprintf(timestamp, "%10ld.%09ld", ts.tv_sec, ts.tv_nsec);
> +	jobj = json_object_new_string(timestamp);
> +	if (!jobj) {
> +		fail("\n");
> +		return -1;
> +	}
> +	json_object_object_add(jmsg, "timestamp", jobj);
> +
> +	jobj = json_object_new_int(getpid());
> +	if (!jobj) {
> +		fail("\n");
> +		return -1;
> +	}
> +	json_object_object_add(jmsg, "pid", jobj);
> +
> +	jobj = dimm_event_to_json(mdimm);
> +	if (!jobj) {
> +		fail("\n");
> +		return -1;
> +	}
> +	json_object_object_add(jmsg, "event", jobj);
> +
> +	jdimm = util_dimm_to_json(mdimm->dimm, 0);
> +	if (!jdimm) {
> +		fail("\n");
> +		return -1;
> +	}
> +	json_object_object_add(jmsg, "dimm", jdimm);
> +
> +	jobj = util_dimm_health_to_json(mdimm->dimm);
> +	if (!jobj) {
> +		fail("\n");
> +		return -1;
> +	}
> +	json_object_object_add(jdimm, "health", jobj);
> +
> +	if (monitor.human)
> +		notice(ctx, "%s", json_object_to_json_string_ext(jmsg,
> +						JSON_C_TO_STRING_PRETTY));
> +	else
> +		notice(ctx, "%s", json_object_to_json_string_ext(jmsg,
> +						JSON_C_TO_STRING_PLAIN));

And since the log functions no longer add newlines, these notice()
strings should have a newline.

> +
> +	free(jobj);
> +	free(jdimm);
> +	free(jmsg);
> +	return 0;
> +}
> +

[..]

> +int cmd_monitor(int argc, const char **argv, void *ctx)
> +{
> +	const struct option options[] = {
> +		OPT_STRING('b', "bus", &param.bus, "bus-id", "filter by bus"),
> +		OPT_STRING('r', "region", &param.region, "region-id",
> +				"filter by region"),
> +		OPT_STRING('d', "dimm", &param.dimm, "dimm-id",
> +				"filter by dimm"),
> +		OPT_STRING('n', "namespace", &param.namespace,
> +				"namespace-id", "filter by namespace id"),
> +		OPT_STRING('D', "dimm-event", &monitor.dimm_event,
> +			"name of event type", "filter by DIMM event type"),
> +		OPT_FILENAME('l', "log", &monitor.log,
> +				"<file> | syslog | standard",
> +				"where to output the monitor's notification"),
> +		OPT_BOOLEAN('x', "daemon", &monitor.daemon,
> +				"run ndctl monitor as a daemon"),
> +		OPT_BOOLEAN('u', "human", &monitor.human,
> +				"use human friendly output formats"),
> +		OPT_END(),
> +	};
> +	const char * const u[] = {
> +		"ndctl monitor [<options>]",
> +		NULL
> +	};
> +	const char *prefix = "./";
> +	struct util_filter_ctx fctx = { 0 };
> +	struct monitor_filter_arg mfa = { 0 };
> +	int i;
> +
> +	argc = parse_options_prefix(argc, argv, prefix, options, u, 0);
> +	for (i = 0; i < argc; i++) {
> +		error("unknown parameter \"%s\"\n", argv[i]);
> +	}
> +	if (argc)
> +		usage_with_options(u, options);
> +
> +	ndctl_set_log_fn((struct ndctl_ctx *)ctx, log_standard);
> +	ndctl_set_log_priority((struct ndctl_ctx *)ctx, LOG_NOTICE);
> +
> +	if (monitor.log) {

I think you were trying to special case the option of ./syslog and
./standard so that they are treated as files (but I'm not sure that's
needed?)

> +		if (strcmp(monitor.log, "./syslog") == 0)
> +			ndctl_set_log_fn((struct ndctl_ctx *)ctx, log_syslog);

I think this is broken as we need 'syslog' to select log_syslog, and
not './syslog'

> +		else if (strcmp(monitor.log, "./standard") != 0)
> +			ndctl_set_log_fn((struct ndctl_ctx *)ctx, log_file);

I think the flow we want here is:

	/* default to log_standard */
	ndctl_set_log_fn((struct ndctl_ctx *)ctx, log_standard);
	ndctl_set_log_priority((struct ndctl_ctx *)ctx, LOG_NOTICE);

	if (monitor.log) {
		/*
		 * we have to add a './' prefix to the comparisons
		 * as fix_filename adds it to monitor.log for us
		 */
		if (strncmp(monitor.log, "./syslog", 8) == 0)
			ndctl_set_log_fn((struct ndctl_ctx *)ctx, log_syslog);
		else if (strncmp(monitor.log, "./standard", 10) == 0)
			; /* default, already set */
		else
			ndctl_set_log_fn((struct ndctl_ctx *)ctx, log_file);
	}

The final log_file case should be a catch-all for anything supplied
that is not exactly 'syslog' or 'standard'. Note that I used strncmp
instead of strcmp to match exactly.

This does mean that if someone supplies "./syslog" intending to write
to a file called syslog in the current directory, it will instead log
to syslog. But I think that is fine, it can be documented as  a quirk
of the option parsing code (parse_options_prefix adds the './' prefix
via fix_filename for OPTION_FILENAME). If they do want a file called
'syslog' or 'standard' they can specify it as an absolute path
(starting with '/'), and fix_filename won't touch it.

> +	}
> +
> +	if (monitor.daemon) {
> +		if (daemon(0, 0) != 0) {
> +			err((struct ndctl_ctx *)ctx, "daemon start failed\n");
> +			goto out;
> +		}
> +		notice((struct ndctl_ctx *)ctx, "ndctl monitor daemon started\n");
> +	}
> +
> +	if (parse_monitor_event(&monitor))
> +		goto out;
> +
> +	fctx.filter_bus = filter_bus;
> +	fctx.filter_dimm = filter_dimm;
> +	fctx.filter_region = filter_region;
> +	fctx.filter_namespace = NULL;
> +	fctx.arg = &mfa;
> +	list_head_init(&mfa.dimms);
> +	mfa.num_dimm = 0;
> +	mfa.maxfd_dimm = -1;
> +	mfa.flags = 0;
> +
> +	if (util_filter_walk(ctx, &fctx, &param))
> +		goto out;
> +
> +	if (!mfa.num_dimm) {
> +		err((struct ndctl_ctx *)ctx, "no dimms to monitor\n");
> +		goto out;
> +	}
> +
> +	if (monitor_event(ctx, &mfa))
> +		goto out;
> +
> +	return 0;
> +out:
> +	return 1;
> +}
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm

  reply	other threads:[~2018-07-13 18:58 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-13 15:53 [ndctl PATCH v12 0/5] ndctl, monitor: add ndctl monitor daemon QI Fuli
2018-07-13 15:53 ` [ndctl PATCH v12 1/5] ndctl, monitor: add a new command - monitor QI Fuli
2018-07-13 18:58   ` Verma, Vishal L [this message]
2018-07-13 15:54 ` [ndctl PATCH v12 2/5] ndctl, monitor: add main ndctl monitor configuration file QI Fuli
2018-07-13 21:32   ` Verma, Vishal L
2018-07-13 15:54 ` [ndctl PATCH v12 3/5] ndctl, monitor: add the unit file of systemd for ndctl-monitor service QI Fuli
2018-07-13 18:24   ` Masayoshi Mizuma
2018-07-13 19:05     ` Verma, Vishal L
2018-07-13 20:36       ` Verma, Vishal L
2018-07-13 15:54 ` [ndctl PATCH v12 4/5] ndctl, documentation: add man page for monitor QI Fuli
2018-07-13 19:09   ` Verma, Vishal L
2018-07-13 15:54 ` [ndctl PATCH v12 5/5] ndctl, test: add a new unit test " QI Fuli
2018-07-13 18:31   ` Masayoshi Mizuma

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1531508290.7574.138.camel@intel.com \
    --to=vishal.l.verma@intel.com \
    --cc=linux-nvdimm@lists.01.org \
    --cc=qi.fuli@jp.fujitsu.com \
    --cc=tokunaga.keiich@jp.fujitsu.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.