[sheepdog] [PATCH v2 1/2] sheep, dog: runtime loglevel changing

Hitoshi Mitake mitake.hitoshi at gmail.com
Sat Oct 19 16:35:33 CEST 2013


This patch adds two new opcode for runtime loglevel changes and let
dog support the changing from command line. This is useful for making
sheep process verbose temporally and can make troubleshooting easier.

Example of usage:

$ dog node loglevel list
emerg   (0)
alert   (1)
crit    (2)
err     (3)
warning (4)
notice  (5)
info    (6)
debug   (7)
$ dog node loglevel get
info (6)
$ dog node loglevel set debug	# <- change loglevel from info to debug
$ dog node loglevel get
debug (7)

Signed-off-by: Hitoshi Mitake <mitake.hitoshi at lab.ntt.co.jp>
---
 CHANGELOG.md             |  8 +++--
 dog/common.c             | 84 ++++++++++++++++++++++++++++++++++++++++++++++++
 dog/dog.h                |  5 +++
 dog/node.c               | 79 ++++++++++++++++++++++++++++++++++++++++++++-
 include/internal_proto.h |  2 ++
 include/logger.h         |  3 ++
 lib/logger.c             | 12 +++++++
 sheep/ops.c              | 43 +++++++++++++++++++++++++
 8 files changed, 233 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 98d221e..771d69b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,9 +3,13 @@
 
 DOG COMMAND INTERFACE:
  - new subcommand "vdi cache purge" for cleaning stale object cache
- -- "vdi cache purge" cleans stale cache of all images
- -- "vdi cache purge <image>" cleans stale cache of the specified image
+  - "vdi cache purge" cleans stale cache of all images
+  - "vdi cache purge <image>" cleans stale cache of the specified image
  - new subcommand "node stat" for showing I/O status of the node
+ - new subcommand "node loglevel" for changing log level at runtime
+  - "node loglevel set" sets loglevel of running sheep process
+  - "node loglevel get" gets loglevel from running sheep process
+  - "node loglevel list" lists avialable loglevels
 
 SHEEP COMMAND INTERFACE:
  - improvements of help messages
diff --git a/dog/common.c b/dog/common.c
index 5e7ce2e..44e116d 100644
--- a/dog/common.c
+++ b/dog/common.c
@@ -351,3 +351,87 @@ bool is_erasure_oid(uint64_t oid, uint8_t policy)
 		return false;
 	return true;
 }
+
+static const char *loglevel_table[] = {
+	"emerg",
+	"alert",
+	"crit",
+	"err",
+	"warning",
+	"notice",
+	"info",
+	"debug",
+};				/* index is log level */
+
+int do_loglevel_set(const struct node_id *nid, const char *loglevel_str)
+{
+	int32_t loglevel = -1;
+	int ret;
+	struct sd_req hdr;
+	struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+
+	for (int i = 0; i < ARRAY_SIZE(loglevel_table); i++) {
+		if (!strcmp(loglevel_table[i], loglevel_str)) {
+			loglevel = i;
+			break;
+		}
+	}
+
+	if (loglevel == -1)
+		return EXIT_USAGE;
+
+	sd_init_req(&hdr, SD_OP_SET_LOGLEVEL);
+	hdr.flags = SD_FLAG_CMD_WRITE;
+	hdr.data_length = sizeof(loglevel);
+
+	ret = dog_exec_req(nid, &hdr, &loglevel);
+	if (ret < 0)
+		return EXIT_SYSFAIL;
+
+	if (rsp->result != SD_RES_SUCCESS)
+		return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
+
+int do_loglevel_get(const struct node_id *nid, int32_t *ret_loglevel)
+{
+	int32_t loglevel = -1;
+	int ret;
+	struct sd_req hdr;
+	struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+
+	sd_init_req(&hdr, SD_OP_GET_LOGLEVEL);
+	hdr.data_length = sizeof(loglevel);
+
+	ret = dog_exec_req(nid, &hdr, &loglevel);
+	if (ret < 0)
+		return EXIT_SYSFAIL;
+
+	if (rsp->result != SD_RES_SUCCESS)
+		return EXIT_FAILURE;
+
+	*ret_loglevel = loglevel;
+
+	return EXIT_SUCCESS;
+}
+
+const char *loglevel_to_str(int loglevel)
+{
+	for (int i = 0; i < ARRAY_SIZE(loglevel_table); i++) {
+		if (i == loglevel)
+			return loglevel_table[i];
+	}
+
+	return "unknown loglevel";
+}
+
+void dump_loglevels(bool err)
+{
+	for (int i = 0; i < ARRAY_SIZE(loglevel_table); i++) {
+		if (err)
+			sd_err("%s\t(%d)", loglevel_table[i], i);
+		else
+			sd_info("%s\t(%d)", loglevel_table[i], i);
+	}
+}
diff --git a/dog/dog.h b/dog/dog.h
index 769fc6c..28c36a1 100644
--- a/dog/dog.h
+++ b/dog/dog.h
@@ -95,4 +95,9 @@ extern struct command cluster_command;
   #define trace_command {}
 #endif /* HAVE_TRACE */
 
+int do_loglevel_set(const struct node_id *nid, const char *loglevel_str);
+int do_loglevel_get(const struct node_id *nid, int32_t *ret_loglevel);
+const char *loglevel_to_str(int loglevel);
+void dump_loglevels(bool err);
+
 #endif
diff --git a/dog/node.c b/dog/node.c
index 052739c..5f1b070 100644
--- a/dog/node.c
+++ b/dog/node.c
@@ -420,7 +420,6 @@ static int node_md(int argc, char **argv)
 	return do_generic_subcommand(node_md_cmd, argc, argv);
 }
 
-
 static int node_parser(int ch, const char *opt)
 {
 	switch (ch) {
@@ -444,6 +443,82 @@ static struct sd_option node_options[] = {
 	{ 0, NULL, false, NULL },
 };
 
+static int node_loglevel_set(int argc, char **argv)
+{
+	int ret = 0;
+	char *loglevel_str = argv[optind];
+
+	ret = do_loglevel_set(&sd_nid, loglevel_str);
+	switch (ret) {
+	case EXIT_USAGE:
+		sd_err("invalid loglevel: %s", loglevel_str);
+		sd_err("available loglevels:");
+		dump_loglevels(true);
+
+		ret = -1;
+		break;
+	case EXIT_FAILURE:
+	case EXIT_SYSFAIL:
+		sd_err("Failed to execute request");
+		ret = -1;
+		break;
+	case EXIT_SUCCESS:
+		/* do nothing */
+		break;
+	default:
+		sd_err("unknown return code of do_loglevel_set(): %d", ret);
+		ret = -1;
+		break;
+	}
+
+	return ret;
+}
+
+static int node_loglevel_get(int argc, char **argv)
+{
+	int ret = 0, loglevel = -1;
+
+	ret = do_loglevel_get(&sd_nid, &loglevel);
+	switch (ret) {
+	case EXIT_FAILURE:
+	case EXIT_SYSFAIL:
+		sd_err("Failed to execute request");
+		ret = -1;
+		break;
+	case EXIT_SUCCESS:
+		sd_info("%s (%d)", loglevel_to_str(loglevel), loglevel);
+		break;
+	default:
+		sd_err("unknown return code of do_loglevel_get(): %d", ret);
+		ret = -1;
+		break;
+	}
+
+	return ret;
+}
+
+static int node_loglevel_list(int argc, char **argv)
+{
+	dump_loglevels(false);
+
+	return EXIT_SUCCESS;
+}
+
+static struct subcommand node_loglevel_cmd[] = {
+	{"set", NULL, NULL, "set new loglevel",
+	 NULL, 0, node_loglevel_set},
+	{"get", NULL, NULL, "get current loglevel",
+	 NULL, 0, node_loglevel_get},
+	{"list", NULL, NULL, "list available loglevels",
+	 NULL, 0, node_loglevel_list},
+	{NULL},
+};
+
+static int node_loglevel(int argc, char **argv)
+{
+	return do_generic_subcommand(node_loglevel_cmd, argc, argv);
+}
+
 static struct subcommand node_cmd[] = {
 	{"kill", "<node id>", "aprh", "kill node", NULL,
 	 CMD_NEED_ARG | CMD_NEED_NODELIST, node_kill},
@@ -457,6 +532,8 @@ static struct subcommand node_cmd[] = {
 	 node_md_cmd, CMD_NEED_ARG, node_md, node_options},
 	{"stat", NULL, "aprwh", "show stat information about the node", NULL,
 	 0, node_stat, node_options},
+	{"loglevel", NULL, "aph", "show or set log level of the node", NULL,
+	 0, node_loglevel},
 	{NULL,},
 };
 
diff --git a/include/internal_proto.h b/include/internal_proto.h
index 8a23737..c6eecaf 100644
--- a/include/internal_proto.h
+++ b/include/internal_proto.h
@@ -95,6 +95,8 @@
 #define SD_OP_GET_CACHE_INFO 0xB6
 #define SD_OP_CACHE_PURGE    0xB7
 #define SD_OP_STAT	0xB8
+#define SD_OP_GET_LOGLEVEL	0xB9
+#define SD_OP_SET_LOGLEVEL	0xBA
 
 /* internal flags for hdr.flags, must be above 0x80 */
 #define SD_FLAG_CMD_RECOVERY 0x0080
diff --git a/include/logger.h b/include/logger.h
index 5bb3a65..3f9292d 100644
--- a/include/logger.h
+++ b/include/logger.h
@@ -87,4 +87,7 @@ void sd_backtrace(void);
 	abort();				\
 })
 
+void set_loglevel(int new_loglevel);
+int get_loglevel(void);
+
 #endif	/* LOG_H */
diff --git a/lib/logger.c b/lib/logger.c
index 6c6a315..bf1a605 100644
--- a/lib/logger.c
+++ b/lib/logger.c
@@ -767,3 +767,15 @@ fallback:
 	/* dump the stack frames if possible*/
 	dump_stack_frames();
 }
+
+void set_loglevel(int new_loglevel)
+{
+	assert(SDOG_EMERG <= new_loglevel && new_loglevel <= SDOG_DEBUG);
+	sd_log_level = new_loglevel;
+}
+
+int get_loglevel(void)
+{
+	return sd_log_level;
+}
+
diff --git a/sheep/ops.c b/sheep/ops.c
index 7f73ab1..914aea7 100644
--- a/sheep/ops.c
+++ b/sheep/ops.c
@@ -947,6 +947,35 @@ static int peer_create_and_write_obj(struct request *req)
 	return sd_store->create_and_write(hdr->obj.oid, &iocb);
 }
 
+static int local_get_loglevel(struct request *req)
+{
+	int32_t current_level;
+
+	current_level = get_loglevel();
+	memcpy(req->data, &current_level, sizeof(current_level));
+	req->rp.data_length = sizeof(current_level);
+
+	sd_info("returning log level: %u", current_level);
+
+	return SD_RES_SUCCESS;
+}
+
+static int local_set_loglevel(struct request *req)
+{
+	int32_t new_level = 0;
+
+	memcpy(&new_level, req->data, sizeof(int32_t));
+	if (!(LOG_EMERG <= new_level && new_level <= LOG_DEBUG)) {
+		sd_err("invalid log level: %d", new_level);
+		return SD_RES_INVALID_PARMS;
+	}
+
+	set_loglevel(new_level);
+
+	return SD_RES_SUCCESS;
+
+}
+
 static struct sd_op_template sd_ops[] = {
 
 	/* cluster operations */
@@ -1217,6 +1246,20 @@ static struct sd_op_template sd_ops[] = {
 		.process_main = local_sd_stat,
 	},
 
+	[SD_OP_GET_LOGLEVEL] = {
+		.name = "GET_LOGLEVEL",
+		.type = SD_OP_TYPE_LOCAL,
+		.force = true,
+		.process_work = local_get_loglevel,
+	},
+
+	[SD_OP_SET_LOGLEVEL] = {
+		.name = "SET_LOGLEVEL",
+		.type = SD_OP_TYPE_LOCAL,
+		.force = true,
+		.process_work = local_set_loglevel,
+	},
+
 	/* gateway I/O operations */
 	[SD_OP_CREATE_AND_WRITE_OBJ] = {
 		.name = "CREATE_AND_WRITE_OBJ",
-- 
1.8.1.2




More information about the sheepdog mailing list