diff --git a/TODO b/TODO
index f08f95e12977b470d3860d8083dfe60abb122624..0b54d5b213aa6b730b0cdae11297f471bcae62ee 100644
--- a/TODO
+++ b/TODO
@@ -1,14 +1,12 @@
 Current activities:
 
-* Improve debugging support in the sieve-test tool:
-	- Improve trace debugging towards something more intuitively readable.
+* Cleanup the test suite
+	- Make uniform command implementations
+	- Cleanup test scripts
 
 Next (in order of descending priority/precedence):
 
 * Update man pages to match style of Dovecot man pages.
-* Cleanup the test suite
-	- Make uniform command implementations
-	- Cleanup test scripts
 * Improve error handling and logging
 	- Detect permission errors when writing global script binaries and advise the 
 	  administrator on using sievec to precompile the scripts.
diff --git a/src/lib-sieve/cmd-discard.c b/src/lib-sieve/cmd-discard.c
index 69a6821a6577a6b7915b9dfe18d8f1bba720adb3..089cbc59f491812349a4fe1c9fa55e1c10cf8026 100644
--- a/src/lib-sieve/cmd-discard.c
+++ b/src/lib-sieve/cmd-discard.c
@@ -110,7 +110,8 @@ static int cmd_discard_operation_execute
 	/* Source line */
 	source_line = sieve_runtime_get_command_location(renv);
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "discard action; cancel implicit keep");
+	sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, 
+		"discard action; cancel implicit keep");
 
 	return ( sieve_result_add_action
 		(renv, NULL, &act_discard, NULL, source_line, NULL, 0) >= 0 );
diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c
index 7f77b0fe9cb677943b22efa568d9e11d06dfe2cb..4d439b4a1e1dc4c93da8280f82955a5a72502c40 100644
--- a/src/lib-sieve/cmd-redirect.c
+++ b/src/lib-sieve/cmd-redirect.c
@@ -219,9 +219,12 @@ static int cmd_redirect_operation_execute
 	/* FIXME: perform address normalization if the string is not a string literal
 	 */
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, 
-		"redirect action; forward message to address `%s'",
-		str_sanitize(str_c(redirect), 64));
+	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_ACTIONS) ) {
+		sieve_runtime_trace(renv, 0, "redirect action");
+		sieve_runtime_trace_descend(renv);
+		sieve_runtime_trace(renv, 0, "forward message to address `%s'",
+			str_sanitize(str_c(redirect), 80));
+	}
 	
 	/* Add redirect action to the result */
 
diff --git a/src/lib-sieve/cmd-stop.c b/src/lib-sieve/cmd-stop.c
index a28f9c2ca5e50ac780eaa7eedacaa6b880487363..41e158d4215deddb4d4ca5c7e8089c6a8562e7f7 100644
--- a/src/lib-sieve/cmd-stop.c
+++ b/src/lib-sieve/cmd-stop.c
@@ -77,7 +77,8 @@ static bool cmd_stop_generate
 static int opc_stop_execute
 (const struct sieve_runtime_env *renv,  sieve_size_t *address ATTR_UNUSED)
 {	
-	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "stop");
+	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, 
+		"stop command; end all script execution");
 	
 	sieve_interpreter_interrupt(renv->interp);
 
diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c
index 7b7465abd51774c154d219c81188718a9a31a767..f50698ba5ae79dafdb0b595eecc14ecacc66bc13 100644
--- a/src/lib-sieve/ext-envelope.c
+++ b/src/lib-sieve/ext-envelope.c
@@ -328,6 +328,12 @@ static int sieve_envelope_address_list_next_item
 		if ( (ret=sieve_stringlist_next_item(addrlist->env_parts, &envp_item)) 
 			<= 0 )
 			return ret;
+
+		if ( _addrlist->strlist.trace ) {
+			sieve_runtime_trace(_addrlist->strlist.runenv, 0,
+				"getting `%s' part from message envelope",
+				str_sanitize(str_c(envp_item), 80));
+		}
 			
 		if ( (epart=_envelope_part_find(str_c(envp_item))) != NULL ) {
 			addrlist->value_index = 0;
diff --git a/src/lib-sieve/ext-fileinto.c b/src/lib-sieve/ext-fileinto.c
index 810889633afdfa4a316eb320e94b0bb5a275fbe1..da5607a7c9ef8a7026138622ba8a76d127bea3f6 100644
--- a/src/lib-sieve/ext-fileinto.c
+++ b/src/lib-sieve/ext-fileinto.c
@@ -178,8 +178,13 @@ static int ext_fileinto_operation_execute
 	 */
 
 	mailbox = str_sanitize(str_c(folder), 64);
-	sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, 
-		"fileinto action; store message in mailbox `%s'", mailbox);
+
+	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_ACTIONS) ) {
+		sieve_runtime_trace(renv, 0, "fileinto action");
+		sieve_runtime_trace_descend(renv);
+		sieve_runtime_trace(renv, 0, "store message in mailbox `%s'", 
+			str_sanitize(mailbox, 80));
+	}
 		
 	/* Add action to result */	
 	ret = sieve_act_store_add_to_result
diff --git a/src/lib-sieve/ext-reject.c b/src/lib-sieve/ext-reject.c
index a872a3f450cedd38c978b7b07e6eec7361b3fb1d..5ca7ed783a9fcac865b5667446eda42a6720f9b0 100644
--- a/src/lib-sieve/ext-reject.c
+++ b/src/lib-sieve/ext-reject.c
@@ -290,12 +290,16 @@ static int ext_reject_operation_execute
 	 * Perform operation
 	 */
 
-	if ( sieve_operation_is(oprtn, ereject_operation) )
-		sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS,
-			"ereject action; reject message with reason `%s'", str_sanitize(str_c(reason), 64));
-	else
-		sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS,
-			"reject action; reject message with reason `%s'", str_sanitize(str_c(reason), 64));
+	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_ACTIONS) ) {
+		if ( sieve_operation_is(oprtn, ereject_operation) )
+			sieve_runtime_trace(renv, 0, "ereject action");
+		else
+			sieve_runtime_trace(renv, 0, "reject action");
+
+		sieve_runtime_trace_descend(renv);
+		sieve_runtime_trace(renv, 0, "reject message with reason `%s'", 
+			str_sanitize(str_c(reason), 64));
+	}
 
 	/* Add reject action to the result */
 	pool = sieve_result_pool(renv->result);
diff --git a/src/lib-sieve/plugins/enotify/cmd-notify.c b/src/lib-sieve/plugins/enotify/cmd-notify.c
index 6be5703ca844f6ca61ffb1583c654b7429449ebd..69a4f0530627c26b6a1769cebf018019800b9668 100644
--- a/src/lib-sieve/plugins/enotify/cmd-notify.c
+++ b/src/lib-sieve/plugins/enotify/cmd-notify.c
@@ -2,6 +2,7 @@
  */
 
 #include "lib.h"
+#include "str-sanitize.h"
 
 #include "sieve-common.h"
 #include "sieve-error.h"
@@ -465,7 +466,12 @@ static int cmd_notify_operation_execute
 
 	/* Trace */
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "notify action");	
+	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_ACTIONS) ) {
+		sieve_runtime_trace(renv, 0, "notify action");	
+		sieve_runtime_trace_descend(renv);
+		sieve_runtime_trace(renv, 0, "notify with uri `%s'",
+			str_sanitize(str_c(method_uri), 80));	
+	}
 
 	/* Check operands */
 
diff --git a/src/lib-sieve/plugins/imap4flags/cmd-flag.c b/src/lib-sieve/plugins/imap4flags/cmd-flag.c
index 0fbde66ce7599238afb79e620904ed6ba1bebb5e..71471d352f708fee0695010f27dfe1569eab9508 100644
--- a/src/lib-sieve/plugins/imap4flags/cmd-flag.c
+++ b/src/lib-sieve/plugins/imap4flags/cmd-flag.c
@@ -177,12 +177,10 @@ static int cmd_flag_operation_execute
 {
 	const struct sieve_operation *op = renv->oprtn;
 	struct sieve_operand operand;
-	string_t *flag_item;
 	struct sieve_stringlist *flag_list;
 	struct sieve_variable_storage *storage;
 	unsigned int var_index;
 	ext_imapflag_flag_operation_t flag_op;
-	int ret;
 		
 	/* 
 	 * Read operands 
@@ -241,7 +239,8 @@ static int cmd_flag_operation_execute
 		i_unreached();
 	}
 
+	sieve_runtime_trace_descend(renv);
+
 	/* Perform requested operation */
-	
 	return flag_op(renv, storage, var_index, flag_list);
 }
diff --git a/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c b/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
index 3c42ebe6d1f3054634a237b036274c3befd8e605..51ba9602defe2dd7a33c7c05ecacfac2311f2b35 100644
--- a/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+++ b/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
@@ -463,84 +463,109 @@ static void flags_list_clear_flags
 	str_truncate(flags_list, 0);
 }
 
-int ext_imap4flags_set_flags
+static string_t *ext_imap4flags_get_flag_variable
 (const struct sieve_runtime_env *renv, struct sieve_variable_storage *storage,
-	unsigned int var_index, struct sieve_stringlist *flags)
+	unsigned int var_index)
 {
-	string_t *cur_flags;
+	string_t *flags;
 	
 	if ( storage != NULL ) {
-		if ( !sieve_variable_get_modifiable(storage, var_index, &cur_flags) )
-			return SIEVE_EXEC_BIN_CORRUPT;
+		if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+			const char *var_name, *var_id;
+	
+			(void)sieve_variable_get_identifier(storage, var_index, &var_name);
+			var_id = sieve_variable_get_varid(storage, var_index);
+
+			sieve_runtime_trace(renv, 0, "update variable `%s' [%s]", 
+				var_name, var_id);
+		}
+
+		if ( !sieve_variable_get_modifiable(storage, var_index, &flags) )
+			return NULL;
 	} else {
-		cur_flags = _get_flags_string(renv->oprtn->ext, renv->result);
+		flags = _get_flags_string(renv->oprtn->ext, renv->result);
 	}
-	
+
+	return flags;
+}
+
+int ext_imap4flags_set_flags
+(const struct sieve_runtime_env *renv, struct sieve_variable_storage *storage,
+	unsigned int var_index, struct sieve_stringlist *flags)
+{
+	string_t *cur_flags = ext_imap4flags_get_flag_variable
+		(renv, storage, var_index);
+		
 	if ( cur_flags != NULL ) {
 		string_t *flags_item;
 		int ret;
 
 		flags_list_clear_flags(cur_flags);
 		while ( (ret=sieve_stringlist_next_item(flags, &flags_item)) > 0 ) {
+			sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, 
+				"set flags `%s'", str_c(flags_item)); 
+
 			flags_list_add_flags(cur_flags, flags_item);
 		}
 
 		if ( ret < 0 ) return SIEVE_EXEC_BIN_CORRUPT;
+	
+		return SIEVE_EXEC_OK;
 	}
 
-	return SIEVE_EXEC_OK;
+	return SIEVE_EXEC_BIN_CORRUPT;
 }
 
 int ext_imap4flags_add_flags
 (const struct sieve_runtime_env *renv, struct sieve_variable_storage *storage, 
 	unsigned int var_index, struct sieve_stringlist *flags)
 {
-	string_t *cur_flags;
-	
-	if ( storage != NULL ) {
-		if ( !sieve_variable_get_modifiable(storage, var_index, &cur_flags) )
-			return SIEVE_EXEC_BIN_CORRUPT;
-	} else
-		cur_flags = _get_flags_string(renv->oprtn->ext, renv->result);
-
+	string_t *cur_flags = ext_imap4flags_get_flag_variable
+		(renv, storage, var_index);
+		
 	if ( cur_flags != NULL ) {
 		string_t *flags_item;
 		int ret;
 
 		while ( (ret=sieve_stringlist_next_item(flags, &flags_item)) > 0 ) {
+			sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, 
+				"add flags `%s'", str_c(flags_item)); 
+
 			flags_list_add_flags(cur_flags, flags_item);
 		}
 
 		if ( ret < 0 ) return SIEVE_EXEC_BIN_CORRUPT;
+	
+		return SIEVE_EXEC_OK;
 	}
 
-	return SIEVE_EXEC_OK;
+	return SIEVE_EXEC_BIN_CORRUPT;
 }
 
 int ext_imap4flags_remove_flags
 (const struct sieve_runtime_env *renv, struct sieve_variable_storage *storage, 
 	unsigned int var_index, struct sieve_stringlist *flags)
 {
-	string_t *cur_flags;
-	
-	if ( storage != NULL ) {
-		if ( !sieve_variable_get_modifiable(storage, var_index, &cur_flags) )
-			return SIEVE_EXEC_BIN_CORRUPT;
-	} else
-		cur_flags = _get_flags_string(renv->oprtn->ext, renv->result);
-	
+	string_t *cur_flags = ext_imap4flags_get_flag_variable
+		(renv, storage, var_index);
+		
 	if ( cur_flags != NULL ) {
 		string_t *flags_item;
 		int ret;
 
 		while ( (ret=sieve_stringlist_next_item(flags, &flags_item)) > 0 ) {
+			sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, 
+				"remove flags `%s'", str_c(flags_item)); 
+
 			flags_list_remove_flags(cur_flags, flags_item);
 		}
 
 		if ( ret < 0 ) return SIEVE_EXEC_BIN_CORRUPT;
+	
+		return SIEVE_EXEC_OK;
 	}
 
-	return SIEVE_EXEC_OK;
+	return SIEVE_EXEC_BIN_CORRUPT;
 }
 
 /* Flag stringlist */
diff --git a/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c b/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
index aead5b0d5fb5b776f4efb8daff9f60ddd6ffd0cf..972e987d7c5159b9542d659ba74b17dfbbbb3349 100644
--- a/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+++ b/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
@@ -2,6 +2,7 @@
  */
 
 #include "lib.h"
+#include "str-sanitize.h"
 #include "mail-storage.h"
 #include "mail-namespace.h"
 
@@ -108,6 +109,7 @@ static int tst_mailboxexists_operation_execute
 {
 	struct sieve_stringlist *mailbox_names;
 	string_t *mailbox_item;
+	bool trace = FALSE; 
 	bool all_exist = TRUE;
 
 	/*
@@ -123,7 +125,12 @@ static int tst_mailboxexists_operation_execute
 	 * Perform operation
 	 */
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "mailboxexists test");
+	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS) ) {
+		sieve_runtime_trace(renv, 0, "mailboxexists test");
+		sieve_runtime_trace_descend(renv);
+
+		trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING);
+	}
 
 	if ( renv->scriptenv->user != NULL ) {
 		int ret;
@@ -138,6 +145,11 @@ static int tst_mailboxexists_operation_execute
 			/* Find the namespace */	
 			ns = mail_namespace_find(renv->scriptenv->user->namespaces, &mailbox);
 			if ( ns == NULL) {
+				if ( trace ) {
+					sieve_runtime_trace(renv, 0, "mailbox `%s' not found", 
+						str_sanitize(mailbox, 80));
+				}
+
 				all_exist = FALSE;
 				break;
 			}
@@ -145,17 +157,35 @@ static int tst_mailboxexists_operation_execute
 			/* Open the box */
 			box = mailbox_alloc(ns->list, mailbox, 0);
 			if ( mailbox_open(box) < 0 ) {
+				if ( trace ) {
+					sieve_runtime_trace(renv, 0, "mailbox `%s' cannot be opened", 
+						str_sanitize(mailbox, 80));
+				}
+
 				all_exist = FALSE;
 				mailbox_free(&box);
 				break;
 			}
 
 			/* Also fail when it is readonly */
-			if ( mailbox_is_readonly(box) )
+			if ( mailbox_is_readonly(box) ) {
+				if ( trace ) {
+					sieve_runtime_trace(renv, 0, "mailbox `%s' is read-only", 
+						str_sanitize(mailbox, 80));
+				}
+
 				all_exist = FALSE;
+				mailbox_free(&box);
+				break;
+			}
 
 			/* FIXME: check acl for 'p' or 'i' ACL permissions as required by RFC */
 
+			if ( trace ) {
+				sieve_runtime_trace(renv, 0, "mailbox `%s' exists", 
+					str_sanitize(mailbox, 80));
+			}
+
 			/* Close mailbox */
 			mailbox_free(&box);
 		}
@@ -165,6 +195,13 @@ static int tst_mailboxexists_operation_execute
 			return SIEVE_EXEC_BIN_CORRUPT;
 		}
 	}
+
+	if ( trace ) {
+		if ( all_exist )
+			sieve_runtime_trace(renv, 0, "all mailboxes are available");
+		else
+			sieve_runtime_trace(renv, 0, "some mailboxes are unavailable");
+	}
 	
 	sieve_interpreter_set_test_result(renv->interp, all_exist);
 	return SIEVE_EXEC_OK;
diff --git a/src/lib-sieve/plugins/regex/mcht-regex.c b/src/lib-sieve/plugins/regex/mcht-regex.c
index 793edcbf3309d4518793cb6d43d454c936bf7e42..7a6b28df0b8693fbd7b82bdc4c509568f6883b37 100644
--- a/src/lib-sieve/plugins/regex/mcht-regex.c
+++ b/src/lib-sieve/plugins/regex/mcht-regex.c
@@ -320,7 +320,7 @@ static int mcht_regex_match_keys
 
 					if ( trace ) {
 						sieve_runtime_trace(renv, 0,
-							"    with regex `%s' [id=%d] => %d", 
+							"with regex `%s' [id=%d] => %d", 
 							str_sanitize(str_c(key_item), 80),
 							array_count(&ctx->reg_expressions)-1, result);
 					}
@@ -347,7 +347,7 @@ static int mcht_regex_match_keys
 
 				if ( trace ) {
 					sieve_runtime_trace(renv, 0,
-						"    with compiled regex [id=%d] => %d", i, result);
+						"with compiled regex [id=%d] => %d", i, result);
 				}
 			}
 
diff --git a/src/lib-sieve/plugins/relational/mcht-count.c b/src/lib-sieve/plugins/relational/mcht-count.c
index 9ec75274b9b802054e1b9b3261feae62b7019ce4..98b417319c76f54b577737d08681a4eb41e626e0 100644
--- a/src/lib-sieve/plugins/relational/mcht-count.c
+++ b/src/lib-sieve/plugins/relational/mcht-count.c
@@ -83,9 +83,11 @@ static int mcht_count_match
 
 	if ( trace ) {
 		sieve_runtime_trace(renv, 0,
-			"  matching count value `%s'", str_sanitize(str_c(value), 80));
+			"matching count value `%s'", str_sanitize(str_c(value), 80));
 	}
 
+	sieve_runtime_trace_descend(renv);
+
   /* Match to all key values */
   key_item = NULL;
 	ret = 0;
@@ -97,10 +99,12 @@ static int mcht_count_match
 
 		if ( trace ) {
 			sieve_runtime_trace(renv, 0,
-				"    with key `%s' => %d", str_sanitize(str_c(key_item), 80), ret);
+				"with key `%s' => %d", str_sanitize(str_c(key_item), 80), ret);
 		}
 	}
 
+	sieve_runtime_trace_ascend(renv);
+
 	return ret;
 }
 
diff --git a/src/lib-sieve/plugins/vacation/cmd-vacation.c b/src/lib-sieve/plugins/vacation/cmd-vacation.c
index 01aaab83677ff5bca655cba0a8ee8e9f51a90173..ec2d452f8ffdb77a58ebcf8cd4a77630a2bfe6f2 100644
--- a/src/lib-sieve/plugins/vacation/cmd-vacation.c
+++ b/src/lib-sieve/plugins/vacation/cmd-vacation.c
@@ -608,8 +608,13 @@ static int ext_vacation_operation_execute
 		days = 1;
 
 	/* Trace */
-	
-	sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "vacation action");	
+
+	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_ACTIONS) ) {
+		sieve_runtime_trace(renv, 0, "vacation action");
+		sieve_runtime_trace_descend(renv);
+		sieve_runtime_trace(renv, 0, "auto-reply with message `%s'",
+			str_sanitize(str_c(reason), 80));
+	}	
 
 	/* Check and normalize :from address */
 	if ( from != NULL ) {
diff --git a/src/lib-sieve/plugins/variables/cmd-set.c b/src/lib-sieve/plugins/variables/cmd-set.c
index 1f1e515643d4eb5dba9a68ccd27ce116f5fa13a1..aafcb523e134436502cae8621c3ae379205c59cb 100644
--- a/src/lib-sieve/plugins/variables/cmd-set.c
+++ b/src/lib-sieve/plugins/variables/cmd-set.c
@@ -307,7 +307,8 @@ static int cmd_set_operation_execute
 	 * Determine and assign the value 
 	 */
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "set:");
+	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "set command");
+	sieve_runtime_trace_descend(renv);
 
 	/* Hold value within limits */
 	if ( str_len(value) > EXT_VARIABLES_MAX_VARIABLE_SIZE )
@@ -334,7 +335,7 @@ static int cmd_set_operation_execute
 					}
 
 					sieve_runtime_trace_here
-						(renv, SIEVE_TRLVL_COMMANDS, " :%s \"%s\" => \"%s\"",
+						(renv, SIEVE_TRLVL_COMMANDS, "modify :%s \"%s\" => \"%s\"",
 							sieve_variables_modifier_name(&modf), str_c(value), str_c(new_value));
 
 					value = new_value;
@@ -359,7 +360,7 @@ static int cmd_set_operation_execute
 					(void)sieve_variable_get_identifier(storage, var_index, &var_name);
 					var_id = sieve_variable_get_varid(storage, var_index);
 
-					sieve_runtime_trace_here(renv, 0, " %s [%s] = \"%s\"",
+					sieve_runtime_trace_here(renv, 0, "assign `%s' [%s] = \"%s\"",
 						var_name, var_id, str_c(value));
 				}
 			}
diff --git a/src/lib-sieve/sieve-address-parts.c b/src/lib-sieve/sieve-address-parts.c
index 540faf4ffa10d5d5bb0ab2340a024e3f66e7425c..5971dbf76b2fc663d2ae024f36b80960bef2057d 100644
--- a/src/lib-sieve/sieve-address-parts.c
+++ b/src/lib-sieve/sieve-address-parts.c
@@ -236,6 +236,8 @@ static void sieve_address_part_stringlist_reset
 	(struct sieve_stringlist *_strlist);
 static int sieve_address_part_stringlist_get_length
 	(struct sieve_stringlist *_strlist);
+static void sieve_address_part_stringlist_set_trace
+(struct sieve_stringlist *_strlist, bool trace);
 
 struct sieve_address_part_stringlist {
 	struct sieve_stringlist strlist;
@@ -255,6 +257,7 @@ struct sieve_stringlist *sieve_address_part_stringlist_create
 	strlist->strlist.next_item = sieve_address_part_stringlist_next_item;
 	strlist->strlist.reset = sieve_address_part_stringlist_reset;
 	strlist->strlist.get_length = sieve_address_part_stringlist_get_length;
+	strlist->strlist.set_trace = sieve_address_part_stringlist_set_trace;
 
 	strlist->addrp = addrp;
 	strlist->addresses = addresses;
@@ -280,6 +283,13 @@ static int sieve_address_part_stringlist_next_item
 		
 		if ( item.local_part == NULL ) {
 			if ( item_unparsed != NULL ) {
+				if ( _strlist->trace ) {
+					sieve_runtime_trace(_strlist->runenv, 0,
+						"extracting `%s' part from non-address value `%s'",
+						sieve_address_part_name(strlist->addrp),
+						str_sanitize(str_c(item_unparsed), 80));
+				}
+
 				if ( str_len(item_unparsed) == 0 ||
 					sieve_address_part_is(strlist->addrp, all_address_part) )
 					*str_r = item_unparsed;
@@ -288,6 +298,13 @@ static int sieve_address_part_stringlist_next_item
 			const struct sieve_address_part *addrp = strlist->addrp;
 			const char *part = NULL;
 
+			if ( _strlist->trace ) {
+				sieve_runtime_trace(_strlist->runenv, 0,
+					"extracting `%s' part from address `%s'",
+					sieve_address_part_name(strlist->addrp),
+					str_sanitize(sieve_address_to_string(&item), 80));
+			}
+
 			if ( addrp->def != NULL && addrp->def->extract_from ) 
 				part = addrp->def->extract_from(addrp, &item);
 
@@ -317,6 +334,15 @@ static int sieve_address_part_stringlist_get_length
 	return sieve_address_list_get_length(strlist->addresses);
 }
 
+static void sieve_address_part_stringlist_set_trace
+(struct sieve_stringlist *_strlist, bool trace)
+{
+	struct sieve_address_part_stringlist *strlist = 
+		(struct sieve_address_part_stringlist *)_strlist;
+
+	sieve_address_list_set_trace(strlist->addresses, trace);
+}
+
 /* 
  * Default ADDRESS-PART, MATCH-TYPE, COMPARATOR access
  */
diff --git a/src/lib-sieve/sieve-address-parts.h b/src/lib-sieve/sieve-address-parts.h
index c72bb1a81778f8ff704d6ca168633510062c015d..8c8797e01d379339d746b57a20a3907b0b08a052 100644
--- a/src/lib-sieve/sieve-address-parts.h
+++ b/src/lib-sieve/sieve-address-parts.h
@@ -35,6 +35,8 @@ struct sieve_address_part {
 #define SIEVE_ADDRESS_PART_DEFAULT(definition) \
 	{ SIEVE_OBJECT_DEFAULT(definition), &(definition) };
 
+#define sieve_address_part_name(addrp) \
+	( (addrp)->object.def->identifier )
 #define sieve_address_part_is(addrp, definition) \
 	( (addrp)->def == &(definition) )
 
diff --git a/src/lib-sieve/sieve-address.c b/src/lib-sieve/sieve-address.c
index ca7b70d59b96bd952467260c5b43f34903fefdbf..e89b40a5e824eb27c527a2e1ae85d20992043616 100644
--- a/src/lib-sieve/sieve-address.c
+++ b/src/lib-sieve/sieve-address.c
@@ -8,6 +8,7 @@
 #include "message-address.h"
 
 #include "sieve-common.h"
+#include "sieve-runtime-trace.h"
 
 #include "sieve-address.h"
 
@@ -26,6 +27,8 @@ static int sieve_header_address_list_next_item
 		string_t **unparsed_r);
 static void sieve_header_address_list_reset
 	(struct sieve_stringlist *_strlist);
+static void sieve_header_address_list_set_trace
+	(struct sieve_stringlist *_strlist, bool trace);
 
 /* Stringlist object */
 
@@ -46,6 +49,7 @@ struct sieve_address_list *sieve_header_address_list_create
 	addrlist->addrlist.strlist.next_item = 
 		sieve_header_address_list_next_string_item;
 	addrlist->addrlist.strlist.reset = sieve_header_address_list_reset;
+	addrlist->addrlist.strlist.set_trace = sieve_header_address_list_set_trace;
 	addrlist->addrlist.next_item = sieve_header_address_list_next_item;
 	addrlist->field_values = field_values;
   
@@ -74,6 +78,12 @@ static int sieve_header_address_list_next_item
 			<= 0 )
 			return ret;
 
+		if ( _addrlist->strlist.trace ) {
+			sieve_runtime_trace(_addrlist->strlist.runenv, 0,
+				"parsing address header value `%s'",
+				str_sanitize(str_c(value_item), 80));
+		}
+
 		addrlist->cur_address = message_address_parse
 			(pool_datastack_create(), (const unsigned char *) str_data(value_item), 
 				str_len(value_item), 256, FALSE);
@@ -149,6 +159,15 @@ static void sieve_header_address_list_reset
 	addrlist->cur_address = NULL;
 }
 
+static void sieve_header_address_list_set_trace
+(struct sieve_stringlist *_strlist, bool trace)
+{
+	struct sieve_header_address_list *addrlist = 
+		(struct sieve_header_address_list *)_strlist;
+
+	sieve_stringlist_set_trace(addrlist->field_values, trace);
+}
+
 /*
  * RFC 2822 addresses
  */
diff --git a/src/lib-sieve/sieve-address.h b/src/lib-sieve/sieve-address.h
index 9ae4c2cc94a523ab45e86f3838c6538660768bc4..95bc2308a0abd132fe82418b0c0134bb2ccab9cd 100644
--- a/src/lib-sieve/sieve-address.h
+++ b/src/lib-sieve/sieve-address.h
@@ -22,10 +22,12 @@ struct sieve_address {
 static inline const char *sieve_address_to_string
 (const struct sieve_address *address) 
 {
-	if ( address == NULL || address->local_part == NULL ||
-		address->domain == NULL )
+	if ( address == NULL || address->local_part == NULL )
 		return NULL;
 
+	if ( address->domain == NULL )
+		return address->local_part;
+
 	return t_strconcat(address->local_part, "@", address->domain, NULL);
 }
 
@@ -60,6 +62,12 @@ static inline int sieve_address_list_get_length
 	return sieve_stringlist_get_length(&addrlist->strlist);
 }
 
+static inline void sieve_address_list_set_trace
+(struct sieve_address_list *addrlist, bool trace)
+{
+	return sieve_stringlist_set_trace(&addrlist->strlist, trace);
+}
+
 /*
  * Header address list
  */
diff --git a/src/lib-sieve/sieve-code.c b/src/lib-sieve/sieve-code.c
index fb81d13ec0955d04988d83db0b42d21831bcd64c..d64f77d4b98a7ebf1d914c39cb9f2b4b240181ca 100644
--- a/src/lib-sieve/sieve-code.c
+++ b/src/lib-sieve/sieve-code.c
@@ -1047,6 +1047,7 @@ static int opc_jmptrue_execute
 	bool result = sieve_interpreter_get_test_result(renv->interp);
 	
 	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "jump if result is true");
+	sieve_runtime_trace_descend(renv);
 	
 	return sieve_interpreter_program_jump(renv->interp, result);
 }
@@ -1057,6 +1058,7 @@ static int opc_jmpfalse_execute
 	bool result = sieve_interpreter_get_test_result(renv->interp);
 	
 	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "jump if result is false");
-	
+	sieve_runtime_trace_descend(renv);
+
 	return sieve_interpreter_program_jump(renv->interp, !result);
 }	
diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h
index 260d461103869d417ecbbaaea11ed1676dbd56c8..dab8d5d77263feb7bdbae7919cde811d677d91dd 100644
--- a/src/lib-sieve/sieve-common.h
+++ b/src/lib-sieve/sieve-common.h
@@ -64,8 +64,10 @@ struct sieve_jumplist;
 struct sieve_generator;
 struct sieve_codegen_env;
 
-/* sieve-interpreter.h */
+/* sieve-runtime.h */
 struct sieve_runtime_env;
+
+/* sieve-interpreter.h */
 struct sieve_interpreter;
 
 /* sieve-dump.h */
diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c
index 6f7c4ff16bb795c3fd9e2b01795df951b83eb8b7..4a0e9a1162b2ffc60f3eaa9fa0c22266154e26e4 100644
--- a/src/lib-sieve/sieve-interpreter.c
+++ b/src/lib-sieve/sieve-interpreter.c
@@ -20,6 +20,7 @@
 #include "sieve-binary.h"
 #include "sieve-result.h"
 #include "sieve-comparators.h"
+#include "sieve-runtime-trace.h"
 
 #include "sieve-interpreter.h"
 
@@ -58,6 +59,7 @@ struct sieve_interpreter {
 	
 	/* Runtime environment */
 	struct sieve_runtime_env runenv;
+	struct sieve_runtime_trace trace;
 
 	/* Current operation */
 	struct sieve_operation oprtn; 
@@ -99,8 +101,13 @@ static struct sieve_interpreter *_sieve_interpreter_create
 	interp->runenv.svinst = svinst;
 	interp->runenv.msgdata = msgdata;
 	interp->runenv.scriptenv = senv;
-	interp->runenv.trace_stream = senv->trace_stream;
-	interp->runenv.trace_config = senv->trace_config;
+
+	if ( senv->trace_stream != NULL ) {
+		interp->trace.stream = senv->trace_stream;
+		interp->trace.config = senv->trace_config;
+		interp->trace.indent = 0;
+		interp->runenv.trace = &interp->trace;
+	}
 
 	if ( senv->exec_status == NULL ) 
 		interp->runenv.exec_status = p_new(interp->pool, struct sieve_exec_status, 1);
@@ -431,7 +438,7 @@ int sieve_interpreter_program_jump
 				unsigned int jmp_line = 
 					sieve_runtime_get_source_location(renv, jmp_addr);
 
-				if ( (renv->trace_config.flags & SIEVE_TRFLG_ADDRESSES) > 0 ) {
+				if ( sieve_runtime_trace_hasflag(renv, SIEVE_TRFLG_ADDRESSES) ) {
 					sieve_runtime_trace(renv, 0, "jumping to line %d [%08llx]", 
 						jmp_line, (long long unsigned int) jmp_addr);
 				} else {
@@ -477,6 +484,8 @@ static int sieve_interpreter_operation_execute
 	struct sieve_operation *oprtn = &(interp->oprtn);
 	sieve_size_t *address = &(interp->runenv.pc);
 
+	sieve_runtime_trace_toplevel(&interp->runenv);
+
 	/* Read the operation */
 	if ( sieve_operation_read(interp->runenv.sblock, address, oprtn) ) {
 		const struct sieve_operation_def *op = oprtn->def;
diff --git a/src/lib-sieve/sieve-match.c b/src/lib-sieve/sieve-match.c
index b0b2acda23ce5b74334d97447c6edac21030be8c..19c0a2e36739fce0f6a9b5d6c5dcf954e3045b4e 100644
--- a/src/lib-sieve/sieve-match.c
+++ b/src/lib-sieve/sieve-match.c
@@ -50,8 +50,9 @@ struct sieve_match_context *sieve_match_begin
 
 	/* Trace */
 	if ( mctx->trace ) {
+		sieve_runtime_trace_descend(renv);
 		sieve_runtime_trace(renv, 0,
-			"  starting `:%s' match with `%s' comparator:",
+			"starting `:%s' match with `%s' comparator:",
 			sieve_match_type_name(mcht), sieve_comparator_name(cmp));
 	}
 
@@ -73,13 +74,18 @@ int sieve_match_value
 
 	if ( mctx->trace ) {
 		sieve_runtime_trace(renv, 0,
-			"  matching value `%s'", str_sanitize(value, 80));
+			"matching value `%s'", str_sanitize(value, 80));
 	}
 
 	/* Match to key values */
 	
 	sieve_stringlist_reset(key_list);
 
+	if ( mctx->trace )
+		sieve_stringlist_set_trace(key_list, TRUE);
+
+	sieve_runtime_trace_descend(renv);
+
 	if ( mcht->def->match_keys != NULL ) {
 		/* Call match-type's own key match handler */
 		result = mcht->def->match_keys(mctx, value, value_size, key_list);
@@ -96,7 +102,7 @@ int sieve_match_value
 
 				if ( mctx->trace ) {
 					sieve_runtime_trace(renv, 0,
-						"    with key `%s' => %d", str_sanitize(str_c(key_item), 80),
+						"with key `%s' => %d", str_sanitize(str_c(key_item), 80),
 						result);
 				}
 			} T_END;
@@ -105,6 +111,8 @@ int sieve_match_value
 		if ( ret < 0 ) result = -1;
 	}
 
+	sieve_runtime_trace_ascend(renv);
+
 	if ( mctx->status < 0 || result < 0 )
 		mctx->status = -1;
 	else 
@@ -124,8 +132,9 @@ int sieve_match_end(struct sieve_match_context **mctx)
 	pool_unref(&(*mctx)->pool);
 
 	sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
-		"  finishing match with result: %s", 
+		"finishing match with result: %s", 
 		( result > 0 ? "matched" : ( result < 0 ? "error" : "not matched" ) ));
+	sieve_runtime_trace_ascend(renv);
 
 	return result;
 }
@@ -148,9 +157,12 @@ int sieve_match
 
 	sieve_stringlist_reset(value_list);
 
+	if ( mctx->trace )
+		sieve_stringlist_set_trace(value_list, TRUE);
+
 	if ( mcht->def->match != NULL ) {
 		/* Call match-type's match handler */
-		result = mcht->def->match(mctx, value_list, key_list); 
+		result = mctx->status = mcht->def->match(mctx, value_list, key_list); 
 
 	} else {
 		/* Default value match loop */
diff --git a/src/lib-sieve/sieve-message.c b/src/lib-sieve/sieve-message.c
index a5f890c73885b44c365c8525d2e1100466d8e818..30b7472695e99ba3724febdba5d4a0d368c195ad 100644
--- a/src/lib-sieve/sieve-message.c
+++ b/src/lib-sieve/sieve-message.c
@@ -6,6 +6,7 @@
 #include "mempool.h"
 #include "array.h"
 #include "str.h"
+#include "str-sanitize.h"
 #include "mail-storage.h"
 
 #include "sieve-common.h"
@@ -13,6 +14,7 @@
 #include "sieve-error.h"
 #include "sieve-extensions.h"
 #include "sieve-runtime.h"
+#include "sieve-runtime-trace.h"
 #include "sieve-address.h"
 
 #include "sieve-message.h"
@@ -275,6 +277,12 @@ static int sieve_message_header_stringlist_next_item
 			<= 0 )
 			return ret;
 
+		if ( _strlist->trace ) {
+			sieve_runtime_trace(renv, 0,
+				"extracting `%s' headers from message",
+				str_sanitize(str_c(hdr_item), 80));
+		}
+
 		/* Fetch all matching headers from the e-mail */
 		if ( mail_get_headers_utf8(mail, str_c(hdr_item), &strlist->headers) < 0 ||
 			( strlist->headers != NULL && strlist->headers[0] == NULL ) ) {
diff --git a/src/lib-sieve/sieve-runtime-trace.c b/src/lib-sieve/sieve-runtime-trace.c
index 7a29b8445b88c723a1c5cb9d8ad4f397cfe49a89..07e7a4746900b25167dc70a9cea9ff163a6398e1 100644
--- a/src/lib-sieve/sieve-runtime-trace.c
+++ b/src/lib-sieve/sieve-runtime-trace.c
@@ -14,15 +14,19 @@ static inline string_t *_trace_line_new
 (const struct sieve_runtime_env *renv, sieve_size_t address, unsigned int cmd_line)
 {
 	string_t *trline;
+	unsigned int i;
 	
 	trline = t_str_new(128);
-	if ( (renv->trace_config.flags & SIEVE_TRFLG_ADDRESSES) > 0 )
+	if ( (renv->trace->config.flags & SIEVE_TRFLG_ADDRESSES) > 0 )
 		str_printfa(trline, "%08llx: ", (unsigned long long) address);
 	if ( cmd_line > 0 )	
 		str_printfa(trline, "%4d: ", cmd_line); 
 	else
 		str_append(trline, "      "); 
 
+	for ( i = 0; i < renv->trace->indent; i++ )
+		str_append(trline, "  "); 
+
 	return trline;
 }
 
@@ -31,13 +35,13 @@ static inline void _trace_line_print
 {
 	str_append_c(trline, '\n');
 
-	o_stream_send(renv->trace_stream, str_data(trline), str_len(trline));
+	o_stream_send(renv->trace->stream, str_data(trline), str_len(trline));
 }
 
 static inline void _trace_line_print_empty
 (const struct sieve_runtime_env *renv)
 {
-	o_stream_send_str(renv->trace_stream, "\n");
+	o_stream_send_str(renv->trace->stream, "\n");
 }
 
 /*
@@ -59,8 +63,8 @@ void _sieve_runtime_trace_operand_error
 (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
 	const char *field_name, const char *fmt, va_list args)
 {
-	string_t *trline = _trace_line_new
-		(renv, oprnd->address, sieve_runtime_get_source_location(renv, oprnd->address));
+	string_t *trline = _trace_line_new(renv, oprnd->address,
+		sieve_runtime_get_source_location(renv, oprnd->address));
 
 	str_printfa(trline, "%s: #ERROR#: ", sieve_operation_mnemonic(renv->oprtn));
 
diff --git a/src/lib-sieve/sieve-runtime-trace.h b/src/lib-sieve/sieve-runtime-trace.h
index 00c4a2c47eac629eca8d37d501e1d157f77d55a0..a22088eff0396ccafc805425269d03f65f91bd11 100644
--- a/src/lib-sieve/sieve-runtime-trace.h
+++ b/src/lib-sieve/sieve-runtime-trace.h
@@ -8,13 +8,44 @@
  * Runtime trace
  */
 
+struct sieve_runtime_trace {
+	struct sieve_trace_config config;
+	struct ostream *stream;
+	unsigned int indent;
+};
+
 /* Trace configuration */
 
 static inline bool sieve_runtime_trace_active
 (const struct sieve_runtime_env *renv, sieve_trace_level_t trace_level) 
 {
-	return ( renv->trace_stream != NULL && 
-		trace_level <= renv->trace_config.level );
+	return ( renv->trace != NULL && trace_level <= renv->trace->config.level );
+}
+
+static inline bool sieve_runtime_trace_hasflag
+(const struct sieve_runtime_env *renv, unsigned int flag) 
+{
+	return ( renv->trace != NULL && (renv->trace->config.flags & flag) != 0 );
+}
+
+/* Trace indent */
+
+static inline void sieve_runtime_trace_descend
+(const struct sieve_runtime_env *renv)
+{
+	if ( renv->trace != NULL ) renv->trace->indent++;
+}
+
+static inline void sieve_runtime_trace_ascend
+(const struct sieve_runtime_env *renv)
+{
+	if ( renv->trace != NULL ) renv->trace->indent--;
+}
+
+static inline void sieve_runtime_trace_toplevel
+(const struct sieve_runtime_env *renv)
+{
+	if ( renv->trace != NULL ) renv->trace->indent = 0;
 }
 
 /* Trace errors */
@@ -40,8 +71,7 @@ static inline void sieve_runtime_trace_error
 	va_list args;
 	
 	va_start(args, fmt);
-	if ( renv->trace_stream != NULL && 
-		renv->trace_config.level > SIEVE_TRLVL_NONE )
+	if ( renv->trace != NULL )
 		_sieve_runtime_trace_error(renv, fmt, args);	
 	va_end(args);
 }
@@ -53,8 +83,7 @@ static inline void sieve_runtime_trace_operand_error
 	va_list args;
 	
 	va_start(args, fmt);
-	if ( renv->trace_stream != NULL && 
-		renv->trace_config.level > SIEVE_TRLVL_NONE )
+	if ( renv->trace != NULL )
 		_sieve_runtime_trace_operand_error(renv, oprnd, field_name, fmt, args);
 	va_end(args);
 }
@@ -76,7 +105,7 @@ static inline void sieve_runtime_trace
 
 	va_start(args, fmt);
 
-	if ( renv->trace_stream != NULL && trace_level <= renv->trace_config.level ) {
+	if ( renv->trace != NULL && trace_level <= renv->trace->config.level ) {
 		_sieve_runtime_trace(renv, fmt, args);
 	}
 
@@ -99,7 +128,7 @@ static inline void sieve_runtime_trace_address
 
 	va_start(args, fmt);
 
-	if ( renv->trace_stream != NULL && trace_level <= renv->trace_config.level ) {
+	if ( renv->trace != NULL && trace_level <= renv->trace->config.level ) {
 		_sieve_runtime_trace_address(renv, address, fmt, args);
 	}
 
@@ -114,7 +143,7 @@ static inline void sieve_runtime_trace_here
 
 	va_start(args, fmt);
 
-	if ( renv->trace_stream != NULL && trace_level <= renv->trace_config.level ) {
+	if ( renv->trace != NULL && trace_level <= renv->trace->config.level ) {
 		_sieve_runtime_trace_address(renv, renv->pc, fmt, args);
 	}
 
@@ -130,21 +159,21 @@ void _sieve_runtime_trace_sep(const struct sieve_runtime_env *renv);
 static inline void sieve_runtime_trace_begin
 (const struct sieve_runtime_env *renv)
 {
-	if ( renv->trace_stream != NULL )
+	if ( renv->trace != NULL )
 		_sieve_runtime_trace_begin(renv);
 }
 
 static inline void sieve_runtime_trace_end
 (const struct sieve_runtime_env *renv)
 {
-	if ( renv->trace_stream != NULL )
+	if ( renv->trace != NULL )
 		_sieve_runtime_trace_end(renv);
 }
 
 static inline void sieve_runtime_trace_sep
 (const struct sieve_runtime_env *renv)
 {
-	if ( renv->trace_stream != NULL )
+	if ( renv->trace != NULL )
 		_sieve_runtime_trace_sep(renv);
 }
 
diff --git a/src/lib-sieve/sieve-runtime.h b/src/lib-sieve/sieve-runtime.h
index 26659674ccec313b3b5717537b2cdcd0c2d5ff1d..15b4c1a6b5f5a458060cca5c6da94f99e0f10ed5 100644
--- a/src/lib-sieve/sieve-runtime.h
+++ b/src/lib-sieve/sieve-runtime.h
@@ -36,8 +36,7 @@ struct sieve_runtime_env {
 	struct sieve_result *result;
 
 	/* Runtime tracing */
-	struct ostream *trace_stream;
-	struct sieve_trace_config trace_config;
+	struct sieve_runtime_trace *trace;
 };
 
 #endif /* __SIEVE_RUNTIME_H */
diff --git a/src/lib-sieve/sieve-stringlist.h b/src/lib-sieve/sieve-stringlist.h
index c9e1ebaced539ae457a627b3f51a9b00d7d6fa78..9729bdb0f7781f9dae8e6b1e4c956da9bcc122e8 100644
--- a/src/lib-sieve/sieve-stringlist.h
+++ b/src/lib-sieve/sieve-stringlist.h
@@ -6,8 +6,6 @@
  */
 
 struct sieve_stringlist {
-	const struct sieve_runtime_env *runenv;
-
 	int (*next_item)
 		(struct sieve_stringlist *strlist, string_t **str_r);
 	void (*reset)
@@ -18,8 +16,23 @@ struct sieve_stringlist {
 	bool (*read_all)
 		(struct sieve_stringlist *strlist, pool_t pool,
 			const char * const **list_r);
+
+	void (*set_trace)
+		(struct sieve_stringlist *strlist, bool trace);
+
+	const struct sieve_runtime_env *runenv;
+	unsigned int trace:1;
 };
 
+static inline void sieve_stringlist_set_trace
+(struct sieve_stringlist *strlist, bool trace)
+{
+	strlist->trace = trace;
+
+	if ( strlist->set_trace != NULL )
+		strlist->set_trace(strlist, trace);
+}
+
 static inline int sieve_stringlist_next_item
 (struct sieve_stringlist *strlist, string_t **str_r) 
 {
diff --git a/src/lib-sieve/tst-exists.c b/src/lib-sieve/tst-exists.c
index 6231f4c35ac60fd7355555665a85b871c51ad398..4aa6c55aaa10913f3257d6dd601646b50734977f 100644
--- a/src/lib-sieve/tst-exists.c
+++ b/src/lib-sieve/tst-exists.c
@@ -125,7 +125,8 @@ static int tst_exists_operation_execute
 	 */
 
 	sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "exists test");
-		
+	sieve_runtime_trace_descend(renv);
+
 	/* Iterate through all requested headers to match (must find all specified) */
 	hdr_item = NULL;
 	matched = TRUE;
@@ -140,9 +141,14 @@ static int tst_exists_operation_execute
 		}	
 	
 		sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
-        	"  header `%s' %s", str_sanitize(str_c(hdr_item), 80),
-			( matched ? "exists" : "missing" ));
+        	"header `%s' %s", str_sanitize(str_c(hdr_item), 80),
+			( matched ? "exists" : "is missing" ));
 	}
+
+	if ( matched )
+		sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING, "all headers exist");
+	else
+		sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING, "headers are missing");
 	
 	/* Set test result for subsequent conditional jump */
 	if ( ret >= 0 ) {
diff --git a/src/lib-sieve/tst-size.c b/src/lib-sieve/tst-size.c
index d5fd31a563b61cffd0b93ab6d82e7c10cff25756..d92430745e25c706a0971551d0c1e51aa3bc0242 100644
--- a/src/lib-sieve/tst-size.c
+++ b/src/lib-sieve/tst-size.c
@@ -269,11 +269,29 @@ static int tst_size_operation_execute
 	/* Perform the test */
 	if ( sieve_operation_is(renv->oprtn, tst_size_over_operation) ) {
 		sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "size :over test");
+		
+		if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING) ) {
+			sieve_runtime_trace_descend(renv);
+
+			sieve_runtime_trace(renv, 0,
+				"comparing message size %"PRIuSIZE_T, mail_size);
+			sieve_runtime_trace(renv, 0,
+				"with upper limit %"PRIuSIZE_T, limit);
+		}
 
 		sieve_interpreter_set_test_result(renv->interp, (mail_size > limit));
 	} else {
 		sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "size :under test");
 
+		if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING) ) {
+			sieve_runtime_trace_descend(renv);
+
+			sieve_runtime_trace(renv, 0,
+				"comparing message size %"PRIuSIZE_T, mail_size);
+			sieve_runtime_trace(renv, 0,
+				"with lower limit %"PRIuSIZE_T, limit);
+		}
+
 		sieve_interpreter_set_test_result(renv->interp, (mail_size < limit));
 	}
 
diff --git a/src/testsuite/cmd-test-binary.c b/src/testsuite/cmd-test-binary.c
index 6f9d48608ae7affd1a5e46317188d9eb756fa84e..a8aef73278275c241406c38f799ca419612bce92 100644
--- a/src/testsuite/cmd-test-binary.c
+++ b/src/testsuite/cmd-test-binary.c
@@ -239,8 +239,11 @@ static int cmd_test_binary_operation_execute
 	if ( sieve_operation_is(oprtn, test_binary_load_operation) ) {
 		struct sieve_binary *sbin = testsuite_binary_load(str_c(binary_name));
 
-		sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
-			"binary :load %s", str_c(binary_name));
+		if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+			sieve_runtime_trace(renv, 0, "testsuite: test_binary command");
+			sieve_runtime_trace_descend(renv);
+			sieve_runtime_trace(renv, 0, "load binary `%s'", str_c(binary_name));
+		}
 
 		if ( sbin != NULL ) {
 			testsuite_script_set_binary(sbin);
@@ -254,8 +257,11 @@ static int cmd_test_binary_operation_execute
 	} else if ( sieve_operation_is(oprtn, test_binary_save_operation) ) {
 		struct sieve_binary *sbin = testsuite_script_get_binary();
 
-		sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
-			"binary :save %s", str_c(binary_name));
+		if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+			sieve_runtime_trace(renv, 0, "testsuite: test_binary command");
+			sieve_runtime_trace_descend(renv);
+			sieve_runtime_trace(renv, 0, "save binary `%s'", str_c(binary_name));
+		}
 
 		if ( sbin != NULL ) 
 			testsuite_binary_save(sbin, str_c(binary_name));
diff --git a/src/testsuite/cmd-test-config.c b/src/testsuite/cmd-test-config.c
index 5082bc9b94beb13cde0036c0add621988d14c923..91d2ca61e2a31f66e0999992feb5c1db4d16c93c 100644
--- a/src/testsuite/cmd-test-config.c
+++ b/src/testsuite/cmd-test-config.c
@@ -335,8 +335,13 @@ static int cmd_test_config_set_operation_execute
 	 * Perform operation
 	 */
 		
-	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
-		"test_config :set %s = `%s'", str_c(setting), str_c(value));
+	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+		sieve_runtime_trace(renv, 0,
+			"testsuite: test_config command");
+		sieve_runtime_trace_descend(renv);
+		sieve_runtime_trace(renv, 0, "set config `%s' = `%s'", 
+			str_c(setting), str_c(value));
+	}
 
 	testsuite_setting_set(str_c(setting), str_c(value));
 
@@ -360,8 +365,12 @@ static int cmd_test_config_unset_operation_execute
 	 * Perform operation
 	 */
 		
-	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
-		"test_config :unset `%s'", str_c(setting));
+	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+		sieve_runtime_trace(renv, 0,
+			"testsuite: test_config command");
+		sieve_runtime_trace_descend(renv);
+		sieve_runtime_trace(renv, 0, "unset config `%s'", str_c(setting));
+	}
 
 	testsuite_setting_unset(str_c(setting));
 
@@ -385,9 +394,14 @@ static int cmd_test_config_reload_operation_execute
 	/*
 	 * Perform operation
 	 */
-		
-	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
-		"test_config :reload `%s'", str_c(extension));
+
+	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+		sieve_runtime_trace(renv, 0,
+			"testsuite: test_config command");
+		sieve_runtime_trace_descend(renv);
+		sieve_runtime_trace(renv, 0, "reload configuration for extension `%s'", 
+			str_c(extension));
+	}
 
 	ext = sieve_extension_get_by_name(renv->svinst, str_c(extension));
 	if ( ext == NULL ) {
diff --git a/src/testsuite/cmd-test-fail.c b/src/testsuite/cmd-test-fail.c
index 2ee26f3a96b681e3c193a1fe34df44641c452e5c..238acc05315cab80989161f521e181a77ebc5630 100644
--- a/src/testsuite/cmd-test-fail.c
+++ b/src/testsuite/cmd-test-fail.c
@@ -135,7 +135,8 @@ static int cmd_test_fail_operation_execute
 	if ( !sieve_opr_string_read(renv, address, "reason", &reason) )
 		return SIEVE_EXEC_BIN_CORRUPT;
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "TEST FAIL");
+	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
+		"testsuite: test_fail command; FAIL current test");
 
 	testsuite_test_fail(reason);
 	
diff --git a/src/testsuite/cmd-test-mailbox.c b/src/testsuite/cmd-test-mailbox.c
index ce6db518f0e960d8eb2f2889cc5188a05680e7ad..8ab5cc345855e627c14c0aba455dbe6ac5124409 100644
--- a/src/testsuite/cmd-test-mailbox.c
+++ b/src/testsuite/cmd-test-mailbox.c
@@ -238,8 +238,11 @@ static int cmd_test_mailbox_operation_execute
 	 */
 		
 	if ( sieve_operation_is(oprtn, test_mailbox_create_operation) ) {
-		sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
-			"test_mailbox :create `%s'", str_c(mailbox));
+		if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+			sieve_runtime_trace(renv, 0, "testsuite/test_mailbox command");
+			sieve_runtime_trace_descend(renv);
+			sieve_runtime_trace(renv, 0, "create mailbox `%s'", str_c(mailbox));
+		}
 
 		testsuite_mailstore_mailbox_create(renv, str_c(mailbox));
 	}
diff --git a/src/testsuite/cmd-test-message.c b/src/testsuite/cmd-test-message.c
index c4ea11c258a9960bf21d0257dacfa78dfad9396c..2623e4e35e0094d72aab7d6e5df8d49f738090fe 100644
--- a/src/testsuite/cmd-test-message.c
+++ b/src/testsuite/cmd-test-message.c
@@ -321,13 +321,24 @@ static int cmd_test_message_smtp_operation_execute
 	/*
 	 * Perform operation
 	 */
-		
-	if ( is_test )
-		sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
-			"test_message test [smtp index=%d]", msg_index);
-	else
-		sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
-			"text_message command [smtp index=%d]", msg_index);
+
+	if ( is_test ) {
+		if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS) ) {
+			sieve_runtime_trace(renv, 0, 
+				"testsuite: test_message test");
+			sieve_runtime_trace_descend(renv);
+			sieve_runtime_trace(renv, 0, 
+				"check and retrieve smtp message [index=%d]", msg_index);
+		}
+	} else {
+		if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+			sieve_runtime_trace(renv, 0, 
+				"testsuite: test_message command");
+			sieve_runtime_trace_descend(renv);
+			sieve_runtime_trace(renv, 0, 
+				"retrieve smtp message [index=%d]", msg_index);
+		}
+	}
 
 	result = testsuite_smtp_get(renv, msg_index);
 
@@ -371,13 +382,26 @@ static int cmd_test_message_mailbox_operation_execute
 	/*
 	 * Perform operation
 	 */
-
-	if ( is_test ) 		
-		sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, 
-			"test_message test [mailbox=`%s' index=%d]", str_c(folder), msg_index);
-	else
-		sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, 
-			"test_message command [mailbox=`%s' index=%d]", str_c(folder), msg_index);
+ 
+	if ( is_test ) {
+		if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS) ) {
+			sieve_runtime_trace(renv, 0, 
+				"testsuite: test_message test");
+			sieve_runtime_trace_descend(renv);
+			sieve_runtime_trace(renv, 0, 
+				"check and retrieve mailbox message [mailbox=`%s' index=%d]", 
+				str_c(folder), msg_index);
+		}
+	} else {
+		if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+			sieve_runtime_trace(renv, 0, 
+				"testsuite: test_message command");
+			sieve_runtime_trace_descend(renv);
+			sieve_runtime_trace(renv, 0, 
+				"retrieve mailbox message [mailbox=`%s' index=%d]", 
+				str_c(folder), msg_index);
+		}
+	}
 
 	result = testsuite_mailstore_mail_index(renv, str_c(folder), msg_index);
 
diff --git a/src/testsuite/cmd-test-result-print.c b/src/testsuite/cmd-test-result-print.c
index 4af964976e7a3237de11fe211e9202e1a5a38103..6858cc0889288ea1c7b3a7361c68a79367c2f8c5 100644
--- a/src/testsuite/cmd-test-result-print.c
+++ b/src/testsuite/cmd-test-result-print.c
@@ -68,6 +68,9 @@ static bool cmd_test_result_print_generate
 static int cmd_test_result_print_operation_execute
 (const struct sieve_runtime_env *renv, sieve_size_t *address ATTR_UNUSED)
 {
+	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, 
+			"testsuite: test_result_print command; print script result ");
+
 	testsuite_result_print(renv);
 
 	return SIEVE_EXEC_OK;
diff --git a/src/testsuite/cmd-test-result-reset.c b/src/testsuite/cmd-test-result-reset.c
index 285afee2acade0cbbe76359c5bc95b4fb909b50f..df2f46c80e993be96b31c1739d431a74022f254c 100644
--- a/src/testsuite/cmd-test-result-reset.c
+++ b/src/testsuite/cmd-test-result-reset.c
@@ -69,6 +69,9 @@ static bool cmd_test_result_reset_generate
 static int cmd_test_result_reset_operation_execute
 (const struct sieve_runtime_env *renv, sieve_size_t *address ATTR_UNUSED)
 {
+	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, 
+			"testsuite: test_result_reset command; reset script result");
+
 	testsuite_result_reset(renv);
 	testsuite_smtp_reset();
 
diff --git a/src/testsuite/cmd-test-set.c b/src/testsuite/cmd-test-set.c
index 459e4e86fa7b257991121f1c933ec9583733a216..32077d6c80f4c582b90bd9fecee5fa8184edfa09 100644
--- a/src/testsuite/cmd-test-set.c
+++ b/src/testsuite/cmd-test-set.c
@@ -138,9 +138,13 @@ static int cmd_test_set_operation_execute
 	if ( !sieve_opr_string_read(renv, address, "string", &value) )
 		return SIEVE_EXEC_BIN_CORRUPT;
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, 
-		"test_set '%s' = \"%s\"", 
-		testsuite_object_member_name(&tobj, member_id), str_c(value));
+	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+		sieve_runtime_trace(renv, 0, "testsuite: test_set command");
+		sieve_runtime_trace_descend(renv);
+		sieve_runtime_trace(renv, 0, 
+			"set test parameter '%s' = \"%s\"", 
+				testsuite_object_member_name(&tobj, member_id), str_c(value));
+	}
 	
 	if ( tobj.def == NULL || tobj.def->set_member == NULL ) {
 		sieve_runtime_trace_error(renv, "unimplemented testsuite object");
diff --git a/src/testsuite/cmd-test.c b/src/testsuite/cmd-test.c
index dd6a786448b5d5e9d90039437ce2d725cee87cbf..40fb7f5c958c4dc074be57ac2b187d2ed0d4622d 100644
--- a/src/testsuite/cmd-test.c
+++ b/src/testsuite/cmd-test.c
@@ -157,7 +157,7 @@ static int cmd_test_operation_execute
 	
 	sieve_runtime_trace_sep(renv);
 	sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, 
-		"** Test start: \"%s\"", str_c(test_name));
+		"** Testsuite test start: \"%s\"", str_c(test_name));
 
 	testsuite_test_start(test_name);
 	return SIEVE_EXEC_OK;
@@ -167,7 +167,8 @@ static int cmd_test_finish_operation_execute
 (const struct sieve_runtime_env *renv ATTR_UNUSED, 
 	sieve_size_t *address ATTR_UNUSED)
 {
-	sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, "** Test end");
+	sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, 
+		"** Testsuite test end");
 	sieve_runtime_trace_sep(renv);
 	
 	testsuite_test_succeed(NULL);
diff --git a/src/testsuite/testsuite-script.c b/src/testsuite/testsuite-script.c
index c82031e4022eb1523627460708ee9078e2c452d5..fe264f0965925a5f06d670b12d3019d8094c4249 100644
--- a/src/testsuite/testsuite-script.c
+++ b/src/testsuite/testsuite-script.c
@@ -8,6 +8,7 @@
 #include "sieve-script.h"
 #include "sieve-binary.h"
 #include "sieve-interpreter.h"
+#include "sieve-runtime-trace.h"
 #include "sieve-result.h"
 
 #include "testsuite-common.h"
@@ -35,11 +36,21 @@ void testsuite_script_deinit(void)
 	}
 }
 
-static struct sieve_binary *_testsuite_script_compile(const char *script_path)
+static struct sieve_binary *_testsuite_script_compile
+(const struct sieve_runtime_env *renv, const char *script)
 {
 	struct sieve_instance *svinst = testsuite_sieve_instance;
 	struct sieve_binary *sbin;
 	const char *sieve_dir;
+	const char *script_path;
+
+	sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "compile script `%s'", script);
+
+	script_path = sieve_script_dirpath(renv->script);
+	if ( script_path == NULL ) 
+		return SIEVE_EXEC_FAILURE;
+
+	script_path = t_strconcat(script_path, "/", script, NULL);
 
 	/* Initialize environment */
 	sieve_dir = strrchr(script_path, '/');
@@ -61,13 +72,14 @@ static struct sieve_binary *_testsuite_script_compile(const char *script_path)
 	return sbin;
 }
 
-bool testsuite_script_compile(const char *script_path)
+bool testsuite_script_compile
+(const struct sieve_runtime_env *renv, const char *script)
 {
 	struct sieve_binary *sbin;
 
 	testsuite_log_clear_messages();
 
-	if ( (sbin=_testsuite_script_compile(script_path)) == NULL )
+	if ( (sbin=_testsuite_script_compile(renv, script)) == NULL )
 		return FALSE;
 
 	if ( _testsuite_compiled_script != NULL ) {
@@ -152,7 +164,7 @@ bool testsuite_script_multiscript
 	const char *const *scripts;
 	unsigned int count, i;
 	bool more = TRUE;
-	int ret;
+	bool result = TRUE;
 
 	testsuite_log_clear_messages();
 
@@ -168,6 +180,7 @@ bool testsuite_script_multiscript
 	scriptenv.duplicate_check = NULL;
 	scriptenv.user = renv->scriptenv->user;
 	scriptenv.trace_stream = renv->scriptenv->trace_stream;	
+	scriptenv.trace_config = renv->scriptenv->trace_config;
 
 	/* Start execution */
 
@@ -179,22 +192,25 @@ bool testsuite_script_multiscript
 
 	for ( i = 0; i < count && more; i++ ) {
 		struct sieve_binary *sbin = NULL;
-		const char *script_path = scripts[i];
+		const char *script = scripts[i];
 		bool final = ( i == count - 1 );
 
 		/* Open */
 	
-		if ( (sbin=_testsuite_script_compile(script_path)) == NULL )
+		if ( (sbin=_testsuite_script_compile(renv, script)) == NULL ) {
+			result = FALSE;
 			break;
+		}
 
 		/* Execute */
 
+		sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "run script `%s'", script);
+
 		more = sieve_multiscript_run(mscript, sbin, testsuite_log_ehandler, final);
 
 		sieve_close(&sbin);
 	}
 
-	ret = sieve_multiscript_finish(&mscript, testsuite_log_ehandler, NULL);
-	
-	return ( ret > 0 );
+	return ( sieve_multiscript_finish(&mscript, testsuite_log_ehandler, NULL) > 0
+		&& result );
 }
diff --git a/src/testsuite/testsuite-script.h b/src/testsuite/testsuite-script.h
index 7ad7c3467fc8b3c067d3e091b3e390d73d801872..9e6ce19c23053d10c82254b745b003a0fe632d79 100644
--- a/src/testsuite/testsuite-script.h
+++ b/src/testsuite/testsuite-script.h
@@ -9,10 +9,13 @@
 void testsuite_script_init(void);
 void testsuite_script_deinit(void);
 
-bool testsuite_script_compile(const char *script_path);
-bool testsuite_script_run(const struct sieve_runtime_env *renv);
+bool testsuite_script_compile
+	(const struct sieve_runtime_env *renv, const char *script);
+bool testsuite_script_run
+	(const struct sieve_runtime_env *renv);
 bool testsuite_script_multiscript
-(const struct sieve_runtime_env *renv, ARRAY_TYPE (const_string) *scriptfiles);
+	(const struct sieve_runtime_env *renv, 
+		ARRAY_TYPE (const_string) *scriptfiles);
 
 struct sieve_binary *testsuite_script_get_binary(void);
 void testsuite_script_set_binary(struct sieve_binary *sbin);
diff --git a/src/testsuite/tst-test-error.c b/src/testsuite/tst-test-error.c
index f182203e02e8ca8296b9550f59f3eda53f504d92..9d7f1e58afd34066e912487b1c0d51436d70e823 100644
--- a/src/testsuite/tst-test-error.c
+++ b/src/testsuite/tst-test-error.c
@@ -251,10 +251,10 @@ static int tst_test_error_operation_execute
 	
 	if ( index > 0 )
 		sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
-			"test_error test [index=%d]", index);
+			"testsuite: test_error test; match error message [index=%d]", index);
 	else
 		sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
-			"test_error test");
+			"testsuite: test_error test; match error messages");
 
 	/* Create value stringlist */
 	value_list = testsuite_log_stringlist_create(renv, index);
diff --git a/src/testsuite/tst-test-multiscript.c b/src/testsuite/tst-test-multiscript.c
index 555e13c6a0a41f197c36c4dff775e1083ef50ee8..156bf434ac6a4a5cb02793f6fbaad1f26c19ce1a 100644
--- a/src/testsuite/tst-test-multiscript.c
+++ b/src/testsuite/tst-test-multiscript.c
@@ -110,7 +110,6 @@ static int tst_test_multiscript_operation_execute
 {
 	struct sieve_stringlist *scripts_list;
 	string_t *script_name;
-	const char *script_path;
 	ARRAY_TYPE (const_string) scriptfiles;
 	bool result = TRUE;
 	int ret;
@@ -127,26 +126,22 @@ static int tst_test_multiscript_operation_execute
 	 * Perform operation
 	 */
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "test_multiscript test");
+	sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, 
+		"testsuite: test_multiscript test");
+	sieve_runtime_trace_descend(renv);
 
 	t_array_init(&scriptfiles, 16);
 
-	script_path = sieve_script_dirpath(renv->script);
-	if ( script_path == NULL )
-		return SIEVE_EXEC_FAILURE;
-
 	script_name = NULL;
 	while ( result &&
 		(ret=sieve_stringlist_next_item(scripts_list, &script_name)) > 0 ) {
+		const char *script = t_strdup(str_c(script_name));
 
-		const char *path =
-			t_strconcat(script_path, "/", str_c(script_name), NULL);
-
-		/* Attempt script compile */
-		array_append(&scriptfiles, &path, 1);
+		array_append(&scriptfiles, &script, 1);
 	}
 
-	result = result && (ret >= 0) && testsuite_script_multiscript(renv, &scriptfiles);
+	result = result && (ret >= 0) && 
+		testsuite_script_multiscript(renv, &scriptfiles);
 
 	/* Set result */
 	sieve_interpreter_set_test_result(renv->interp, result);
diff --git a/src/testsuite/tst-test-result-execute.c b/src/testsuite/tst-test-result-execute.c
index 21e4c7dfe7c965c5e965a6b48c5c8b5ef378bb24..515a9aeba3c8aee79633e80fe4b1ca0db0e9feaf 100644
--- a/src/testsuite/tst-test-result-execute.c
+++ b/src/testsuite/tst-test-result-execute.c
@@ -74,10 +74,17 @@ static int tst_test_result_execute_operation_execute
 	 * Perform operation
 	 */
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "test_result_execute");
+	sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, 
+		"testsuite: test_result_execute test");
 
 	result = testsuite_result_execute(renv);
 
+	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS) ) {
+		sieve_runtime_trace_descend(renv);
+		sieve_runtime_trace(renv, 0, "execution of result %s", 
+			( result ? "succeeded" : "failed" ));
+	}
+
 	/* Set result */
 	sieve_interpreter_set_test_result(renv->interp, result);
 
diff --git a/src/testsuite/tst-test-result.c b/src/testsuite/tst-test-result.c
index 1470454f73bf2227003b12506d3385b72d100ab7..9a9889bd9c70524712da11c188567c18d2d9dd99 100644
--- a/src/testsuite/tst-test-result.c
+++ b/src/testsuite/tst-test-result.c
@@ -255,7 +255,7 @@ static int tst_test_result_operation_execute
 	 */
 	
 	sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
-		"test_result test (index: %d)", index);
+		"testsuite: test_result test; match result name (index: %d)", index);
 
 	/* Create value stringlist */
 	value_list = testsuite_result_stringlist_create(renv, index);
diff --git a/src/testsuite/tst-test-script-compile.c b/src/testsuite/tst-test-script-compile.c
index c76699e9db95266537862eba026e708db2596038..58ec3f413bd611a7f1d83918339bbe6bfc532f02 100644
--- a/src/testsuite/tst-test-script-compile.c
+++ b/src/testsuite/tst-test-script-compile.c
@@ -108,7 +108,6 @@ static int tst_test_script_compile_operation_execute
 (const struct sieve_runtime_env *renv, sieve_size_t *address)
 {
 	string_t *script_name;
-	const char *script_path;
 	bool result = TRUE;
 
 	/*
@@ -122,18 +121,14 @@ static int tst_test_script_compile_operation_execute
 	 * Perform operation
 	 */
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
-		"testsuite: compile script '%s'", str_c(script_name));
-
-	script_path = sieve_script_dirpath(renv->script);
-	if ( script_path == NULL ) 
-		return SIEVE_EXEC_FAILURE;
-
-	script_path = t_strconcat(script_path, "/", str_c(script_name), NULL);
+	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS) ) {
+		sieve_runtime_trace(renv, 0, "testsuite: test_script_compile test");
+		sieve_runtime_trace_descend(renv);
+	}
 
 	/* Attempt script compile */
 
-	result = testsuite_script_compile(script_path);
+	result = testsuite_script_compile(renv, str_c(script_name));
 
 	/* Set result */
 	sieve_interpreter_set_test_result(renv->interp, result);
diff --git a/src/testsuite/tst-test-script-run.c b/src/testsuite/tst-test-script-run.c
index 262da7ed934fa05dc2862e1a73501d1c2ef70c12..c59d91013e53e0ab953d5979a009f168d339c2e0 100644
--- a/src/testsuite/tst-test-script-run.c
+++ b/src/testsuite/tst-test-script-run.c
@@ -170,8 +170,9 @@ static int tst_test_script_run_operation_execute
 	 * Perform operation
 	 */
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, 
-		"testsuite: run compiled script");
+	sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, 
+		"testsuite: run compiled script [append_result=%s]",
+		( append_result ? "yes" : "no" ));
 
 	/* Reset result object */
 	if ( !append_result ) 
@@ -180,6 +181,12 @@ static int tst_test_script_run_operation_execute
 	/* Run script */
 	result = testsuite_script_run(renv);
 
+	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS) ) {
+		sieve_runtime_trace_descend(renv);
+		sieve_runtime_trace(renv, 0, "execution of script %s", 
+			( result ? "succeeded" : "failed" ));
+	}
+
 	/* Indicate test status */
 	sieve_interpreter_set_test_result(renv->interp, result);