virt plugin: Do not request cpu maps when not required
[collectd.git] / src / virt.c
index 2a7162e..64f9415 100644 (file)
 #endif
 
 /*
-  virConnectListAllDomains() appeared in 0.10.2
-  Note that LIBVIR_CHECK_VERSION appeared a year later, so
-  in some systems which actually have virConnectListAllDomains()
+  virConnectListAllDomains() appeared in 0.10.2 (Sep 2012)
+  Note that LIBVIR_CHECK_VERSION appeared a year later (Dec 2013,
+  libvirt-1.2.0),
+  so in some systems which actually have virConnectListAllDomains()
   we can't detect this.
  */
 #if LIBVIR_CHECK_VERSION(0, 10, 2)
 #define HAVE_DOM_REASON_POSTCOPY 1
 #endif
 
+#if LIBVIR_CHECK_VERSION(4, 10, 0)
+#define HAVE_DOM_REASON_SHUTOFF_DAEMON 1
+#endif
 #endif /* LIBVIR_CHECK_VERSION */
 
 /* structure used for aggregating notification-thread data*/
@@ -300,6 +304,16 @@ static int map_domain_event_detail_to_reason(int event, int detail) {
     switch (detail) {
     case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED: /* Guest finished shutdown
                                                 sequence */
+#ifdef LIBVIR_CHECK_VERSION
+#if LIBVIR_CHECK_VERSION(3, 4, 0)
+    case VIR_DOMAIN_EVENT_SHUTDOWN_GUEST: /* Domain finished shutting down after
+                                             request from the guest itself (e.g.
+                                             hardware-specific action) */
+    case VIR_DOMAIN_EVENT_SHUTDOWN_HOST:  /* Domain finished shutting down after
+                                             request from the host (e.g. killed
+                                             by a signal) */
+#endif
+#endif
       ret = VIR_DOMAIN_SHUTDOWN_USER;
       break;
     default:
@@ -425,6 +439,10 @@ const char *domain_reasons[][DOMAIN_STATE_REASON_MAX_SIZE] = {
             "domain failed to start",
         [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT] =
             "restored from a snapshot which was taken while domain was shutoff",
+#ifdef HAVE_DOM_REASON_SHUTOFF_DAEMON
+        [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_DAEMON] =
+            "daemon decides to kill domain during reconnection processing",
+#endif
 
         [VIR_DOMAIN_CRASHED][VIR_DOMAIN_CRASHED_UNKNOWN] =
             "the reason is unknown",
@@ -592,7 +610,9 @@ enum ex_stats {
 #endif
   ex_stats_disk_allocation = 1 << 10,
   ex_stats_disk_capacity = 1 << 11,
-  ex_stats_disk_physical = 1 << 12
+  ex_stats_disk_physical = 1 << 12,
+  ex_stats_memory = 1 << 13,
+  ex_stats_vcpu = 1 << 14
 };
 
 static unsigned int extra_stats = ex_stats_none;
@@ -623,6 +643,8 @@ static const struct ex_stats_item ex_stats_table[] = {
     {"disk_allocation", ex_stats_disk_allocation},
     {"disk_capacity", ex_stats_disk_capacity},
     {"disk_physical", ex_stats_disk_physical},
+    {"memory", ex_stats_memory},
+    {"vcpu", ex_stats_vcpu},
     {NULL, ex_stats_none},
 };
 
@@ -635,6 +657,8 @@ static enum if_field interface_format = if_name;
 static time_t last_refresh = (time_t)0;
 
 static int refresh_lists(struct lv_read_instance *inst);
+static int register_event_impl(void);
+static int start_event_loop(virt_notif_thread_t *thread_data);
 
 struct lv_block_stats {
   virDomainBlockStatsStruct bi;
@@ -916,10 +940,10 @@ static void memory_submit(virDomainPtr dom, gauge_t value) {
 
 static void memory_stats_submit(gauge_t value, virDomainPtr dom,
                                 int tag_index) {
-  static const char *tags[] = {"swap_in",        "swap_out", "major_fault",
-                               "minor_fault",    "unused",   "available",
-                               "actual_balloon", "rss",      "usable",
-                               "last_update"};
+  static const char *tags[] = {"swap_in",        "swap_out",   "major_fault",
+                               "minor_fault",    "unused",     "available",
+                               "actual_balloon", "rss",        "usable",
+                               "last_update",    "disk_caches"};
 
   if ((tag_index < 0) || (tag_index >= (int)STATIC_ARRAY_SIZE(tags))) {
     ERROR("virt plugin: Array index out of bounds: tag_index = %d", tag_index);
@@ -1189,25 +1213,19 @@ static int lv_config(oconfig_item_t *ci) {
     oconfig_item_t *c = ci->children + i;
 
     if (strcasecmp(c->key, "Connection") == 0) {
-      if (cf_util_get_string(c, &conn_string) != 0 || conn_string == NULL) {
-        ERROR(PLUGIN_NAME " plugin: Could not get 'Connection' parameter");
+      if (cf_util_get_string(c, &conn_string) != 0 || conn_string == NULL)
         return -1;
-      }
 
       continue;
     } else if (strcasecmp(c->key, "RefreshInterval") == 0) {
-      if (cf_util_get_int(c, &interval) != 0) {
-        ERROR(PLUGIN_NAME " plugin: Could not get 'RefreshInterval' parameter");
+      if (cf_util_get_int(c, &interval) != 0)
         return -1;
-      }
 
       continue;
     } else if (strcasecmp(c->key, "Domain") == 0) {
       char *domain_name = NULL;
-      if (cf_util_get_string(c, &domain_name) != 0 || domain_name == NULL) {
-        ERROR(PLUGIN_NAME " plugin: Could not get 'Domain' parameter");
+      if (cf_util_get_string(c, &domain_name) != 0)
         return -1;
-      }
 
       if (ignorelist_add(il_domains, domain_name)) {
         ERROR(PLUGIN_NAME " plugin: Adding '%s' to domain-ignorelist failed",
@@ -1220,10 +1238,8 @@ static int lv_config(oconfig_item_t *ci) {
       continue;
     } else if (strcasecmp(c->key, "BlockDevice") == 0) {
       char *device_name = NULL;
-      if (cf_util_get_string(c, &device_name) != 0 || device_name == NULL) {
-        ERROR(PLUGIN_NAME " plugin: Could not get 'BlockDevice' parameter");
+      if (cf_util_get_string(c, &device_name) != 0)
         return -1;
-      }
 
       if (ignorelist_add(il_block_devices, device_name) != 0) {
         ERROR(PLUGIN_NAME
@@ -1237,11 +1253,8 @@ static int lv_config(oconfig_item_t *ci) {
       continue;
     } else if (strcasecmp(c->key, "BlockDeviceFormat") == 0) {
       char *device_format = NULL;
-      if (cf_util_get_string(c, &device_format) != 0 || device_format == NULL) {
-        ERROR(PLUGIN_NAME
-              " plugin: Could not get 'BlockDeviceFormat' parameter");
+      if (cf_util_get_string(c, &device_format) != 0)
         return -1;
-      }
 
       if (strcasecmp(device_format, "target") == 0)
         blockdevice_format = target;
@@ -1257,20 +1270,14 @@ static int lv_config(oconfig_item_t *ci) {
       sfree(device_format);
       continue;
     } else if (strcasecmp(c->key, "BlockDeviceFormatBasename") == 0) {
-      if (cf_util_get_boolean(c, &blockdevice_format_basename) != 0) {
-        ERROR(PLUGIN_NAME
-              " plugin: Could not get 'BlockDeviceFormatBasename' parameter");
+      if (cf_util_get_boolean(c, &blockdevice_format_basename) != 0)
         return -1;
-      }
 
       continue;
     } else if (strcasecmp(c->key, "InterfaceDevice") == 0) {
       char *interface_name = NULL;
-      if (cf_util_get_string(c, &interface_name) != 0 ||
-          interface_name == NULL) {
-        ERROR(PLUGIN_NAME " plugin: Could not get 'InterfaceDevice' parameter");
+      if (cf_util_get_string(c, &interface_name) != 0)
         return -1;
-      }
 
       if (ignorelist_add(il_interface_devices, interface_name)) {
         ERROR(PLUGIN_NAME " plugin: Adding '%s' to interface-ignorelist failed",
@@ -1283,10 +1290,8 @@ static int lv_config(oconfig_item_t *ci) {
       continue;
     } else if (strcasecmp(c->key, "IgnoreSelected") == 0) {
       bool ignore_selected = false;
-      if (cf_util_get_boolean(c, &ignore_selected) != 0) {
-        ERROR(PLUGIN_NAME " plugin: Could not get 'IgnoreSelected' parameter");
+      if (cf_util_get_boolean(c, &ignore_selected) != 0)
         return -1;
-      }
 
       if (ignore_selected) {
         ignorelist_set_invert(il_domains, 0);
@@ -1300,19 +1305,13 @@ static int lv_config(oconfig_item_t *ci) {
 
       continue;
     } else if (strcasecmp(c->key, "HostnameMetadataNS") == 0) {
-      if (cf_util_get_string(c, &hm_ns) != 0) {
-        ERROR(PLUGIN_NAME
-              " plugin: Could not get 'HostnameMetadataNS' parameter");
+      if (cf_util_get_string(c, &hm_ns) != 0)
         return -1;
-      }
 
       continue;
     } else if (strcasecmp(c->key, "HostnameMetadataXPath") == 0) {
-      if (cf_util_get_string(c, &hm_xpath) != 0) {
-        ERROR(PLUGIN_NAME
-              " plugin: Could not get 'HostnameMetadataXPath' parameter");
+      if (cf_util_get_string(c, &hm_xpath) != 0)
         return -1;
-      }
 
       continue;
     } else if (strcasecmp(c->key, "HostnameFormat") == 0) {
@@ -1378,10 +1377,8 @@ static int lv_config(oconfig_item_t *ci) {
       continue;
     } else if (strcasecmp(c->key, "InterfaceFormat") == 0) {
       char *format = NULL;
-      if (cf_util_get_string(c, &format) != 0 || format == NULL) {
-        ERROR(PLUGIN_NAME " plugin: could not get 'InterfaceFormat' parameter");
+      if (cf_util_get_string(c, &format) != 0)
         return -1;
-      }
 
       if (strcasecmp(format, "name") == 0)
         interface_format = if_name;
@@ -1398,10 +1395,8 @@ static int lv_config(oconfig_item_t *ci) {
       sfree(format);
       continue;
     } else if (strcasecmp(c->key, "Instances") == 0) {
-      if (cf_util_get_int(c, &nr_instances) != 0) {
-        ERROR(PLUGIN_NAME " plugin: could not get 'Instances' parameter");
+      if (cf_util_get_int(c, &nr_instances) != 0)
         return -1;
-      }
 
       if (nr_instances <= 0) {
         ERROR(PLUGIN_NAME " plugin: Instances <= 0 makes no sense.");
@@ -1419,10 +1414,8 @@ static int lv_config(oconfig_item_t *ci) {
     } else if (strcasecmp(c->key, "ExtraStats") == 0) {
       char *ex_str = NULL;
 
-      if (cf_util_get_string(c, &ex_str) != 0 || ex_str == NULL) {
-        ERROR(PLUGIN_NAME " plugin: could not get 'ExtraStats' parameter");
+      if (cf_util_get_string(c, &ex_str) != 0)
         return -1;
-      }
 
       char *exstats[EX_STATS_MAX_FIELDS];
       int numexstats = strsplit(ex_str, exstats, STATIC_ARRAY_SIZE(exstats));
@@ -1443,30 +1436,21 @@ static int lv_config(oconfig_item_t *ci) {
       }
 #endif
 
-      /* ExtraStats parsed successfully*/
+      /* ExtraStats parsed successfully */
       continue;
     } else if (strcasecmp(c->key, "PersistentNotification") == 0) {
-      if (cf_util_get_boolean(c, &persistent_notification) != 0) {
-        ERROR(PLUGIN_NAME
-              " plugin: could not get 'PersistentNotification' parameter");
+      if (cf_util_get_boolean(c, &persistent_notification) != 0)
         return -1;
-      }
 
       continue;
     } else if (strcasecmp(c->key, "ReportBlockDevices") == 0) {
-      if (cf_util_get_boolean(c, &report_block_devices) != 0) {
-        ERROR(PLUGIN_NAME
-              " plugin: could not get 'ReportBlockDevices' parameter");
+      if (cf_util_get_boolean(c, &report_block_devices) != 0)
         return -1;
-      }
 
       continue;
     } else if (strcasecmp(c->key, "ReportNetworkInterfaces") == 0) {
-      if (cf_util_get_boolean(c, &report_network_interfaces) != 0) {
-        ERROR(PLUGIN_NAME
-              " plugin: could not get 'ReportNetworkInterfaces' parameter");
+      if (cf_util_get_boolean(c, &report_network_interfaces) != 0)
         return -1;
-      }
 
       continue;
     } else {
@@ -1481,6 +1465,11 @@ static int lv_config(oconfig_item_t *ci) {
 
 static int lv_connect(void) {
   if (conn == NULL) {
+    /* event implementation must be registered before connection is opened */
+    if (!persistent_notification)
+      if (register_event_impl() != 0)
+        return -1;
+
 /* `conn_string == NULL' is acceptable */
 #ifdef HAVE_FS_INFO
     /* virDomainGetFSInfo requires full read-write access connection */
@@ -1498,8 +1487,17 @@ static int lv_connect(void) {
     int status = virNodeGetInfo(conn, &nodeinfo);
     if (status != 0) {
       ERROR(PLUGIN_NAME " plugin: virNodeGetInfo failed");
+      virConnectClose(conn);
+      conn = NULL;
       return -1;
     }
+
+    if (!persistent_notification)
+      if (start_event_loop(&notif_thread) != 0) {
+        virConnectClose(conn);
+        conn = NULL;
+        return -1;
+      }
   }
   c_release(LOG_NOTICE, &conn_complain,
             PLUGIN_NAME " plugin: Connection established.");
@@ -1591,7 +1589,6 @@ static void vcpu_pin_submit(virDomainPtr dom, int max_cpus, int vcpu,
 
 static int get_vcpu_stats(virDomainPtr domain, unsigned short nr_virt_cpu) {
   int max_cpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
-  int cpu_map_len = VIR_CPU_MAPLEN(max_cpus);
 
   virVcpuInfoPtr vinfo = calloc(nr_virt_cpu, sizeof(*vinfo));
   if (vinfo == NULL) {
@@ -1599,11 +1596,17 @@ static int get_vcpu_stats(virDomainPtr domain, unsigned short nr_virt_cpu) {
     return -1;
   }
 
-  unsigned char *cpumaps = calloc(nr_virt_cpu, cpu_map_len);
-  if (cpumaps == NULL) {
-    ERROR(PLUGIN_NAME " plugin: calloc failed.");
-    sfree(vinfo);
-    return -1;
+  int cpu_map_len = 0;
+  unsigned char *cpumaps = NULL;
+  if (extra_stats & ex_stats_vcpupin) {
+    cpu_map_len = VIR_CPU_MAPLEN(max_cpus);
+    cpumaps = calloc(nr_virt_cpu, cpu_map_len);
+
+    if (cpumaps == NULL) {
+      ERROR(PLUGIN_NAME " plugin: calloc failed.");
+      sfree(vinfo);
+      return -1;
+    }
   }
 
   int status =
@@ -1617,7 +1620,8 @@ static int get_vcpu_stats(virDomainPtr domain, unsigned short nr_virt_cpu) {
   }
 
   for (int i = 0; i < nr_virt_cpu; ++i) {
-    vcpu_submit(vinfo[i].cpuTime, domain, vinfo[i].number, "virt_vcpu");
+    if (extra_stats & ex_stats_vcpu)
+      vcpu_submit(vinfo[i].cpuTime, domain, vinfo[i].number, "virt_vcpu");
     if (extra_stats & ex_stats_vcpupin)
       vcpu_pin_submit(domain, max_cpus, i, cpumaps, cpu_map_len);
   }
@@ -1671,16 +1675,7 @@ static int get_pcpu_stats(virDomainPtr dom) {
 #endif /* HAVE_CPU_STATS */
 
 #ifdef HAVE_DOM_REASON
-
-static void domain_state_submit(virDomainPtr dom, int state, int reason) {
-  value_t values[] = {
-      {.gauge = (gauge_t)state}, {.gauge = (gauge_t)reason},
-  };
-
-  submit(dom, "domain_state", NULL, values, STATIC_ARRAY_SIZE(values));
-}
-
-static int get_domain_state(virDomainPtr domain) {
+static int submit_domain_state(virDomainPtr domain) {
   int domain_state = 0;
   int domain_reason = 0;
 
@@ -1691,9 +1686,13 @@ static int get_domain_state(virDomainPtr domain) {
     return status;
   }
 
-  domain_state_submit(domain, domain_state, domain_reason);
+  value_t values[] = {
+      {.gauge = (gauge_t)domain_state}, {.gauge = (gauge_t)domain_reason},
+  };
 
-  return status;
+  submit(domain, "domain_state", NULL, values, STATIC_ARRAY_SIZE(values));
+
+  return 0;
 }
 
 #ifdef HAVE_LIST_ALL_DOMAINS
@@ -1708,8 +1707,7 @@ static int get_domain_state_notify(virDomainPtr domain) {
     return status;
   }
 
-  if (persistent_notification)
-    domain_state_submit_notif(domain, domain_state, domain_reason);
+  domain_state_submit_notif(domain, domain_state, domain_reason);
 
   return status;
 }
@@ -1733,8 +1731,42 @@ static int get_memory_stats(virDomainPtr domain) {
     return mem_stats;
   }
 
-  for (int i = 0; i < mem_stats; i++)
-    memory_stats_submit((gauge_t)minfo[i].val * 1024, domain, minfo[i].tag);
+  derive_t swap_in = -1;
+  derive_t swap_out = -1;
+  derive_t min_flt = -1;
+  derive_t maj_flt = -1;
+
+  for (int i = 0; i < mem_stats; i++) {
+    if (minfo[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_IN)
+      swap_in = minfo[i].val;
+    else if (minfo[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_OUT)
+      swap_out = minfo[i].val;
+    else if (minfo[i].tag == VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT)
+      min_flt = minfo[i].val;
+    else if (minfo[i].tag == VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT)
+      maj_flt = minfo[i].val;
+#ifdef LIBVIR_CHECK_VERSION
+#if LIBVIR_CHECK_VERSION(2, 1, 0)
+    else if (minfo[i].tag == VIR_DOMAIN_MEMORY_STAT_LAST_UPDATE)
+      /* Skip 'last_update' reporting as that is not memory but timestamp */
+      continue;
+#endif
+#endif
+    else
+      memory_stats_submit((gauge_t)minfo[i].val * 1024, domain, minfo[i].tag);
+  }
+
+  if (swap_in > 0 || swap_out > 0) {
+    submit(domain, "swap_io", "in", &(value_t){.gauge = swap_in}, 1);
+    submit(domain, "swap_io", "out", &(value_t){.gauge = swap_out}, 1);
+  }
+
+  if (min_flt > 0 || maj_flt > 0) {
+    value_t values[] = {
+        {.gauge = (gauge_t)min_flt}, {.gauge = (gauge_t)maj_flt},
+    };
+    submit(domain, "ps_pagefaults", NULL, values, STATIC_ARRAY_SIZE(values));
+  }
 
   sfree(minfo);
   return 0;
@@ -1979,7 +2011,7 @@ static int get_domain_metrics(domain_t *domain) {
      * however it doesn't provide a reason for entering particular state.
      * We need to get it from virDomainGetState.
      */
-    GET_STATS(get_domain_state, "domain reason", domain->ptr);
+    GET_STATS(submit_domain_state, "domain reason", domain->ptr);
 #endif
   }
 
@@ -1996,8 +2028,10 @@ static int get_domain_metrics(domain_t *domain) {
 
   memory_submit(domain->ptr, (gauge_t)info.memory * 1024);
 
-  GET_STATS(get_vcpu_stats, "vcpu stats", domain->ptr, info.nrVirtCpu);
-  GET_STATS(get_memory_stats, "memory stats", domain->ptr);
+  if (extra_stats & (ex_stats_vcpu | ex_stats_vcpupin))
+    GET_STATS(get_vcpu_stats, "vcpu stats", domain->ptr, info.nrVirtCpu);
+  if (extra_stats & ex_stats_memory)
+    GET_STATS(get_memory_stats, "memory stats", domain->ptr);
 
 #ifdef HAVE_PERF_STATS
   if (extra_stats & ex_stats_perf)
@@ -2131,10 +2165,9 @@ static void *event_loop_worker(void *arg) {
 }
 
 static int virt_notif_thread_init(virt_notif_thread_t *thread_data) {
-  int ret;
-
   assert(thread_data != NULL);
-  ret = pthread_mutex_init(&thread_data->active_mutex, NULL);
+
+  int ret = pthread_mutex_init(&thread_data->active_mutex, NULL);
   if (ret != 0) {
     ERROR(PLUGIN_NAME " plugin: Failed to initialize mutex, err %u", ret);
     return ret;
@@ -2163,11 +2196,15 @@ static int start_event_loop(virt_notif_thread_t *thread_data) {
     return -1;
   }
 
+  DEBUG(PLUGIN_NAME " plugin: starting event loop");
+
   virt_notif_thread_set_active(thread_data, 1);
   if (pthread_create(&thread_data->event_loop_tid, NULL, event_loop_worker,
                      thread_data)) {
     ERROR(PLUGIN_NAME " plugin: failed event loop thread creation");
+    virt_notif_thread_set_active(thread_data, 0);
     virConnectDomainEventDeregisterAny(conn, thread_data->domain_event_cb_id);
+    thread_data->domain_event_cb_id = -1;
     return -1;
   }
 
@@ -2176,13 +2213,21 @@ static int start_event_loop(virt_notif_thread_t *thread_data) {
 
 /* stop event loop thread and deregister callback */
 static void stop_event_loop(virt_notif_thread_t *thread_data) {
-  /* stopping loop and de-registering event handler*/
-  virt_notif_thread_set_active(thread_data, 0);
-  if (conn != NULL && thread_data->domain_event_cb_id != -1)
-    virConnectDomainEventDeregisterAny(conn, thread_data->domain_event_cb_id);
 
-  if (pthread_join(notif_thread.event_loop_tid, NULL) != 0)
-    ERROR(PLUGIN_NAME " plugin: stopping notification thread failed");
+  DEBUG(PLUGIN_NAME " plugin: stopping event loop");
+
+  /* Stopping loop */
+  if (virt_notif_thread_is_active(thread_data)) {
+    virt_notif_thread_set_active(thread_data, 0);
+    if (pthread_join(notif_thread.event_loop_tid, NULL) != 0)
+      ERROR(PLUGIN_NAME " plugin: stopping notification thread failed");
+  }
+
+  /* ... and de-registering event handler */
+  if (conn != NULL && thread_data->domain_event_cb_id != -1) {
+    virConnectDomainEventDeregisterAny(conn, thread_data->domain_event_cb_id);
+    thread_data->domain_event_cb_id = -1;
+  }
 }
 
 static int persistent_domains_state_notification(void) {
@@ -2258,33 +2303,26 @@ static int persistent_domains_state_notification(void) {
 }
 
 static int lv_read(user_data_t *ud) {
-  time_t t;
-  struct lv_read_instance *inst = NULL;
-  struct lv_read_state *state = NULL;
-
   if (ud->data == NULL) {
     ERROR(PLUGIN_NAME " plugin: NULL userdata");
     return -1;
   }
 
-  inst = ud->data;
-  state = &inst->read_state;
-
-  bool reconnect = conn == NULL ? true : false;
-  /* event implementation must be registered before connection is opened */
-  if (inst->id == 0) {
-    if (!persistent_notification && reconnect)
-      if (register_event_impl() != 0)
-        return -1;
+  struct lv_read_instance *inst = ud->data;
+  struct lv_read_state *state = &inst->read_state;
 
+  if (inst->id == 0)
     if (lv_connect() < 0)
       return -1;
 
-    if (!persistent_notification && reconnect && conn != NULL)
-      if (start_event_loop(&notif_thread) != 0)
-        return -1;
+  /* Wait until inst#0 establish connection */
+  if (conn == NULL) {
+    DEBUG(PLUGIN_NAME " plugin#%s: Wait until inst#0 establish connection",
+          inst->tag);
+    return 0;
   }
 
+  time_t t;
   time(&t);
 
   /* Need to refresh domain or device lists? */
@@ -2331,8 +2369,8 @@ static int lv_read(user_data_t *ud) {
     if (dom->active)
       status = get_domain_metrics(dom);
 #ifdef HAVE_DOM_REASON
-    else
-      status = get_domain_state(dom->ptr);
+    else if (extra_stats & ex_stats_domain_state)
+      status = submit_domain_state(dom->ptr);
 #endif
 
     if (status != 0)
@@ -2405,21 +2443,11 @@ static int lv_init(void) {
   if (lv_init_ignorelists() != 0)
     return -1;
 
-  /* event implementation must be registered before connection is opened */
   if (!persistent_notification)
-    if (register_event_impl() != 0)
+    if (virt_notif_thread_init(&notif_thread) != 0)
       return -1;
 
-  if (lv_connect() != 0)
-    return -1;
-
-  DEBUG(PLUGIN_NAME " plugin: starting event loop");
-
-  if (!persistent_notification) {
-    virt_notif_thread_init(&notif_thread);
-    if (start_event_loop(&notif_thread) != 0)
-      return -1;
-  }
+  lv_connect();
 
   DEBUG(PLUGIN_NAME " plugin: starting %i instances", nr_instances);
 
@@ -3004,8 +3032,6 @@ static int lv_shutdown(void) {
     lv_fini_instance(i);
   }
 
-  DEBUG(PLUGIN_NAME " plugin: stopping event loop");
-
   if (!persistent_notification)
     stop_event_loop(&notif_thread);