yanglint UPDATE logging improved
diff --git a/tools/lint/cmd_add.c b/tools/lint/cmd_add.c
index 6a9af8d..9f10711 100644
--- a/tools/lint/cmd_add.c
+++ b/tools/lint/cmd_add.c
@@ -74,7 +74,7 @@
         switch (opt) {
         case 'D': /* --disable--search */
             if (yo->ctx_options & LY_CTX_DISABLE_SEARCHDIRS) {
-                YLMSG_W("The -D option specified too many times.\n");
+                YLMSG_W("The -D option specified too many times.");
             }
             yo_opt_update_disable_searchdir(yo);
             break;
@@ -98,7 +98,7 @@
             break;
 
         default:
-            YLMSG_E("Unknown option.\n");
+            YLMSG_E("Unknown option.");
             return 1;
         }
     }
@@ -132,7 +132,7 @@
 
     if (yo->schema_out_format || yo->feature_param_format) {
         if (ly_set_add(&yo->schema_modules, (void *)mod, 1, NULL)) {
-            YLMSG_E("Storing parsed schema module (%s) for print failed.\n", filepath);
+            YLMSG_E("Storing parsed schema module (%s) for print failed.", filepath);
             return 1;
         }
     }
diff --git a/tools/lint/cmd_clear.c b/tools/lint/cmd_clear.c
index 233cc92..4a869af 100644
--- a/tools/lint/cmd_clear.c
+++ b/tools/lint/cmd_clear.c
@@ -83,7 +83,7 @@
             yo->ctx_options &= ~LY_CTX_NO_YANGLIBRARY;
             yo->yang_lib_file = optarg;
             if (!yo->yang_lib_file) {
-                YLMSG_E("Memory allocation error.\n");
+                YLMSG_E("Memory allocation error.");
                 return 1;
             }
             break;
@@ -91,7 +91,7 @@
             cmd_clear_help();
             return 1;
         default:
-            YLMSG_E("Unknown option.\n");
+            YLMSG_E("Unknown option.");
             return 1;
         }
     }
@@ -108,7 +108,7 @@
     (void) yo;
 
     if (posc) {
-        YLMSG_E("No positional arguments are allowed.\n");
+        YLMSG_E("No positional arguments are allowed.");
         return 1;
     }
 
@@ -148,16 +148,16 @@
 
     if (yo->yang_lib_file) {
         if (searchpaths_to_str(*ctx, &yo->searchpaths)) {
-            YLMSG_E("Storing searchpaths failed.\n");
+            YLMSG_E("Storing searchpaths failed.");
             return 1;
         }
         if (ly_ctx_new_ylpath(yo->searchpaths, yo->yang_lib_file, LYD_UNKNOWN, yo->ctx_options, &ctx_new)) {
-            YLMSG_E("Unable to create libyang context with yang-library data.\n");
+            YLMSG_E("Unable to create libyang context with yang-library data.");
             return 1;
         }
     } else {
         if (ly_ctx_new(NULL, yo->ctx_options, &ctx_new)) {
-            YLMSG_W("Failed to create context.\n");
+            YLMSG_W("Failed to create context.");
             return 1;
         }
     }
diff --git a/tools/lint/cmd_data.c b/tools/lint/cmd_data.c
index 9fa1b95..44fb237 100644
--- a/tools/lint/cmd_data.c
+++ b/tools/lint/cmd_data.c
@@ -182,7 +182,7 @@
         switch (opt) {
         case 'd': /* --default */
             if (yo_opt_update_data_default(optarg, yo)) {
-                YLMSG_E("Unknown default mode %s\n", optarg);
+                YLMSG_E("Unknown default mode %s.", optarg);
                 cmd_data_help_default();
                 return 1;
             }
@@ -195,32 +195,32 @@
             break;
         case 'F': /* --in-format */
             if (yo_opt_update_data_in_format(optarg, yo)) {
-                YLMSG_E("Unknown input format %s\n", optarg);
+                YLMSG_E("Unknown input format %s.", optarg);
                 cmd_data_help_in_format();
                 return 1;
             }
             break;
         case 'o': /* --output */
             if (yo->out) {
-                YLMSG_E("Only a single output can be specified.\n");
+                YLMSG_E("Only a single output can be specified.");
                 return 1;
             } else {
                 if (ly_out_new_filepath(optarg, &yo->out)) {
-                    YLMSG_E("Unable open output file %s (%s)\n", optarg, strerror(errno));
+                    YLMSG_E("Unable open output file %s (%s).", optarg, strerror(errno));
                     return 1;
                 }
             }
             break;
         case 'O':   /* --operational */
             if (yo->data_operational.path) {
-                YLMSG_E("The operational datastore (-O) cannot be set multiple times.\n");
+                YLMSG_E("The operational datastore (-O) cannot be set multiple times.");
                 return 1;
             }
             yo->data_operational.path = optarg;
             break;
         case 'R':   /* --reply-rpc */
             if (yo->reply_rpc.path) {
-                YLMSG_E("The PRC of the reply (-R) cannot be set multiple times.\n");
+                YLMSG_E("The PRC of the reply (-R) cannot be set multiple times.");
                 return 1;
             }
             yo->reply_rpc.path = optarg;
@@ -236,12 +236,12 @@
             break;
         case 't': /* --type */
             if (data_type_set) {
-                YLMSG_E("The data type (-t) cannot be set multiple times.\n");
+                YLMSG_E("The data type (-t) cannot be set multiple times.");
                 return 1;
             }
 
             if (yl_opt_update_data_type(optarg, yo)) {
-                YLMSG_E("Unknown data tree type %s.\n", optarg);
+                YLMSG_E("Unknown data tree type %s.", optarg);
                 cmd_data_help_type();
                 return 1;
             }
@@ -251,7 +251,7 @@
 
         case 'x': /* --xpath */
             if (ly_set_add(&yo->data_xpath, optarg, 0, NULL)) {
-                YLMSG_E("Storing XPath \"%s\" failed.\n", optarg);
+                YLMSG_E("Storing XPath \"%s\" failed.", optarg);
                 return 1;
             }
             break;
@@ -260,7 +260,7 @@
             cmd_data_help();
             return 1;
         default:
-            YLMSG_E("Unknown option.\n");
+            YLMSG_E("Unknown option.");
             return 1;
         }
     }
@@ -275,14 +275,14 @@
 cmd_data_dep(struct yl_opt *yo, int posc)
 {
     if (yo->interactive && !posc) {
-        YLMSG_E("Missing the data file to process.\n");
+        YLMSG_E("Missing the data file to process.");
         return 1;
     }
 
     if (yo->data_merge) {
         if (yo->data_type || (yo->data_parse_options & LYD_PARSE_ONLY)) {
             /* switch off the option, incompatible input data type */
-            YLMSG_W("The --merge option has effect only for 'data' and 'config' TYPEs\n");
+            YLMSG_W("The --merge option has effect only for 'data' and 'config' TYPEs.");
             yo->data_merge = 0;
         } else {
             /* postpone validation after the merge of all the input data */
@@ -293,14 +293,14 @@
     }
 
     if (yo->data_xpath.count && (yo->schema_out_format || yo->data_out_format)) {
-        YLMSG_E("The --format option cannot be combined with --xpath option.\n");
+        YLMSG_E("The --format option cannot be combined with --xpath option.");
         if (yo->interactive) {
             cmd_data_help_xpath();
         }
         return 1;
     }
     if (yo->data_xpath.count && (yo->data_print_options & LYD_PRINT_WD_MASK)) {
-        YLMSG_E("The --default option cannot be combined with --xpath option.\n");
+        YLMSG_E("The --default option cannot be combined with --xpath option.");
         if (yo->interactive) {
             cmd_data_help_xpath();
         }
@@ -308,27 +308,27 @@
     }
 
     if (yo->data_operational.path && !yo->data_type) {
-        YLMSG_W("Operational datastore takes effect only with RPCs/Actions/Replies/Notification input data types.\n");
+        YLMSG_W("Operational datastore takes effect only with RPCs/Actions/Replies/Notification input data types.");
         yo->data_operational.path = NULL;
     }
 
     if (yo->reply_rpc.path && (yo->data_type != LYD_TYPE_REPLY_NETCONF)) {
-        YLMSG_W("Source RPC is needed only for NETCONF Reply input data type.\n");
+        YLMSG_W("Source RPC is needed only for NETCONF Reply input data type.");
         yo->data_operational.path = NULL;
     } else if (!yo->reply_rpc.path && (yo->data_type == LYD_TYPE_REPLY_NETCONF)) {
-        YLMSG_E("Missing source RPC (-R) for NETCONF Reply input data type.\n");
+        YLMSG_E("Missing source RPC (-R) for NETCONF Reply input data type.");
         return 1;
     }
 
     if (!yo->out && (yo->data_out_format == LYD_LYB)) {
-        YLMSG_E("The LYB format requires the -o option specified.\n");
+        YLMSG_E("The LYB format requires the -o option specified.");
         return 1;
     }
 
     /* default output stream */
     if (!yo->out) {
         if (ly_out_new_file(stdout, &yo->out)) {
-            YLMSG_E("Unable to set stdout as output.\n");
+            YLMSG_E("Unable to set stdout as output.");
             return 1;
         }
         yo->out_stdout = 1;
@@ -438,7 +438,7 @@
     }
 
     if (!operational_f || (operational_f && !operational_f->in)) {
-        YLMSG_E("The --operational parameter needed to validate operation \"%s\" is missing.\n", LYD_NAME(op));
+        YLMSG_E("The --operational parameter needed to validate operation \"%s\" is missing.", LYD_NAME(op));
         ret = LY_EVALID;
         goto cleanup;
     }
@@ -450,8 +450,8 @@
     }
 
     if (!oper_tree) {
-        YLMSG_W("Operational datastore is empty or contains unknown data.\n");
-        YLMSG_E("Operation \"%s\" parent \"%s\" not found in the operational data.\n", LYD_NAME(op), path);
+        YLMSG_W("Operational datastore is empty or contains unknown data.");
+        YLMSG_E("Operation \"%s\" parent \"%s\" not found in the operational data.", LYD_NAME(op), path);
         ret = LY_EVALID;
         goto cleanup;
     }
@@ -459,7 +459,7 @@
         goto cleanup;
     }
     if (!set->count) {
-        YLMSG_E("Operation \"%s\" parent \"%s\" not found in the operational data.\n", LYD_NAME(op), path);
+        YLMSG_E("Operation \"%s\" parent \"%s\" not found in the operational data.", LYD_NAME(op), path);
         ret = LY_EVALID;
         goto cleanup;
     }
@@ -505,7 +505,7 @@
     if (operational && operational->in) {
         ret = lyd_parse_data(ctx, NULL, operational->in, operational->format, LYD_PARSE_ONLY, 0, &oper_tree);
         if (ret) {
-            YLMSG_E("Failed to parse operational datastore file \"%s\".\n", operational->path);
+            YLMSG_E("Failed to parse operational datastore file \"%s\".", operational->path);
             goto cleanup;
         }
     }
@@ -534,7 +534,7 @@
             assert(reply_rpc && reply_rpc->in);
             ret = lyd_parse_op(ctx, NULL, reply_rpc->in, reply_rpc->format, LYD_TYPE_RPC_NETCONF, &envp, &op);
             if (ret) {
-                YLMSG_E("Failed to parse source NETCONF RPC operation file \"%s\".\n", reply_rpc->path);
+                YLMSG_E("Failed to parse source NETCONF RPC operation file \"%s\".", reply_rpc->path);
                 goto cleanup;
             }
 
@@ -551,12 +551,12 @@
             ret = lyd_parse_op(ctx, op, input_f->in, input_f->format, type, &envp, NULL);
             break;
         default:
-            YLMSG_E("Internal error (%s:%d).\n", __FILE__, __LINE__);
+            YLMSG_E("Internal error (%s:%d).", __FILE__, __LINE__);
             goto cleanup;
         }
 
         if (ret) {
-            YLMSG_E("Failed to parse input data file \"%s\".\n", input_f->path);
+            YLMSG_E("Failed to parse input data file \"%s\".", input_f->path);
             goto cleanup;
         }
 
@@ -567,7 +567,7 @@
             } else {
                 ret = lyd_merge_siblings(&merged_tree, tree, LYD_MERGE_DESTRUCT);
                 if (ret) {
-                    YLMSG_E("Merging %s with previous data failed.\n", input_f->path);
+                    YLMSG_E("Merging %s with previous data failed.", input_f->path);
                     goto cleanup;
                 }
             }
@@ -615,10 +615,10 @@
             }
             if (ret) {
                 if (operational->path) {
-                    YLMSG_E("Failed to validate input data file \"%s\" with operational datastore \"%s\".\n",
+                    YLMSG_E("Failed to validate input data file \"%s\" with operational datastore \"%s\".",
                             input_f->path, operational->path);
                 } else {
-                    YLMSG_E("Failed to validate input data file \"%s\".\n", input_f->path);
+                    YLMSG_E("Failed to validate input data file \"%s\".", input_f->path);
                 }
                 goto cleanup;
             }
@@ -639,7 +639,7 @@
         /* validate the merged result */
         ret = lyd_validate_all(&merged_tree, ctx, validate_options, NULL);
         if (ret) {
-            YLMSG_E("Merged data are not valid.\n");
+            YLMSG_E("Merged data are not valid.");
             goto cleanup;
         }
 
@@ -654,7 +654,7 @@
             ret = lys_find_xpath(ctx, NULL, xpath, LYS_FIND_NO_MATCH_ERROR, &set);
             if (ret || !set->count) {
                 ret = (ret == LY_SUCCESS) ? LY_EINVAL : ret;
-                YLMSG_E("The requested xpath failed.\n");
+                YLMSG_E("The requested xpath failed.");
                 goto cleanup;
             }
             if (evaluate_xpath(merged_tree, xpath)) {
diff --git a/tools/lint/cmd_debug.c b/tools/lint/cmd_debug.c
index 1432fe9..3661bfa 100644
--- a/tools/lint/cmd_debug.c
+++ b/tools/lint/cmd_debug.c
@@ -73,7 +73,7 @@
             cmd_debug_help();
             return 1;
         default:
-            YLMSG_E("Unknown option.\n");
+            YLMSG_E("Unknown option.");
             return 1;
         }
     }
@@ -117,7 +117,7 @@
     }
 
     if (!set) {
-        YLMSG_E("Unknown debug group \"%s\"\n", posv);
+        YLMSG_E("Unknown debug group \"%s\".", posv);
         return 1;
     }
 
diff --git a/tools/lint/cmd_extdata.c b/tools/lint/cmd_extdata.c
index fe14f4a..fc7ac7b 100644
--- a/tools/lint/cmd_extdata.c
+++ b/tools/lint/cmd_extdata.c
@@ -70,7 +70,7 @@
             cmd_extdata_help();
             return 1;
         default:
-            YLMSG_E("Unknown option.\n");
+            YLMSG_E("Unknown option.");
             return 1;
         }
     }
@@ -85,7 +85,7 @@
 cmd_extdata_dep(struct yl_opt *yo, int posc)
 {
     if (!yo->extdata_unset && (posc > 1)) {
-        YLMSG_E("Only one file must be entered.\n");
+        YLMSG_E("Only one file must be entered.");
         return 1;
     }
 
@@ -105,7 +105,7 @@
         free(filename);
         filename = strdup(posv);
         if (!filename) {
-            YLMSG_E("Memory allocation error.\n");
+            YLMSG_E("Memory allocation error.");
             return 1;
         }
         ly_ctx_set_ext_data_clb(*ctx, ext_data_clb, filename);
diff --git a/tools/lint/cmd_feature.c b/tools/lint/cmd_feature.c
index 5c8bd82..96d55c1 100644
--- a/tools/lint/cmd_feature.c
+++ b/tools/lint/cmd_feature.c
@@ -68,7 +68,7 @@
             yo->feature_param_format = 1;
             break;
         default:
-            YLMSG_E("Unknown option.\n");
+            YLMSG_E("Unknown option.");
             return 1;
         }
     }
@@ -83,13 +83,13 @@
 cmd_feature_dep(struct yl_opt *yo, int posc)
 {
     if (ly_out_new_file(stdout, &yo->out)) {
-        YLMSG_E("Unable to print to the standard output.\n");
+        YLMSG_E("Unable to print to the standard output.");
         return 1;
     }
     yo->out_stdout = 1;
 
     if (yo->interactive && !yo->feature_print_all && !posc) {
-        YLMSG_E("Missing modules to print.\n");
+        YLMSG_E("Missing modules to print.");
         return 1;
     }
 
@@ -108,7 +108,7 @@
 
     mod = ly_ctx_get_module_latest(*ctx, posv);
     if (!mod) {
-        YLMSG_E("Module \"%s\" not found.\n", posv);
+        YLMSG_E("Module \"%s\" not found.", posv);
         return 1;
     }
 
diff --git a/tools/lint/cmd_help.c b/tools/lint/cmd_help.c
index 8a2a597..a1ee3f6 100644
--- a/tools/lint/cmd_help.c
+++ b/tools/lint/cmd_help.c
@@ -50,7 +50,7 @@
             cmd_help_help();
             return 1;
         } else {
-            YLMSG_E("Unknown option.\n");
+            YLMSG_E("Unknown option.");
             return 1;
         }
     }
diff --git a/tools/lint/cmd_list.c b/tools/lint/cmd_list.c
index fb9a2a7..166fbfa 100644
--- a/tools/lint/cmd_list.c
+++ b/tools/lint/cmd_list.c
@@ -64,7 +64,7 @@
             } else if (!strcasecmp(optarg, "json")) {
                 yo->data_out_format = LYD_JSON;
             } else {
-                YLMSG_E("Unknown output format %s\n", optarg);
+                YLMSG_E("Unknown output format %s.", optarg);
                 cmd_list_help();
                 return 1;
             }
@@ -73,7 +73,7 @@
             cmd_list_help();
             return 1;
         default:
-            YLMSG_E("Unknown option.\n");
+            YLMSG_E("Unknown option.");
             return 1;
         }
     }
@@ -88,11 +88,11 @@
 cmd_list_dep(struct yl_opt *yo, int posc)
 {
     if (posc) {
-        YLMSG_E("No positional arguments are allowed.\n");
+        YLMSG_E("No positional arguments are allowed.");
         return 1;
     }
     if (ly_out_new_file(stdout, &yo->out)) {
-        YLMSG_E("Unable to print to the standard output.\n");
+        YLMSG_E("Unable to print to the standard output.");
         return 1;
     }
     yo->out_stdout = 1;
@@ -114,7 +114,8 @@
     struct lyd_node *ylib;
 
     if (ly_ctx_get_yanglib_data(ctx, &ylib, "%u", ly_ctx_get_change_count(ctx))) {
-        YLMSG_E("Getting context info (ietf-yang-library data) failed. If the YANG module is missing or not implemented, use an option to add it internally.\n");
+        YLMSG_E("Getting context info (ietf-yang-library data) failed. If the YANG module is missing or not implemented, "
+                "use an option to add it internally.");
         return 1;
     }
 
diff --git a/tools/lint/cmd_load.c b/tools/lint/cmd_load.c
index f7457c8..808c125 100644
--- a/tools/lint/cmd_load.c
+++ b/tools/lint/cmd_load.c
@@ -86,7 +86,7 @@
             break;
 
         default:
-            YLMSG_E("Unknown option.\n");
+            YLMSG_E("Unknown option.");
             return 1;
         }
     }
diff --git a/tools/lint/cmd_print.c b/tools/lint/cmd_print.c
index a89ac1a..ff5fb90 100644
--- a/tools/lint/cmd_print.c
+++ b/tools/lint/cmd_print.c
@@ -81,11 +81,11 @@
         switch (opt) {
         case 'o': /* --output */
             if (yo->out) {
-                YLMSG_E("Only a single output can be specified.\n");
+                YLMSG_E("Only a single output can be specified.");
                 return 1;
             } else {
                 if (ly_out_new_filepath(optarg, &yo->out)) {
-                    YLMSG_E("Unable open output file %s (%s)\n", optarg, strerror(errno));
+                    YLMSG_E("Unable open output file %s (%s).", optarg, strerror(errno));
                     return 1;
                 }
             }
@@ -114,7 +114,7 @@
             cmd_print_help();
             return 1;
         default:
-            YLMSG_E("Unknown option.\n");
+            YLMSG_E("Unknown option.");
             return 1;
         }
     }
@@ -130,17 +130,17 @@
 {
     /* file name */
     if (yo->interactive && !posc && !yo->schema_node_path) {
-        YLMSG_E("Missing the name of the module to print.\n");
+        YLMSG_E("Missing the name of the module to print.");
         return 1;
     }
 
     if ((yo->schema_out_format != LYS_OUT_TREE) && yo->line_length) {
-        YLMSG_W("--tree-line-length take effect only in case of the tree output format.\n");
+        YLMSG_W("--tree-line-length take effect only in case of the tree output format.");
     }
 
     if (!yo->out) {
         if (ly_out_new_file(stdout, &yo->out)) {
-            YLMSG_E("Could not use stdout to print output.\n");
+            YLMSG_E("Could not use stdout to print output.");
         }
         yo->out_stdout = 1;
     }
@@ -170,9 +170,9 @@
     if (!erc) {
         return 0;
     } else if ((erc == LY_ENOTFOUND) && revision) {
-        YLMSG_E("No submodule \"%s\" found.\n", name);
+        YLMSG_E("No submodule \"%s\" found.", name);
     } else {
-        YLMSG_E("Unable to print submodule %s.\n", name);
+        YLMSG_E("Unable to print submodule %s.", name);
     }
 
     return erc;
@@ -195,9 +195,9 @@
     if (!erc) {
         return 0;
     } else if ((erc == LY_ENOTFOUND) && revision) {
-        YLMSG_E("No module \"%s\" found.\n", name);
+        YLMSG_E("No module \"%s\" found.", name);
     } else {
-        YLMSG_E("Unable to print module %s.\n", name);
+        YLMSG_E("Unable to print module %s.", name);
     }
 
     return erc;
@@ -245,7 +245,7 @@
         /* Use the same approach as for completion. */
         node = find_schema_path(ctx, yo->schema_node_path);
         if (!node) {
-            YLMSG_E("The requested schema node \"%s\" does not exists.\n", yo->schema_node_path);
+            YLMSG_E("The requested schema node \"%s\" does not exists.", yo->schema_node_path);
             return 1;
         }
     } else {
@@ -259,14 +259,14 @@
             /* search operation output */
             node = lys_find_path(ctx, NULL, yo->schema_node_path, 1);
             if (!node) {
-                YLMSG_E("Invalid schema path.\n");
+                YLMSG_E("Invalid schema path.");
                 return 1;
             }
         }
     }
 
     if (lys_print_node(yo->out, node, yo->schema_out_format, yo->line_length, yo->schema_print_options)) {
-        YLMSG_E("Unable to print schema node %s.\n", yo->schema_node_path);
+        YLMSG_E("Unable to print schema node %s.", yo->schema_node_path);
         return 1;
     }
 
diff --git a/tools/lint/cmd_searchpath.c b/tools/lint/cmd_searchpath.c
index 15c98a1..a6aeacf 100644
--- a/tools/lint/cmd_searchpath.c
+++ b/tools/lint/cmd_searchpath.c
@@ -62,7 +62,7 @@
             cmd_searchpath_help();
             return 1;
         default:
-            YLMSG_E("Unknown option.\n");
+            YLMSG_E("Unknown option.");
             return 1;
         }
     }
diff --git a/tools/lint/cmd_verb.c b/tools/lint/cmd_verb.c
index 6d31c33..33c8d1e 100644
--- a/tools/lint/cmd_verb.c
+++ b/tools/lint/cmd_verb.c
@@ -49,7 +49,7 @@
             cmd_verb_help();
             return 1;
         } else {
-            YLMSG_E("Unknown option.\n");
+            YLMSG_E("Unknown option.");
             return 1;
         }
     }
@@ -66,7 +66,7 @@
     (void) yo;
 
     if (posc > 1) {
-        YLMSG_E("Only a single verbosity level can be set.\n");
+        YLMSG_E("Only a single verbosity level can be set.");
         cmd_verb_help();
         return 1;
     }
@@ -105,7 +105,7 @@
         } else if (!strcasecmp("debug", posv) || !strcmp("3", posv)) {
             ly_log_level(LY_LLDBG);
         } else {
-            YLMSG_E("Unknown verbosity \"%s\"\n", posv);
+            YLMSG_E("Unknown verbosity \"%s\".", posv);
             return 1;
         }
     }
diff --git a/tools/lint/common.c b/tools/lint/common.c
index bdf96e6..08d23c3 100644
--- a/tools/lint/common.c
+++ b/tools/lint/common.c
@@ -20,6 +20,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -30,6 +31,19 @@
 #include "plugins_exts.h"
 #include "yl_opt.h"
 
+void
+yl_log(ly_bool err, const char *format, ...)
+{
+    char msg[256];
+    va_list ap;
+
+    va_start(ap, format);
+    vsnprintf(msg, 256, format, ap);
+    va_end(ap);
+
+    fprintf(stderr, "YANGLINT[%c]: %s\n", err ? 'E' : 'W', msg);
+}
+
 int
 parse_schema_path(const char *path, char **dir, char **module)
 {
@@ -67,11 +81,11 @@
 
     /* check that the filepath exists and is a regular file */
     if (stat(filepath, &st) == -1) {
-        YLMSG_E("Unable to use input filepath (%s) - %s.\n", filepath, strerror(errno));
+        YLMSG_E("Unable to use input filepath (%s) - %s.", filepath, strerror(errno));
         return -1;
     }
     if (!S_ISREG(st.st_mode)) {
-        YLMSG_E("Provided input file (%s) is not a regular file.\n", filepath);
+        YLMSG_E("Provided input file (%s) is not a regular file.", filepath);
         return -1;
     }
 
@@ -80,7 +94,7 @@
     }
 
     if (in && ly_in_new_filepath(filepath, 0, in)) {
-        YLMSG_E("Unable to process input file.\n");
+        YLMSG_E("Unable to process input file.");
         return -1;
     }
 
@@ -191,7 +205,7 @@
             /* - 1 because module_name_end points to ':' */
             module_name = strndup(schema_path + 1, module_name_end - schema_path - 1);
             if (!module_name) {
-                YLMSG_E("Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+                YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno));
                 parent_node = NULL;
                 goto cleanup;
             }
diff --git a/tools/lint/common.h b/tools/lint/common.h
index 340cecd..7c50e72 100644
--- a/tools/lint/common.h
+++ b/tools/lint/common.h
@@ -42,13 +42,13 @@
  * @brief log error message
  */
 #define YLMSG_E(...) \
-        fprintf(stderr, "YANGLINT[E]: " __VA_ARGS__)
+        yl_log(1, __VA_ARGS__);
 
 /**
  * @brief log warning message
  */
 #define YLMSG_W(...) \
-        fprintf(stderr, "YANGLINT[W]: " __VA_ARGS__)
+        yl_log(0, __VA_ARGS__);
 
 #ifndef _WIN32
 # define PATH_SEPARATOR ":"
@@ -59,6 +59,15 @@
 struct cmdline_file;
 
 /**
+ * @brief Log a yanglint message.
+ *
+ * @param[in] err Whether the message is an error or a warning.
+ * @param[in] format Message format.
+ * @param[in] ... Format arguments.
+ */
+void yl_log(ly_bool err, const char *format, ...);
+
+/**
  * @brief Parse path of a schema module file into the directory and module name.
  *
  * @param[in] path Schema module file path to be parsed.
diff --git a/tools/lint/completion.c b/tools/lint/completion.c
index 7a1842a..67c6b68 100644
--- a/tools/lint/completion.c
+++ b/tools/lint/completion.c
@@ -45,13 +45,13 @@
 
     p = realloc(*matches, (*match_count + 1) * sizeof **matches);
     if (!p) {
-        YLMSG_E("Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+        YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno));
         return;
     }
     *matches = p;
     (*matches)[*match_count] = strdup(match);
     if (!((*matches)[*match_count])) {
-        YLMSG_E("Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+        YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno));
         return;
     }
     ++(*match_count);
@@ -189,13 +189,13 @@
         if (parent && (node->module != parent->module)) {
             /* augmented node */
             if (asprintf(&node_name, "%s:%s", node->module->name, node->name) == -1) {
-                YLMSG_E("Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+                YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno));
                 break;
             }
         } else {
             node_name = strdup(node->name);
             if (!node_name) {
-                YLMSG_E("Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+                YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno));
                 break;
             }
         }
@@ -261,7 +261,7 @@
         /* module name known */
         module_name = strndup(start, end - start);
         if (!module_name) {
-            YLMSG_E("Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+            YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno));
             rc = 1;
             goto cleanup;
         }
@@ -287,7 +287,7 @@
         /* get rid of stuff after the last '/' to obtain the parent node */
         path = strndup(hint, start - hint);
         if (!path) {
-            YLMSG_E("Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+            YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno));
             rc = 1;
             goto cleanup;
         }
diff --git a/tools/lint/configuration.c b/tools/lint/configuration.c
index 86179fa..e3db668 100644
--- a/tools/lint/configuration.c
+++ b/tools/lint/configuration.c
@@ -37,14 +37,14 @@
     char *user_home, *yl_dir;
 
     if (!(pw = getpwuid(getuid()))) {
-        YLMSG_E("Determining home directory failed (%s).\n", strerror(errno));
+        YLMSG_E("Determining home directory failed (%s).", strerror(errno));
         return NULL;
     }
     user_home = pw->pw_dir;
 
     yl_dir = malloc(strlen(user_home) + 1 + strlen(YL_DIR) + 1);
     if (!yl_dir) {
-        YLMSG_E("Memory allocation failed (%s).\n", strerror(errno));
+        YLMSG_E("Memory allocation failed (%s).", strerror(errno));
         return NULL;
     }
     sprintf(yl_dir, "%s/%s", user_home, YL_DIR);
@@ -53,17 +53,17 @@
     if (ret == -1) {
         if (errno == ENOENT) {
             /* directory does not exist */
-            YLMSG_W("Configuration directory \"%s\" does not exist, creating it.\n", yl_dir);
+            YLMSG_W("Configuration directory \"%s\" does not exist, creating it.", yl_dir);
             if (mkdir(yl_dir, 00700)) {
                 if (errno != EEXIST) {
                     /* parallel execution, yay */
-                    YLMSG_E("Configuration directory \"%s\" cannot be created (%s).\n", yl_dir, strerror(errno));
+                    YLMSG_E("Configuration directory \"%s\" cannot be created (%s).", yl_dir, strerror(errno));
                     free(yl_dir);
                     return NULL;
                 }
             }
         } else {
-            YLMSG_E("Configuration directory \"%s\" exists but cannot be accessed (%s).\n", yl_dir, strerror(errno));
+            YLMSG_E("Configuration directory \"%s\" exists but cannot be accessed (%s).", yl_dir, strerror(errno));
             free(yl_dir);
             return NULL;
         }
@@ -83,16 +83,16 @@
 
     history_file = malloc(strlen(yl_dir) + 9);
     if (!history_file) {
-        YLMSG_E("Memory allocation failed (%s).\n", strerror(errno));
+        YLMSG_E("Memory allocation failed (%s).", strerror(errno));
         free(yl_dir);
         return;
     }
 
     sprintf(history_file, "%s/history", yl_dir);
     if (access(history_file, F_OK) && (errno == ENOENT)) {
-        YLMSG_W("No saved history.\n");
+        YLMSG_W("No saved history.");
     } else if (linenoiseHistoryLoad(history_file)) {
-        YLMSG_E("Failed to load history.\n");
+        YLMSG_E("Failed to load history.");
     }
 
     free(history_file);
@@ -110,14 +110,14 @@
 
     history_file = malloc(strlen(yl_dir) + 9);
     if (!history_file) {
-        YLMSG_E("Memory allocation failed (%s).\n", strerror(errno));
+        YLMSG_E("Memory allocation failed (%s).", strerror(errno));
         free(yl_dir);
         return;
     }
 
     sprintf(history_file, "%s/history", yl_dir);
     if (linenoiseHistorySave(history_file)) {
-        YLMSG_E("Failed to save history.\n");
+        YLMSG_E("Failed to save history.");
     }
 
     free(history_file);
diff --git a/tools/lint/main.c b/tools/lint/main.c
index 987ea10..43b90c8 100644
--- a/tools/lint/main.c
+++ b/tools/lint/main.c
@@ -56,7 +56,7 @@
     load_config();
 
     if (ly_ctx_new(NULL, YL_DEFAULT_CTX_OPTIONS, &ctx)) {
-        YLMSG_E("Failed to create context.\n");
+        YLMSG_E("Failed to create context.");
         return 1;
     }
 
@@ -116,7 +116,7 @@
 
         if (!cmd_found) {
             /* if unknown command specified, tell it to user */
-            YLMSG_E("Unknown command \"%.*s\", type 'help' for more information.\n", cmdlen, cmdline);
+            YLMSG_E("Unknown command \"%.*s\", type 'help' for more information.", cmdlen, cmdline);
         }
 
         linenoiseHistoryAdd(cmdline);
diff --git a/tools/lint/main_ni.c b/tools/lint/main_ni.c
index 6f04623..c08acc3 100644
--- a/tools/lint/main_ni.c
+++ b/tools/lint/main_ni.c
@@ -278,7 +278,7 @@
         ly_set_erase(schema_features, yl_schema_features_free);
 
         if (ly_ctx_new_ylpath(searchpaths, yang_lib_file, LYD_UNKNOWN, *ctx_options, ctx)) {
-            YLMSG_E("Unable to modify libyang context with yang-library data.\n");
+            YLMSG_E("Unable to modify libyang context with yang-library data.");
             return -1;
         }
     } else {
@@ -286,7 +286,7 @@
         (*ctx_options) |= !schema_features->count ? LY_CTX_ENABLE_IMP_FEATURES : 0;
 
         if (ly_ctx_new(searchpaths, *ctx_options, ctx)) {
-            YLMSG_E("Unable to create libyang context\n");
+            YLMSG_E("Unable to create libyang context.");
             return -1;
         }
     }
@@ -315,13 +315,13 @@
             mod = ly_ctx_get_module_latest(ctx, sf->mod_name);
         }
         if (!mod) {
-            YLMSG_E("Specified features not applied, module \"%s\" not loaded.\n", sf->mod_name);
+            YLMSG_E("Specified features not applied, module \"%s\" not loaded.", sf->mod_name);
             return 1;
         }
 
         /* we have the module, implement it if needed and enable the specific features */
         if (lys_set_implemented(mod, (const char **)sf->features)) {
-            YLMSG_E("Implementing module \"%s\" failed.\n", mod->name);
+            YLMSG_E("Implementing module \"%s\" failed.", mod->name);
             return 1;
         }
         sf->applied = 1;
@@ -519,7 +519,7 @@
 
         case 'I': /* --in-format */
             if (yo_opt_update_data_in_format(optarg, yo)) {
-                YLMSG_E("Unknown input format %s\n", optarg);
+                YLMSG_E("Unknown input format %s.", optarg);
                 help(1);
                 return -1;
             }
@@ -527,7 +527,7 @@
 
         case 'p':   /* --path */
             if (searchpath_strcat(&yo->searchpaths, optarg)) {
-                YLMSG_E("Storing searchpath failed.\n");
+                YLMSG_E("Storing searchpath failed.");
                 return -1;
             }
             break;
@@ -535,7 +535,7 @@
 
         case 'D': /* --disable-searchdir */
             if (yo->ctx_options & LY_CTX_DISABLE_SEARCHDIRS) {
-                YLMSG_W("The -D option specified too many times.\n");
+                YLMSG_W("The -D option specified too many times.");
             }
             yo_opt_update_disable_searchdir(yo);
             break;
@@ -576,12 +576,12 @@
 
         case 't': /* --type */
             if (data_type_set) {
-                YLMSG_E("The data type (-t) cannot be set multiple times.\n");
+                YLMSG_E("The data type (-t) cannot be set multiple times.");
                 return -1;
             }
 
             if (yl_opt_update_data_type(optarg, yo)) {
-                YLMSG_E("Unknown data tree type %s\n", optarg);
+                YLMSG_E("Unknown data tree type %s.", optarg);
                 help(1);
                 return -1;
             }
@@ -591,7 +591,7 @@
 
         case 'd': /* --default */
             if (yo_opt_update_data_default(optarg, yo)) {
-                YLMSG_E("Unknown default mode %s\n", optarg);
+                YLMSG_E("Unknown default mode %s.", optarg);
                 help(1);
                 return -1;
             }
@@ -599,7 +599,7 @@
 
         case 'E': /* --data-xpath */
             if (ly_set_add(&yo->data_xpath, optarg, 0, NULL)) {
-                YLMSG_E("Storing XPath \"%s\" failed.\n", optarg);
+                YLMSG_E("Storing XPath \"%s\" failed.", optarg);
                 return -1;
             }
             break;
@@ -614,11 +614,11 @@
 
         case 'o': /* --output */
             if (yo->out) {
-                YLMSG_E("Only a single output can be specified.\n");
+                YLMSG_E("Only a single output can be specified.");
                 return -1;
             } else {
                 if (ly_out_new_filepath(optarg, &yo->out)) {
-                    YLMSG_E("Unable open output file %s (%s)\n", optarg, strerror(errno));
+                    YLMSG_E("Unable open output file %s (%s).", optarg, strerror(errno));
                     return -1;
                 }
             }
@@ -626,7 +626,7 @@
 
         case 'O': /* --operational */
             if (yo->data_operational.path) {
-                YLMSG_E("The operational datastore (-O) cannot be set multiple times.\n");
+                YLMSG_E("The operational datastore (-O) cannot be set multiple times.");
                 return -1;
             }
             yo->data_operational.path = optarg;
@@ -634,7 +634,7 @@
 
         case 'R': /* --reply-rpc */
             if (yo->reply_rpc.path) {
-                YLMSG_E("The PRC of the reply (-R) cannot be set multiple times.\n");
+                YLMSG_E("The PRC of the reply (-R) cannot be set multiple times.");
                 return -1;
             }
             yo->reply_rpc.path = optarg;
@@ -666,7 +666,7 @@
             /* case 'G' */
 #endif
         default:
-            YLMSG_E("Invalid option or missing argument: -%c\n", optopt);
+            YLMSG_E("Invalid option or missing argument: -%c.", optopt);
             return -1;
         } /* switch */
     }
@@ -674,7 +674,7 @@
     /* additional checks for the options combinations */
     if (!yo->list && (optind >= argc)) {
         help(1);
-        YLMSG_E("Missing <schema> to process.\n");
+        YLMSG_E("Missing <schema> to process.");
         return 1;
     }
 
@@ -702,16 +702,16 @@
 
     /* the second batch of checks */
     if (yo->schema_print_options && !yo->schema_out_format) {
-        YLMSG_W("Schema printer options specified, but the schema output format is missing.\n");
+        YLMSG_W("Schema printer options specified, but the schema output format is missing.");
     }
     if (yo->schema_parse_options && !yo->schema_modules.count) {
-        YLMSG_W("Schema parser options specified, but no schema input file provided.\n");
+        YLMSG_W("Schema parser options specified, but no schema input file provided.");
     }
     if (yo->data_print_options && !yo->data_out_format) {
-        YLMSG_W("data printer options specified, but the data output format is missing.\n");
+        YLMSG_W("data printer options specified, but the data output format is missing.");
     }
     if (((yo->data_parse_options != YL_DEFAULT_DATA_PARSE_OPTIONS) || yo->data_type) && !yo->data_inputs.count) {
-        YLMSG_W("Data parser options specified, but no data input file provided.\n");
+        YLMSG_W("Data parser options specified, but no data input file provided.");
     }
 
     return 0;
diff --git a/tools/lint/yl_opt.c b/tools/lint/yl_opt.c
index 1a6add0..7cd855f 100644
--- a/tools/lint/yl_opt.c
+++ b/tools/lint/yl_opt.c
@@ -32,7 +32,7 @@
 
     rec = malloc(sizeof *rec);
     if (!rec) {
-        YLMSG_E("Allocating memory for data file information failed.\n");
+        YLMSG_E("Allocating memory for data file information failed.");
         return NULL;
     }
     rec->in = in;
@@ -41,7 +41,7 @@
 
     if (set && ly_set_add(set, rec, 1, NULL)) {
         free(rec);
-        YLMSG_E("Storing data file information failed.\n");
+        YLMSG_E("Storing data file information failed.");
         return NULL;
     }
 
@@ -165,7 +165,7 @@
         return 0;
     }
 
-    YLMSG_E("Unknown output format %s\n", arg);
+    YLMSG_E("Unknown output format %s.", arg);
     return 1;
 }
 
@@ -312,7 +312,7 @@
         ++count;
         r = realloc(vector, (count + 1) * sizeof *vector);
         if (!r) {
-            YLMSG_E("Memory allocation failed (%s:%d, %s).\n", __FILE__, __LINE__, strerror(errno));
+            YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno));
             free(vector);
             return -1;
         }
diff --git a/tools/lint/yl_schema_features.c b/tools/lint/yl_schema_features.c
index ceaff36..74f88b9 100644
--- a/tools/lint/yl_schema_features.c
+++ b/tools/lint/yl_schema_features.c
@@ -69,14 +69,14 @@
 
     rec = calloc(1, sizeof *rec);
     if (!rec) {
-        YLMSG_E("Unable to allocate features information record (%s).\n", strerror(errno));
+        YLMSG_E("Unable to allocate features information record (%s).", strerror(errno));
         goto error;
     }
 
     /* fill the record */
     p = strchr(fstring, ':');
     if (!p) {
-        YLMSG_E("Invalid format of the features specification (%s).\n", fstring);
+        YLMSG_E("Invalid format of the features specification (%s).", fstring);
         goto error;
     }
     rec->mod_name = strndup(fstring, p - fstring);
@@ -97,7 +97,7 @@
         if (len) {
             fp = realloc(rec->features, (count + 1) * sizeof *rec->features);
             if (!fp) {
-                YLMSG_E("Unable to store features list information (%s).\n", strerror(errno));
+                YLMSG_E("Unable to store features list information (%s).", strerror(errno));
                 goto error;
             }
             rec->features = fp;
@@ -109,7 +109,7 @@
     /* terminating NULL */
     fp = realloc(rec->features, (count + 1) * sizeof *rec->features);
     if (!fp) {
-        YLMSG_E("Unable to store features list information (%s).\n", strerror(errno));
+        YLMSG_E("Unable to store features list information (%s).", strerror(errno));
         goto error;
     }
     rec->features = fp;
@@ -117,7 +117,7 @@
 
     /* Store record to the output set. */
     if (ly_set_add(fset, rec, 1, NULL)) {
-        YLMSG_E("Unable to store features information (%s).\n", strerror(errno));
+        YLMSG_E("Unable to store features information (%s).", strerror(errno));
         goto error;
     }
     rec = NULL;