diff --git a/include/maestro/env.h b/include/maestro/env.h
index edd9c60f2547d91c2aaaf5ab6813a1cf34a77ee8..0d95b73a21a19b4fbae924559b4183bcd904d61d 100644
--- a/include/maestro/env.h
+++ b/include/maestro/env.h
@@ -63,6 +63,26 @@
  */
 #define MSTRO_ENV_LOG_LEVEL "MSTRO_LOG_LEVEL"
 
+/**@brief Selection of modules that should log (Optional)
+ *
+ * Maestro log messages are annotated with a module name; by default
+ * all modules are permitted to log. This variable can be set to
+ * selectively disable or enable certain modules.
+ *
+ * The syntax is 
+ *   component1,component2,^component3,...
+ *
+ * where 'component1' indicates that it should be included, and
+ * '^component3' indicates that component3 should be excluded.
+ *
+ * The pseudo-component 'all' may be used to indicate all
+ * components. This can be used to set a 'background', and either
+ * selectively include or exclude components.
+ *
+ * If unset, the default is "all".
+ */
+#define MSTRO_ENV_LOG_MODULES "MSTRO_LOG_MODULES"
+
 /**@brief Log color. (Optional)
  *
  * Maestro logging color (ANSI) can be changed at application startup by
diff --git a/maestro/logging.c b/maestro/logging.c
index 854046237a1596773987c27ad0dfe1ac270e1881..78c8e2158a898a45214378e4b4cec9e54cf62d1c 100644
--- a/maestro/logging.c
+++ b/maestro/logging.c
@@ -261,6 +261,77 @@ static _Atomic(bool) g_queried_env = false;
 static int g_log_dst = MSTRO_LOG_DST_STDERR;
 static char *g_env_debug_flag = NULL;
 
+static uint64_t g_log_module_mask = MSTRO_LOG_MODULE_ALL;
+
+static const struct mstro_log_module_descriptor
+g_module_descriptors[] = MSTRO_LOG_MODULES;
+
+
+static inline
+uint64_t mstro_log__parse_module_spec(char *module_spec)
+{
+  uint64_t result=0;
+  char *sep = ",";
+  char *word;
+  const size_t num_modules = (sizeof(g_module_descriptors)/
+                              sizeof(struct mstro_log_module_descriptor));
+
+  for (word = strtok(module_spec, sep);
+       word;
+       word = strtok(NULL, sep)) {
+    char *modulename = word;
+    bool flip = false;
+    if(word[0]=='^') {
+      flip=true;
+      modulename++;
+    }
+    uint64_t val=0;
+    if(strcasecmp("all",modulename)==0) {
+      val = MSTRO_LOG_MODULE_ALL;
+    } else {
+      for(size_t i=0; i<num_modules; i++) {
+        if(strcasecmp(g_module_descriptors[i].name, modulename)==0) {
+          val = g_module_descriptors[i].selector;
+          break;
+        }
+      }
+    }
+    if(val==0) {
+      LOG_ERR(MSTRO_LOG_MODULE_CORE,
+              "Invalid module specifier %s in module specification %s, skipping\n",
+              modulename, module_spec);
+    } else {
+      /* LOG_DEBUG(MSTRO_LOG_MODULE_CORE, */
+      /*           "Parsed |%s|, value %" PRIx64 ", complement? %d, result %" PRIx64" moves to %" PRIx64"\n", */
+      /*           word, val, flip, result, */
+      /*           flip? result & ~val : result |val); */
+      
+      if(!flip) {
+        result |= val;
+      } else {
+        result &= ~val;
+      }
+    }
+  }
+  /* LOG_DEBUG(MSTRO_LOG_MODULE_CORE, "Parsed |%s| as %" PRIx64 "\n", */
+  /*           module_spec, result); */
+  return result;
+}
+
+static inline
+const char *mstro_log_module_name(uint64_t module)
+{
+  /* FIXME: We could hash on the module */
+  const size_t num_modules = (sizeof(g_module_descriptors)/
+                              sizeof(struct mstro_log_module_descriptor));
+  for(size_t i=0; i<num_modules; i++) {
+    if((module & g_module_descriptors[i].selector)!=0) {
+      return g_module_descriptors[i].name;
+    }
+  }
+  return "???";
+}
+
 /* one-time init function for log infrastructure */
 static inline
 void
@@ -270,6 +341,8 @@ mstro_log__init()
       atomic_exchange(&g_queried_env, true);
   
   if(!already_initialized) {
+    g_pid=getpid();
+    
     const char *env_log_dst = getenv(MSTRO_ENV_LOG_DST);
     if(env_log_dst!=NULL) {
       LOG_NOISE(MSTRO_LOG_MODULE_CORE,
@@ -327,29 +400,21 @@ mstro_log__init()
     if(env_color_errors!=NULL) {
       g_color_errors = true;
     }
+
+    char *env_module_val = getenv(MSTRO_ENV_LOG_MODULES);
+    if(env_module_val==NULL) {
+      env_module_val="all";
+    }
+    g_log_module_mask = mstro_log__parse_module_spec(env_module_val);
+    LOG_DEBUG(MSTRO_LOG_MODULE_CORE,
+              "Environment variable %s select log modules %" PRIx64 "\n",
+              MSTRO_ENV_LOG_MODULES, g_log_module_mask);
     
-    g_pid=getpid();
 
     /* thread ID can't be set here, every thread sets it at first call */
   }
 }
 
-static const struct mstro_log_module_descriptor
-g_module_descriptors[] = MSTRO_LOG_MODULES;
-
-static inline
-const char *mstro_log_module_name(uint64_t module)
-{
-  /* FIXME: We could hash on the module */
-  const size_t num_modules = (sizeof(g_module_descriptors)/
-                              sizeof(struct mstro_log_module_descriptor));
-  for(size_t i=0; i<num_modules; i++) {
-    if((module & g_module_descriptors[i].selector)!=0) {
-      return g_module_descriptors[i].name;
-    }
-  }
-  return "???";
-}
 
 void
 mstro_vlocation_aware_log(int level,
@@ -362,7 +427,10 @@ mstro_vlocation_aware_log(int level,
     
   assert(level>=0); assert(level<MSTRO_log__MAX);
 
-  if(level <= g_debug_level) {
+  if(level <= g_debug_level
+     && (module & g_log_module_mask)) {
+    /* fprintf(stderr,"module %" PRIx64 ", mask %" PRIx64 "\n", */
+    /*         module, g_log_module_mask); */
     const char *thread_desc = mstro__ensure_threadid();
     
     if(g_instance_identifier==NULL) {