From 8ede5713846e6b1919d08cbc2bc4f97de4550e93 Mon Sep 17 00:00:00 2001 From: Ayush Srivastava Date: Tue, 6 Feb 2024 11:00:35 +0530 Subject: [PATCH 1/2] write_prometheus plugin modification Addition and modifications made to make collectd inline with lustre_exporter by using write_prometheus plugin. --- contrib/redhat/collectd.spec | 2 +- src/daemon/common.c | 21 +++++- src/daemon/common.h | 23 ++++++- src/df.c | 28 +++++++- src/filedata_config.c | 2 + src/filedata_config.h | 3 +- src/filedata_read.c | 6 +- src/filedata_xml.c | 10 +++ src/memory.c | 10 +-- src/write_prometheus.c | 130 +++++++++++++++++++++-------------- version-gen.sh | 2 +- 11 files changed, 171 insertions(+), 66 deletions(-) diff --git a/contrib/redhat/collectd.spec b/contrib/redhat/collectd.spec index 12e9c982f..253321e2e 100644 --- a/contrib/redhat/collectd.spec +++ b/contrib/redhat/collectd.spec @@ -281,7 +281,7 @@ Summary: Statistics collection and monitoring daemon Name: collectd -Version: 5.7.5.ddn +Version: 5.7.6.ddn Release: 1.g%{?rev}%{?dist} URL: https://collectd.org Source0: %{_sourcedir}/%{name}-%{version}.tar.bz2 diff --git a/src/daemon/common.c b/src/daemon/common.c index 87083b008..ac52f1eb1 100644 --- a/src/daemon/common.c +++ b/src/daemon/common.c @@ -329,6 +329,25 @@ int strsplit(char *string, char **fields, size_t size) { return (int)i; } +int strsplit_delimiter(char *string, char **fields, size_t size, char *delimiter) { + size_t i; + char *ptr; + char *saveptr; + + i = 0; + ptr = string; + saveptr = NULL; + while ((fields[i] = strtok_r(ptr, delimiter, &saveptr)) != NULL) { + ptr = NULL; + i++; + + if (i >= size) + break; + } + + return (int)i; +} + int strjoin(char *buffer, size_t buffer_size, char **fields, size_t fields_num, const char *sep) { size_t avail = 0; @@ -1601,4 +1620,4 @@ int check_capability(__attribute__((unused)) int arg) /* {{{ */ "Some plugin(s) may require elevated privileges to work properly."); return 0; } /* }}} int check_capability */ -#endif /* HAVE_CAPABILITY */ +#endif /* HAVE_CAPABILITY */ \ No newline at end of file diff --git a/src/daemon/common.h b/src/daemon/common.h index 364ee202e..985e50187 100644 --- a/src/daemon/common.h +++ b/src/daemon/common.h @@ -136,6 +136,27 @@ ssize_t swrite(int fd, const void *buf, size_t count); */ int strsplit(char *string, char **fields, size_t size); +/* + * NAME + * strsplit + * + * DESCRIPTION + * Splits a string into parts and stores pointers to the parts in `fields'. + * + * PARAMETERS + * `string' String to split. This string will be modified. `fields' will + * contain pointers to parts of this string, so free'ing it + * will destroy `fields' as well. + * `fields' Array of strings where pointers to the parts will be stored. + * `size' Number of elements in the array. No more than `size' + * pointers will be stored in `fields'. + * `delimiter' Character at which the string is split. + * + * RETURN VALUE + * Returns the number of parts stored in `fields'. + */ +int strsplit_delimiter(char *string, char **fields, size_t size, char *delimiter); + /* * NAME * strjoin @@ -388,4 +409,4 @@ void strarray_free(char **array, size_t array_len); int check_capability(int arg); #endif /* HAVE_SYS_CAPABILITY_H */ -#endif /* COMMON_H */ +#endif /* COMMON_H */ \ No newline at end of file diff --git a/src/df.c b/src/df.c index dd90f2433..4263c9c44 100644 --- a/src/df.c +++ b/src/df.c @@ -167,6 +167,8 @@ static int df_read(void) { char disk_name[256]; cu_mount_t *dup_ptr; uint64_t blk_free; + uint64_t blk_avail; + uint64_t blk_total; uint64_t blk_reserved; uint64_t blk_used; @@ -262,13 +264,19 @@ static int df_read(void) { if (statbuf.f_blocks < statbuf.f_bfree) statbuf.f_blocks = statbuf.f_bfree; - blk_free = (uint64_t)statbuf.f_bavail; + blk_free = (uint64_t)statbuf.f_bfree; + blk_avail = (uint64_t)statbuf.f_bavail; + blk_total = (uint64_t)statbuf.f_blocks; blk_reserved = (uint64_t)(statbuf.f_bfree - statbuf.f_bavail); blk_used = (uint64_t)(statbuf.f_blocks - statbuf.f_bfree); if (values_absolute) { df_submit_one(disk_name, "df_complex", "free", (gauge_t)(blk_free * blocksize)); + df_submit_one(disk_name, "df_complex", "avail", + (gauge_t)(blk_avail * blocksize)); + df_submit_one(disk_name, "df_complex", "total", + (gauge_t)(blk_total * blocksize)); df_submit_one(disk_name, "df_complex", "reserved", (gauge_t)(blk_reserved * blocksize)); df_submit_one(disk_name, "df_complex", "used", @@ -279,6 +287,10 @@ static int df_read(void) { if (statbuf.f_blocks > 0) { df_submit_one(disk_name, "percent_bytes", "free", (gauge_t)((float_t)(blk_free) / statbuf.f_blocks * 100)); + df_submit_one(disk_name, "percent_bytes", "avail", + (gauge_t)((float_t)(blk_avail) / statbuf.f_blocks * 100)); + df_submit_one(disk_name, "percent_bytes", "total", + (gauge_t)((float_t)(blk_total) / statbuf.f_blocks * 100)); df_submit_one( disk_name, "percent_bytes", "reserved", (gauge_t)((float_t)(blk_reserved) / statbuf.f_blocks * 100)); @@ -291,6 +303,8 @@ static int df_read(void) { /* inode handling */ if (report_inodes && statbuf.f_files != 0 && statbuf.f_ffree != 0) { uint64_t inode_free; + uint64_t inode_avail; + uint64_t inode_total; uint64_t inode_reserved; uint64_t inode_used; @@ -300,7 +314,9 @@ static int df_read(void) { if (statbuf.f_files < statbuf.f_ffree) statbuf.f_files = statbuf.f_ffree; - inode_free = (uint64_t)statbuf.f_favail; + inode_free = (uint64_t)statbuf.f_ffree; + inode_avail = (uint64_t)statbuf.f_favail; + inode_total = (uint64_t)statbuf.f_files; inode_reserved = (uint64_t)(statbuf.f_ffree - statbuf.f_favail); inode_used = (uint64_t)(statbuf.f_files - statbuf.f_ffree); @@ -309,6 +325,12 @@ static int df_read(void) { df_submit_one( disk_name, "percent_inodes", "free", (gauge_t)((float_t)(inode_free) / statbuf.f_files * 100)); + df_submit_one( + disk_name, "percent_inodes", "avail", + (gauge_t)((float_t)(inode_avail) / statbuf.f_files * 100)); + df_submit_one( + disk_name, "percent_inodes", "total", + (gauge_t)((float_t)(inode_total) / statbuf.f_files * 100)); df_submit_one( disk_name, "percent_inodes", "reserved", (gauge_t)((float_t)(inode_reserved) / statbuf.f_files * 100)); @@ -320,6 +342,8 @@ static int df_read(void) { } if (values_absolute) { df_submit_one(disk_name, "df_inodes", "free", (gauge_t)inode_free); + df_submit_one(disk_name, "df_inodes", "avail", (gauge_t)inode_avail); + df_submit_one(disk_name, "df_inodes", "total", (gauge_t)inode_total); df_submit_one(disk_name, "df_inodes", "reserved", (gauge_t)inode_reserved); df_submit_one(disk_name, "df_inodes", "used", (gauge_t)inode_used); diff --git a/src/filedata_config.c b/src/filedata_config.c index 968e4f040..1311c5e6c 100644 --- a/src/filedata_config.c +++ b/src/filedata_config.c @@ -392,6 +392,8 @@ void filedata_math_entry_free(struct filedata_math_entry *fme) free(fme->fme_operation); free(fme->fme_right_operand); free(fme->fme_tsdb_name); + free(fme->fme_plugin); + free(fme->fme_plugin_instance); free(fme->fme_type); free(fme->fme_type_instance); free(fme); diff --git a/src/filedata_config.h b/src/filedata_config.h index e8bbacfdb..38eceed1c 100644 --- a/src/filedata_config.h +++ b/src/filedata_config.h @@ -317,7 +317,8 @@ struct filedata_math_entry { char *fme_left_operand; char *fme_right_operand; char *fme_operation; - + char *fme_plugin; + char *fme_plugin_instance; char *fme_tsdb_name; /* submit instance */ char *fme_type; char *fme_type_instance; diff --git a/src/filedata_read.c b/src/filedata_read.c index 025811b71..b288774c4 100644 --- a/src/filedata_read.c +++ b/src/filedata_read.c @@ -1538,8 +1538,10 @@ filedata_submit_math_instance(struct filedata_entry *entry) fme->fme_operation, fhme_found->fhme_value); filedata_instance_submit(fhme->fhme_host, - fhme->fhme_plugin, - fhme->fhme_plugin_instance, + fme->fme_plugin ? + fme->fme_plugin : fhme->fhme_plugin, + fme->fme_plugin_instance ? + fme->fme_plugin_instance : fhme->fhme_plugin_instance, fme->fme_type ? fme->fme_type : fhme->fhme_type, fme->fme_type_instance ? diff --git a/src/filedata_xml.c b/src/filedata_xml.c index 7a8c1f7ba..d13aa46d9 100644 --- a/src/filedata_xml.c +++ b/src/filedata_xml.c @@ -144,6 +144,8 @@ filedata_entry_free(struct filedata_entry *entry) #define FILEDATA_XML_ME_OPERATION "operation" #define FILEDATA_XML_ME_RIGHT_OPERAND "right_operand" #define FILEDATA_XML_ME_TSDB_NAME "tsdb_name" +#define FILEDATA_XML_ME_PLUGIN "plugin" +#define FILEDATA_XML_ME_PLUGIN_INSTANCE "plugin_instance" #define FILEDATA_XML_ME_TYPE "type" #define FILEDATA_XML_ME_TYPE_INSTANCE "type_instance" #define FILEDATA_XML_SUBPATH "subpath" @@ -1083,6 +1085,14 @@ filedata_xml_math_entry_parse(struct filedata_definition *definition, FILEDATA_XML_ME_TSDB_NAME) == 0) { status = filedata_xml_get_str(tmp, &fme->fme_tsdb_name); + } else if (strcmp((char *)tmp->name, + FILEDATA_XML_ME_PLUGIN) == 0) { + status = filedata_xml_get_str(tmp, + &fme->fme_plugin); + } else if (strcmp((char *)tmp->name, + FILEDATA_XML_ME_PLUGIN_INSTANCE) == 0) { + status = filedata_xml_get_str(tmp, + &fme->fme_plugin_instance); } else if (strcmp((char *)tmp->name, FILEDATA_XML_ME_TYPE) == 0) { status = filedata_xml_get_str(tmp, diff --git a/src/memory.c b/src/memory.c index e49fe84a1..32b309e5d 100644 --- a/src/memory.c +++ b/src/memory.c @@ -330,12 +330,12 @@ static int memory_read_internal(value_list_t *vl) { * kernels. So SReclaimable/SUnreclaim are submitted if available, and Slab * if not. */ if (detailed_slab_info) - MEMORY_SUBMIT("used", mem_used, "buffered", mem_buffered, "cached", - mem_cached, "free", mem_free, "slab_unrecl", - mem_slab_unreclaimable, "slab_recl", mem_slab_reclaimable); + MEMORY_SUBMIT("MemUsed", mem_used, "Buffers", mem_buffered, "Cached", + mem_cached, "MemFree", mem_free, "SUnreclaim", + mem_slab_unreclaimable, "SReclaimable", mem_slab_reclaimable); else - MEMORY_SUBMIT("used", mem_used, "buffered", mem_buffered, "cached", - mem_cached, "free", mem_free, "slab", mem_slab_total); + MEMORY_SUBMIT("MemUsed", mem_used, "Buffers", mem_buffered, "Cached", + mem_cached, "MemFree", mem_free, "Slab", mem_slab_total); /* #endif KERNEL_LINUX */ #elif HAVE_LIBKSTAT diff --git a/src/write_prometheus.c b/src/write_prometheus.c index a2434e01d..bf3a5a793 100644 --- a/src/write_prometheus.c +++ b/src/write_prometheus.c @@ -144,19 +144,18 @@ static char *format_labels(char *buffer, size_t buffer_size, Io__Prometheus__Client__Metric const *m) { /* our metrics always have at least one and at most three labels. */ assert(m->n_label >= 1); - assert(m->n_label <= 3); + assert(m->n_label <= 6); #define LABEL_KEY_SIZE DATA_MAX_NAME_LEN #define LABEL_VALUE_SIZE (2 * DATA_MAX_NAME_LEN - 1) #define LABEL_BUFFER_SIZE (LABEL_KEY_SIZE + LABEL_VALUE_SIZE + 4) - char *labels[3] = { + char *labels[6] = { + (char[LABEL_BUFFER_SIZE]){0}, (char[LABEL_BUFFER_SIZE]){0}, + (char[LABEL_BUFFER_SIZE]){0}, (char[LABEL_BUFFER_SIZE]){0}, (char[LABEL_BUFFER_SIZE]){0}, (char[LABEL_BUFFER_SIZE]){0}, - (char[LABEL_BUFFER_SIZE]){0}, }; - /* N.B.: the label *names* are hard-coded by this plugin and therefore we - * know that they are sane. */ for (size_t i = 0; i < m->n_label; i++) { char value[LABEL_VALUE_SIZE]; ssnprintf(labels[i], LABEL_BUFFER_SIZE, "%s=\"%s\"", m->label[i]->name, @@ -178,7 +177,7 @@ static void format_text(ProtobufCBuffer *buffer) { while (c_avl_iterator_next(iter, (void *)&unused_name, (void *)&fam) == 0) { char line[1024]; /* 4x DATA_MAX_NAME_LEN? */ - ssnprintf(line, sizeof(line), "# HELP %s %s\n", fam->name, fam->help); + ssnprintf(line, sizeof(line), "\n# HELP %s %s\n", fam->name, fam->help); buffer->append(buffer, strlen(line), (uint8_t *)line); ssnprintf(line, sizeof(line), "# TYPE %s %s\n", fam->name, @@ -381,42 +380,72 @@ static int metric_cmp(void const *a, void const *b) { return 0; } -#define METRIC_INIT \ - &(Io__Prometheus__Client__Metric) { \ - .label = \ - (Io__Prometheus__Client__LabelPair *[]){ \ - &(Io__Prometheus__Client__LabelPair){ \ - .name = NULL, \ - }, \ - &(Io__Prometheus__Client__LabelPair){ \ - .name = NULL, \ - }, \ - &(Io__Prometheus__Client__LabelPair){ \ - .name = NULL, \ - }, \ - }, \ - .n_label = 0, \ - } - -#define METRIC_ADD_LABELS(m, vl) \ - do { \ - if (strlen((vl)->plugin_instance) != 0) { \ - (m)->label[(m)->n_label]->name = (char *)(vl)->plugin; \ - (m)->label[(m)->n_label]->value = (char *)(vl)->plugin_instance; \ - (m)->n_label++; \ - } \ - \ - if (strlen((vl)->type_instance) != 0) { \ - (m)->label[(m)->n_label]->name = "type"; \ - if (strlen((vl)->plugin_instance) == 0) \ - (m)->label[(m)->n_label]->name = (char *)(vl)->plugin; \ - (m)->label[(m)->n_label]->value = (char *)(vl)->type_instance; \ - (m)->n_label++; \ - } \ - \ - (m)->label[(m)->n_label]->name = "instance"; \ - (m)->label[(m)->n_label]->value = (char *)(vl)->host; \ - (m)->n_label++; \ +#define METRIC_INIT \ + &(Io__Prometheus__Client__Metric) { \ + .label = \ + (Io__Prometheus__Client__LabelPair *[]){ \ + &(Io__Prometheus__Client__LabelPair){ \ + .name = NULL, \ + }, \ + &(Io__Prometheus__Client__LabelPair){ \ + .name = NULL, \ + }, \ + &(Io__Prometheus__Client__LabelPair){ \ + .name = NULL, \ + }, \ + &(Io__Prometheus__Client__LabelPair){ \ + .name = NULL, \ + }, \ + &(Io__Prometheus__Client__LabelPair){ \ + .name = NULL, \ + }, \ + &(Io__Prometheus__Client__LabelPair){ \ + .name = NULL, \ + }, \ + }, \ + .n_label = 0, \ + } + +#define METRIC_ADD_LABELS(m, vl) \ + do { \ + int add_type = 1; \ + if (strlen((vl)->plugin_instance) != 0) { \ + char *p_instance = strdup((vl)->plugin_instance); \ + if (p_instance != NULL) { \ + char* fields; \ + char* outer_saveptr = NULL; \ + char* inner_saveptr = NULL; \ + fields = strtok_r(p_instance, " ", &outer_saveptr); \ + while (fields != NULL) { \ + char* inner_token = strtok_r(fields, "=", &inner_saveptr); \ + if (inner_token != NULL) { \ + (m)->label[(m)->n_label]->name = strdup(inner_token); \ + inner_token = strtok_r(NULL, "=", &inner_saveptr); \ + if (inner_token != NULL) { \ + (m)->label[(m)->n_label]->value = strdup(inner_token); \ + } else { \ + (m)->label[(m)->n_label]->name = (char *)(vl)->plugin; \ + (m)->label[(m)->n_label]->value = (char *)(vl)->plugin_instance; \ + } \ + if (strcmp("operation", (m)->label[(m)->n_label]->name) == 0) { \ + add_type = 0; \ + } \ + (m)->n_label++; \ + } \ + fields = strtok_r(NULL, " ", &outer_saveptr); \ + } \ + sfree(p_instance); \ + } \ + } \ + \ + if (strlen((vl)->type_instance) != 0 && add_type) { \ + (m)->label[(m)->n_label]->name = "type"; \ + (m)->label[(m)->n_label]->value = (char *)(vl)->type_instance; \ + (m)->n_label++; \ + } \ + (m)->label[(m)->n_label]->name = "fqdn"; \ + (m)->label[(m)->n_label]->value = (char *)(vl)->host; \ + (m)->n_label++; \ } while (0) /* metric_clone allocates and initializes a new metric based on orig. */ @@ -653,15 +682,13 @@ metric_family_create(char *name, data_set_t const *ds, value_list_t const *vl, * the labels of a metric. */ static char *metric_family_name(data_set_t const *ds, value_list_t const *vl, size_t ds_index) { - char const *fields[5] = {"collectd"}; - size_t fields_num = 1; + char const *fields[4]; + size_t fields_num = 0; - if (strcmp(vl->plugin, vl->type) != 0) { - fields[fields_num] = vl->plugin; - fields_num++; + if (strstr(vl->plugin, "lustre") == NULL) { + fields[fields_num++] = "node"; } - fields[fields_num] = vl->type; - fields_num++; + fields[fields_num++] = vl->plugin; if (strcmp("value", ds->ds[ds_index].name) != 0) { fields[fields_num] = ds->ds[ds_index].name; @@ -672,11 +699,10 @@ static char *metric_family_name(data_set_t const *ds, value_list_t const *vl, * cumulative metrics should have a "total" suffix. */ if ((ds->ds[ds_index].type == DS_TYPE_COUNTER) || (ds->ds[ds_index].type == DS_TYPE_DERIVE)) { - fields[fields_num] = "total"; - fields_num++; + fields[fields_num++] = "total"; } - char name[5 * DATA_MAX_NAME_LEN]; + char name[4 * DATA_MAX_NAME_LEN]; strjoin(name, sizeof(name), (char **)fields, fields_num, "_"); return strdup(name); } diff --git a/version-gen.sh b/version-gen.sh index 55012b92c..1c20d0f33 100755 --- a/version-gen.sh +++ b/version-gen.sh @@ -1,6 +1,6 @@ #!/bin/sh -DEFAULT_VERSION="5.7.5.git" +DEFAULT_VERSION="5.7.6.git" if [ -d .git ]; then VERSION="`git describe --dirty=+ --abbrev=7 2> /dev/null | grep collectd | sed -e 's/^collectd-//' -e 's/-/./g'`" From 5aeaa745488d0f9ae554ec230cc3ae0974283420 Mon Sep 17 00:00:00 2001 From: Ayush Srivastava Date: Wed, 7 Feb 2024 14:03:26 +0530 Subject: [PATCH 2/2] Added missing fields Missing fields MemAvailable in memory and partition total size in df plugin added. --- src/df.c | 4 ++-- src/memory.c | 15 ++++++++++----- src/write_prometheus.c | 7 +++++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/df.c b/src/df.c index 4263c9c44..7e02ebc2f 100644 --- a/src/df.c +++ b/src/df.c @@ -275,7 +275,7 @@ static int df_read(void) { (gauge_t)(blk_free * blocksize)); df_submit_one(disk_name, "df_complex", "avail", (gauge_t)(blk_avail * blocksize)); - df_submit_one(disk_name, "df_complex", "total", + df_submit_one(disk_name, "df_complex", "size", (gauge_t)(blk_total * blocksize)); df_submit_one(disk_name, "df_complex", "reserved", (gauge_t)(blk_reserved * blocksize)); @@ -289,7 +289,7 @@ static int df_read(void) { (gauge_t)((float_t)(blk_free) / statbuf.f_blocks * 100)); df_submit_one(disk_name, "percent_bytes", "avail", (gauge_t)((float_t)(blk_avail) / statbuf.f_blocks * 100)); - df_submit_one(disk_name, "percent_bytes", "total", + df_submit_one(disk_name, "percent_bytes", "size", (gauge_t)((float_t)(blk_total) / statbuf.f_blocks * 100)); df_submit_one( disk_name, "percent_bytes", "reserved", diff --git a/src/memory.c b/src/memory.c index 32b309e5d..8d7e6f697 100644 --- a/src/memory.c +++ b/src/memory.c @@ -271,6 +271,7 @@ static int memory_read_internal(value_list_t *vl) { _Bool detailed_slab_info = 0; gauge_t mem_total = 0; + gauge_t mem_avail = 0; gauge_t mem_used = 0; gauge_t mem_buffered = 0; gauge_t mem_cached = 0; @@ -292,6 +293,8 @@ static int memory_read_internal(value_list_t *vl) { val = &mem_total; else if (strncasecmp(buffer, "MemFree:", 8) == 0) val = &mem_free; + else if (strncasecmp(buffer, "MemAvailable:", 13) == 0) + val = &mem_avail; else if (strncasecmp(buffer, "Buffers:", 8) == 0) val = &mem_buffered; else if (strncasecmp(buffer, "Cached:", 7) == 0) @@ -330,12 +333,14 @@ static int memory_read_internal(value_list_t *vl) { * kernels. So SReclaimable/SUnreclaim are submitted if available, and Slab * if not. */ if (detailed_slab_info) - MEMORY_SUBMIT("MemUsed", mem_used, "Buffers", mem_buffered, "Cached", - mem_cached, "MemFree", mem_free, "SUnreclaim", - mem_slab_unreclaimable, "SReclaimable", mem_slab_reclaimable); + MEMORY_SUBMIT("MemTotal", mem_total, "MemAvailable", mem_avail, "MemUsed", + mem_used, "Buffers", mem_buffered, "Cached", mem_cached, + "MemFree", mem_free, "SUnreclaim", mem_slab_unreclaimable, + "SReclaimable", mem_slab_reclaimable); else - MEMORY_SUBMIT("MemUsed", mem_used, "Buffers", mem_buffered, "Cached", - mem_cached, "MemFree", mem_free, "Slab", mem_slab_total); + MEMORY_SUBMIT("MemTotal", mem_total, "MemAvailable", mem_avail, "MemUsed", + mem_used, "Buffers", mem_buffered, "Cached", mem_cached, + "MemFree", mem_free, "Slab", mem_slab_total); /* #endif KERNEL_LINUX */ #elif HAVE_LIBKSTAT diff --git a/src/write_prometheus.c b/src/write_prometheus.c index bf3a5a793..69d4e2d9c 100644 --- a/src/write_prometheus.c +++ b/src/write_prometheus.c @@ -438,6 +438,13 @@ static int metric_cmp(void const *a, void const *b) { } \ } \ \ + if (strlen((vl)->type) != 0) { \ + if (strcmp((vl)->type, "derive") != 0 && strcmp((vl)->type, "gauge") != 0) { \ + (m)->label[(m)->n_label]->name = "kind"; \ + (m)->label[(m)->n_label]->value = (char *)(vl)->type; \ + (m)->n_label++; \ + } \ + } \ if (strlen((vl)->type_instance) != 0 && add_type) { \ (m)->label[(m)->n_label]->name = "type"; \ (m)->label[(m)->n_label]->value = (char *)(vl)->type_instance; \