| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "exporting_engine.h" |
| 4 | |
| 5 | EXPORTING_OPTIONS global_exporting_options = EXPORTING_SOURCE_DATA_AVERAGE | EXPORTING_OPTION_SEND_NAMES; |
| 6 | const char *global_exporting_prefix = "netdata"; |
| 7 | |
| 8 | struct config exporting_config = APPCONFIG_INITIALIZER; |
| 9 | |
| 10 | /** |
| 11 | * Free exporting configuration |
| 12 | * |
| 13 | * Free all memory associated with the exporting configuration. |
| 14 | * Called during shutdown to prevent memory leaks. |
| 15 | */ |
| 16 | void exporting_config_free(void) { |
| 17 | inicfg_free(&exporting_config); |
| 18 | } |
| 19 | |
| 20 | struct instance *prometheus_exporter_instance = NULL; |
| 21 | |
| 22 | static _CONNECTOR_INSTANCE *find_instance(const char *section) |
| 23 | { |
| 24 | _CONNECTOR_INSTANCE *local_ci; |
| 25 | |
| 26 | local_ci = add_connector_instance(NULL, NULL); // Get root section |
| 27 | if (unlikely(!local_ci)) |
| 28 | return local_ci; |
| 29 | |
| 30 | if (!section) |
| 31 | return local_ci; |
| 32 | |
| 33 | while (local_ci) { |
| 34 | if (!strcmp(local_ci->instance_name, section)) |
| 35 | break; |
| 36 | local_ci = local_ci->next; |
| 37 | } |
| 38 | return local_ci; |
| 39 | } |
| 40 | |
| 41 | static const char *expconfig_get(struct config *root, const char *section, const char *name, const char *default_value) |
| 42 | { |
| 43 | _CONNECTOR_INSTANCE *local_ci; |
| 44 | |
| 45 | if (!strcmp(section, CONFIG_SECTION_EXPORTING)) |
| 46 | return inicfg_get(root, CONFIG_SECTION_EXPORTING, name, default_value); |
| 47 | |
| 48 | local_ci = find_instance(section); |
| 49 | |
| 50 | if (!local_ci) |
| 51 | return NULL; // TODO: Check if it is meaningful to return default_value |
| 52 | |
| 53 | return inicfg_get( |
| 54 | root, local_ci->instance_name, name, |
| 55 | inicfg_get( |
| 56 | root, local_ci->connector_name, name, inicfg_get(root, CONFIG_SECTION_EXPORTING, name, default_value))); |
| 57 | } |
| 58 | |
| 59 | int expconfig_get_boolean(struct config *root, const char *section, const char *name, int default_value) |
| 60 | { |
| 61 | _CONNECTOR_INSTANCE *local_ci; |
| 62 | |
| 63 | if (!strcmp(section, CONFIG_SECTION_EXPORTING)) |
| 64 | return inicfg_get_boolean(root, CONFIG_SECTION_EXPORTING, name, default_value); |
| 65 | |
| 66 | local_ci = find_instance(section); |
| 67 | |
| 68 | if (!local_ci) |
| 69 | return 0; // TODO: Check if it is meaningful to return default_value |
| 70 | |
| 71 | return inicfg_get_boolean( |
| 72 | root, local_ci->instance_name, name, |
| 73 | inicfg_get_boolean( |
| 74 | root, local_ci->connector_name, name, |
| 75 | inicfg_get_boolean(root, CONFIG_SECTION_EXPORTING, name, default_value))); |
| 76 | } |
| 77 | |
| 78 | long long expconfig_get_number(struct config *root, const char *section, const char *name, long long default_value) |
| 79 | { |
| 80 | _CONNECTOR_INSTANCE *local_ci; |
| 81 | |
| 82 | if (!strcmp(section, CONFIG_SECTION_EXPORTING)) |
| 83 | return inicfg_get_number(root, CONFIG_SECTION_EXPORTING, name, default_value); |
| 84 | |
| 85 | local_ci = find_instance(section); |
| 86 | |
| 87 | if (!local_ci) |
| 88 | return 0; // TODO: Check if it is meaningful to return default_value |
| 89 | |
| 90 | return inicfg_get_number( |
| 91 | root, local_ci->instance_name, name, |
| 92 | inicfg_get_number( |
| 93 | root, local_ci->connector_name, name, |
| 94 | inicfg_get_number(root, CONFIG_SECTION_EXPORTING, name, default_value))); |
| 95 | } |
| 96 | |
| 97 | /* |
| 98 | * Get the next connector instance that we need to activate |
| 99 | * |
| 100 | * @param @target_ci will be filled with instance name and connector name |
| 101 | * |
| 102 | * @return - 1 if more connectors to be fetched, 0 done |
| 103 | * |
| 104 | */ |
| 105 | |
| 106 | int get_connector_instance(struct connector_instance *target_ci) |
| 107 | { |
| 108 | static _CONNECTOR_INSTANCE *local_ci = NULL; |
| 109 | _CONNECTOR_INSTANCE *global_connector_instance; |
| 110 | |
| 111 | global_connector_instance = find_instance(NULL); // Fetch head of instances |
| 112 | |
| 113 | if (unlikely(!global_connector_instance)) |
| 114 | return 0; |
| 115 | |
| 116 | if (target_ci == NULL) { |
| 117 | local_ci = NULL; |
| 118 | return 1; |
| 119 | } |
| 120 | if (local_ci == NULL) |
| 121 | local_ci = global_connector_instance; |
| 122 | else { |
| 123 | local_ci = local_ci->next; |
| 124 | if (local_ci == NULL) |
| 125 | return 0; |
| 126 | } |
| 127 | |
| 128 | strcpy(target_ci->instance_name, local_ci->instance_name); |
| 129 | strcpy(target_ci->connector_name, local_ci->connector_name); |
| 130 | |
| 131 | return 1; |
| 132 | } |
| 133 | |
| 134 | /** |
| 135 | * Select Type |
| 136 | * |
| 137 | * Select the connector type based on the user input |
| 138 | * |
| 139 | * @param type is the string that defines the connector type |
| 140 | * |
| 141 | * @return It returns the connector id. |
| 142 | */ |
| 143 | EXPORTING_CONNECTOR_TYPE exporting_select_type(const char *type) |
| 144 | { |
| 145 | if (!strcmp(type, "graphite") || !strcmp(type, "graphite:plaintext")) { |
| 146 | return EXPORTING_CONNECTOR_TYPE_GRAPHITE; |
| 147 | } else if (!strcmp(type, "graphite:http") || !strcmp(type, "graphite:https")) { |
| 148 | return EXPORTING_CONNECTOR_TYPE_GRAPHITE_HTTP; |
| 149 | } else if (!strcmp(type, "json") || !strcmp(type, "json:plaintext")) { |
| 150 | return EXPORTING_CONNECTOR_TYPE_JSON; |
| 151 | } else if (!strcmp(type, "json:http") || !strcmp(type, "json:https")) { |
| 152 | return EXPORTING_CONNECTOR_TYPE_JSON_HTTP; |
| 153 | } else if (!strcmp(type, "opentsdb") || !strcmp(type, "opentsdb:telnet")) { |
| 154 | return EXPORTING_CONNECTOR_TYPE_OPENTSDB; |
| 155 | } else if (!strcmp(type, "opentsdb:http") || !strcmp(type, "opentsdb:https")) { |
| 156 | return EXPORTING_CONNECTOR_TYPE_OPENTSDB_HTTP; |
| 157 | } else if ( |
| 158 | !strcmp(type, "prometheus_remote_write") || |
| 159 | !strcmp(type, "prometheus_remote_write:http") || |
| 160 | !strcmp(type, "prometheus_remote_write:https")) { |
| 161 | return EXPORTING_CONNECTOR_TYPE_PROMETHEUS_REMOTE_WRITE; |
| 162 | } else if (!strcmp(type, "kinesis") || !strcmp(type, "kinesis:plaintext")) { |
| 163 | return EXPORTING_CONNECTOR_TYPE_KINESIS; |
| 164 | } else if (!strcmp(type, "pubsub") || !strcmp(type, "pubsub:plaintext")) { |
| 165 | return EXPORTING_CONNECTOR_TYPE_PUBSUB; |
| 166 | } else if (!strcmp(type, "mongodb") || !strcmp(type, "mongodb:plaintext")) |
| 167 | return EXPORTING_CONNECTOR_TYPE_MONGODB; |
| 168 | |
| 169 | return EXPORTING_CONNECTOR_TYPE_UNKNOWN; |
| 170 | } |
| 171 | |
| 172 | inline EXPORTING_OPTIONS exporting_parse_data_source(const char *data_source, EXPORTING_OPTIONS exporting_options) |
| 173 | { |
| 174 | if (!strcmp(data_source, "raw") || !strcmp(data_source, "as collected") || !strcmp(data_source, "as-collected") || |
| 175 | !strcmp(data_source, "as_collected") || !strcmp(data_source, "ascollected")) { |
| 176 | exporting_options |= EXPORTING_SOURCE_DATA_AS_COLLECTED; |
| 177 | exporting_options &= ~(EXPORTING_OPTIONS_SOURCE_BITS ^ EXPORTING_SOURCE_DATA_AS_COLLECTED); |
| 178 | } else if (!strcmp(data_source, "average")) { |
| 179 | exporting_options |= EXPORTING_SOURCE_DATA_AVERAGE; |
| 180 | exporting_options &= ~(EXPORTING_OPTIONS_SOURCE_BITS ^ EXPORTING_SOURCE_DATA_AVERAGE); |
| 181 | } else if (!strcmp(data_source, "sum") || !strcmp(data_source, "volume")) { |
| 182 | exporting_options |= EXPORTING_SOURCE_DATA_SUM; |
| 183 | exporting_options &= ~(EXPORTING_OPTIONS_SOURCE_BITS ^ EXPORTING_SOURCE_DATA_SUM); |
| 184 | } else { |
| 185 | netdata_log_error("EXPORTING: invalid data data_source method '%s'.", data_source); |
| 186 | } |
| 187 | |
| 188 | return exporting_options; |
| 189 | } |
| 190 | |
| 191 | /** |
| 192 | * Read configuration |
| 193 | * |
| 194 | * Based on read configuration an engine data structure is filled with exporting connector instances. |
| 195 | * |
| 196 | * @return Returns a filled engine data structure or NULL if there are no connector instances configured. |
| 197 | */ |
| 198 | struct engine *read_exporting_config() |
| 199 | { |
| 200 | int instances_to_activate = 0; |
| 201 | int exporting_config_exists = 0; |
| 202 | |
| 203 | static struct engine *engine = NULL; |
| 204 | struct connector_instance_list { |
| 205 | struct connector_instance local_ci; |
| 206 | EXPORTING_CONNECTOR_TYPE exporting_type; |
| 207 | |
| 208 | struct connector_instance_list *next; |
| 209 | }; |
| 210 | struct connector_instance local_ci; |
| 211 | struct connector_instance_list *tmp_ci_list = NULL, *tmp_ci_list1 = NULL, *tmp_ci_list_prev = NULL; |
| 212 | |
| 213 | if (unlikely(engine)) |
| 214 | return engine; |
| 215 | |
| 216 | char *filename = filename_from_path_entry_strdupz(netdata_configured_user_config_dir, EXPORTING_CONF); |
| 217 | |
| 218 | exporting_config_exists = inicfg_load(&exporting_config, filename, 0, NULL); |
| 219 | if (!exporting_config_exists) { |
| 220 | netdata_log_info("CONFIG: cannot load user exporting config '%s'. Will try the stock version.", filename); |
| 221 | freez(filename); |
| 222 | |
| 223 | filename = filename_from_path_entry_strdupz(netdata_configured_stock_config_dir, EXPORTING_CONF); |
| 224 | exporting_config_exists = inicfg_load(&exporting_config, filename, 0, NULL); |
| 225 | if (!exporting_config_exists) |
| 226 | netdata_log_info("CONFIG: cannot load stock exporting config '%s'. Running with internal defaults.", filename); |
| 227 | } |
| 228 | |
| 229 | freez(filename); |
| 230 | |
| 231 | #define prometheus_config_get(name, value) \ |
| 232 | inicfg_get( \ |
| 233 | &exporting_config, CONFIG_SECTION_PROMETHEUS, name, \ |
| 234 | inicfg_get(&exporting_config, CONFIG_SECTION_EXPORTING, name, value)) |
| 235 | #define prometheus_config_get_number(name, value) \ |
| 236 | inicfg_get_number( \ |
| 237 | &exporting_config, CONFIG_SECTION_PROMETHEUS, name, \ |
| 238 | inicfg_get_number(&exporting_config, CONFIG_SECTION_EXPORTING, name, value)) |
| 239 | #define prometheus_config_get_boolean(name, value) \ |
| 240 | inicfg_get_boolean( \ |
| 241 | &exporting_config, CONFIG_SECTION_PROMETHEUS, name, \ |
| 242 | inicfg_get_boolean(&exporting_config, CONFIG_SECTION_EXPORTING, name, value)) |
| 243 | |
| 244 | if (!prometheus_exporter_instance) { |
| 245 | prometheus_exporter_instance = callocz(1, sizeof(struct instance)); |
| 246 | |
| 247 | prometheus_exporter_instance->config.update_every = |
| 248 | prometheus_config_get_number(EXPORTING_UPDATE_EVERY_OPTION_NAME, EXPORTING_UPDATE_EVERY_DEFAULT); |
| 249 | |
| 250 | prometheus_exporter_instance->config.options |= global_exporting_options & EXPORTING_OPTIONS_SOURCE_BITS; |
| 251 | |
| 252 | const char *data_source = prometheus_config_get("data source", "average"); |
| 253 | prometheus_exporter_instance->config.options = |
| 254 | exporting_parse_data_source(data_source, prometheus_exporter_instance->config.options); |
| 255 | |
| 256 | if (prometheus_config_get_boolean( |
| 257 | "send names instead of ids", global_exporting_options & EXPORTING_OPTION_SEND_NAMES)) |
| 258 | prometheus_exporter_instance->config.options |= EXPORTING_OPTION_SEND_NAMES; |
| 259 | else |
| 260 | prometheus_exporter_instance->config.options &= ~EXPORTING_OPTION_SEND_NAMES; |
| 261 | |
| 262 | if (prometheus_config_get_boolean("send configured labels", CONFIG_BOOLEAN_YES)) |
| 263 | prometheus_exporter_instance->config.options |= EXPORTING_OPTION_SEND_CONFIGURED_LABELS; |
| 264 | else |
| 265 | prometheus_exporter_instance->config.options &= ~EXPORTING_OPTION_SEND_CONFIGURED_LABELS; |
| 266 | |
| 267 | if (prometheus_config_get_boolean("send automatic labels", CONFIG_BOOLEAN_NO)) |
| 268 | prometheus_exporter_instance->config.options |= EXPORTING_OPTION_SEND_AUTOMATIC_LABELS; |
| 269 | else |
| 270 | prometheus_exporter_instance->config.options &= ~EXPORTING_OPTION_SEND_AUTOMATIC_LABELS; |
| 271 | |
| 272 | prometheus_exporter_instance->config.charts_pattern = simple_pattern_create( |
| 273 | prometheus_config_get("send charts matching", "*"), |
| 274 | NULL, |
| 275 | SIMPLE_PATTERN_EXACT, true); |
| 276 | prometheus_exporter_instance->config.hosts_pattern = simple_pattern_create( |
| 277 | prometheus_config_get("send hosts matching", "localhost *"), NULL, SIMPLE_PATTERN_EXACT, true); |
| 278 | |
| 279 | prometheus_exporter_instance->config.prefix = prometheus_config_get("prefix", global_exporting_prefix); |
| 280 | |
| 281 | prometheus_exporter_instance->config.label_prefix = prometheus_config_get("netdata label prefix", ""); |
| 282 | |
| 283 | prometheus_exporter_instance->config.initialized = 1; |
| 284 | } |
| 285 | |
| 286 | while (get_connector_instance(&local_ci)) { |
| 287 | netdata_log_info("Processing connector instance (%s)", local_ci.instance_name); |
| 288 | |
| 289 | if (exporter_get_boolean(local_ci.instance_name, "enabled", 0)) { |
| 290 | netdata_log_info( |
| 291 | "Instance (%s) on connector (%s) is enabled and scheduled for activation", |
| 292 | local_ci.instance_name, local_ci.connector_name); |
| 293 | |
| 294 | tmp_ci_list = (struct connector_instance_list *)callocz(1, sizeof(struct connector_instance_list)); |
| 295 | memcpy(&tmp_ci_list->local_ci, &local_ci, sizeof(local_ci)); |
| 296 | tmp_ci_list->exporting_type = exporting_select_type(local_ci.connector_name); |
| 297 | tmp_ci_list->next = tmp_ci_list_prev; |
| 298 | tmp_ci_list_prev = tmp_ci_list; |
| 299 | instances_to_activate++; |
| 300 | } else |
| 301 | netdata_log_info("Instance (%s) on connector (%s) is not enabled", local_ci.instance_name, local_ci.connector_name); |
| 302 | } |
| 303 | |
| 304 | if (unlikely(!instances_to_activate)) { |
| 305 | netdata_log_info("No connector instances to activate"); |
| 306 | return NULL; |
| 307 | } |
| 308 | |
| 309 | engine = (struct engine *)callocz(1, sizeof(struct engine)); |
| 310 | // TODO: Check and fill engine fields if actually needed |
| 311 | |
| 312 | if (exporting_config_exists) { |
| 313 | engine->config.hostname = |
| 314 | strdupz(exporter_get(CONFIG_SECTION_EXPORTING, "hostname", netdata_configured_hostname)); |
| 315 | engine->config.update_every = exporter_get_number( |
| 316 | CONFIG_SECTION_EXPORTING, EXPORTING_UPDATE_EVERY_OPTION_NAME, EXPORTING_UPDATE_EVERY_DEFAULT); |
| 317 | } |
| 318 | |
| 319 | while (tmp_ci_list) { |
| 320 | struct instance *tmp_instance; |
| 321 | char *instance_name; |
| 322 | char *default_destination = "localhost"; |
| 323 | |
| 324 | netdata_log_info("Instance %s on %s", tmp_ci_list->local_ci.instance_name, tmp_ci_list->local_ci.connector_name); |
| 325 | |
| 326 | if (tmp_ci_list->exporting_type == EXPORTING_CONNECTOR_TYPE_UNKNOWN) { |
| 327 | netdata_log_error("Unknown exporting connector type"); |
| 328 | goto next_connector_instance; |
| 329 | } |
| 330 | |
| 331 | #ifndef ENABLE_PROMETHEUS_REMOTE_WRITE |
| 332 | if (tmp_ci_list->exporting_type == EXPORTING_CONNECTOR_TYPE_PROMETHEUS_REMOTE_WRITE) { |
| 333 | netdata_log_error("Prometheus Remote Write support isn't compiled"); |
| 334 | goto next_connector_instance; |
| 335 | } |
| 336 | #endif |
| 337 | |
| 338 | #ifndef HAVE_KINESIS |
| 339 | if (tmp_ci_list->exporting_type == EXPORTING_CONNECTOR_TYPE_KINESIS) { |
| 340 | netdata_log_error("AWS Kinesis support isn't compiled"); |
| 341 | goto next_connector_instance; |
| 342 | } |
| 343 | #endif |
| 344 | |
| 345 | #ifndef ENABLE_EXPORTING_PUBSUB |
| 346 | if (tmp_ci_list->exporting_type == EXPORTING_CONNECTOR_TYPE_PUBSUB) { |
| 347 | netdata_log_error("Google Cloud Pub/Sub support isn't compiled"); |
| 348 | goto next_connector_instance; |
| 349 | } |
| 350 | #endif |
| 351 | |
| 352 | #ifndef HAVE_MONGOC |
| 353 | if (tmp_ci_list->exporting_type == EXPORTING_CONNECTOR_TYPE_MONGODB) { |
| 354 | netdata_log_error("MongoDB support isn't compiled"); |
| 355 | goto next_connector_instance; |
| 356 | } |
| 357 | #endif |
| 358 | |
| 359 | tmp_instance = (struct instance *)callocz(1, sizeof(struct instance)); |
| 360 | tmp_instance->next = engine->instance_root; |
| 361 | engine->instance_root = tmp_instance; |
| 362 | |
| 363 | tmp_instance->engine = engine; |
| 364 | tmp_instance->config.type = tmp_ci_list->exporting_type; |
| 365 | |
| 366 | instance_name = tmp_ci_list->local_ci.instance_name; |
| 367 | |
| 368 | tmp_instance->config.type_name = strdupz(tmp_ci_list->local_ci.connector_name); |
| 369 | tmp_instance->config.name = strdupz(tmp_ci_list->local_ci.instance_name); |
| 370 | |
| 371 | |
| 372 | tmp_instance->config.update_every = |
| 373 | exporter_get_number(instance_name, EXPORTING_UPDATE_EVERY_OPTION_NAME, EXPORTING_UPDATE_EVERY_DEFAULT); |
| 374 | |
| 375 | tmp_instance->config.buffer_on_failures = exporter_get_number(instance_name, "buffer on failures", 10); |
| 376 | |
| 377 | tmp_instance->config.timeoutms = exporter_get_number(instance_name, "timeout ms", 10000); |
| 378 | |
| 379 | tmp_instance->config.charts_pattern = |
| 380 | simple_pattern_create(exporter_get(instance_name, "send charts matching", "*"), NULL, |
| 381 | SIMPLE_PATTERN_EXACT, |
| 382 | true); |
| 383 | |
| 384 | tmp_instance->config.hosts_pattern = simple_pattern_create( |
| 385 | exporter_get(instance_name, "send hosts matching", "localhost *"), NULL, SIMPLE_PATTERN_EXACT, true); |
| 386 | |
| 387 | const char *data_source = exporter_get(instance_name, "data source", "average"); |
| 388 | |
| 389 | tmp_instance->config.options = exporting_parse_data_source(data_source, tmp_instance->config.options); |
| 390 | if (EXPORTING_OPTIONS_DATA_SOURCE(tmp_instance->config.options) != EXPORTING_SOURCE_DATA_AS_COLLECTED && |
| 391 | tmp_instance->config.update_every % localhost->rrd_update_every) |
| 392 | netdata_log_info( |
| 393 | "The update interval %d for instance %s is not a multiple of the database update interval %d. " |
| 394 | "Metric values will deviate at different points in time.", |
| 395 | tmp_instance->config.update_every, tmp_instance->config.name, localhost->rrd_update_every); |
| 396 | |
| 397 | if (exporter_get_boolean(instance_name, "send configured labels", CONFIG_BOOLEAN_YES)) |
| 398 | tmp_instance->config.options |= EXPORTING_OPTION_SEND_CONFIGURED_LABELS; |
| 399 | else |
| 400 | tmp_instance->config.options &= ~EXPORTING_OPTION_SEND_CONFIGURED_LABELS; |
| 401 | |
| 402 | if (exporter_get_boolean(instance_name, "send automatic labels", CONFIG_BOOLEAN_NO)) |
| 403 | tmp_instance->config.options |= EXPORTING_OPTION_SEND_AUTOMATIC_LABELS; |
| 404 | else |
| 405 | tmp_instance->config.options &= ~EXPORTING_OPTION_SEND_AUTOMATIC_LABELS; |
| 406 | |
| 407 | if (exporter_get_boolean(instance_name, "send names instead of ids", CONFIG_BOOLEAN_YES)) |
| 408 | tmp_instance->config.options |= EXPORTING_OPTION_SEND_NAMES; |
| 409 | else |
| 410 | tmp_instance->config.options &= ~EXPORTING_OPTION_SEND_NAMES; |
| 411 | |
| 412 | if (exporter_get_boolean(instance_name, "send variables", CONFIG_BOOLEAN_YES)) |
| 413 | tmp_instance->config.options |= EXPORTING_OPTION_SEND_VARIABLES; |
| 414 | else |
| 415 | tmp_instance->config.options &= ~EXPORTING_OPTION_SEND_VARIABLES; |
| 416 | |
| 417 | if (tmp_instance->config.type == EXPORTING_CONNECTOR_TYPE_PROMETHEUS_REMOTE_WRITE) { |
| 418 | struct prometheus_remote_write_specific_config *connector_specific_config = |
| 419 | callocz(1, sizeof(struct prometheus_remote_write_specific_config)); |
| 420 | |
| 421 | tmp_instance->config.connector_specific_config = connector_specific_config; |
| 422 | |
| 423 | connector_specific_config->remote_write_path = |
| 424 | strdupz(exporter_get(instance_name, "remote write URL path", "/receive")); |
| 425 | } |
| 426 | |
| 427 | if (tmp_instance->config.type == EXPORTING_CONNECTOR_TYPE_KINESIS) { |
| 428 | struct aws_kinesis_specific_config *connector_specific_config = |
| 429 | callocz(1, sizeof(struct aws_kinesis_specific_config)); |
| 430 | |
| 431 | default_destination = "us-east-1"; |
| 432 | |
| 433 | tmp_instance->config.connector_specific_config = connector_specific_config; |
| 434 | |
| 435 | connector_specific_config->stream_name = strdupz(exporter_get(instance_name, "stream name", "")); |
| 436 | |
| 437 | connector_specific_config->auth_key_id = strdupz(exporter_get(instance_name, "aws_access_key_id", "")); |
| 438 | connector_specific_config->secure_key = strdupz(exporter_get(instance_name, "aws_secret_access_key", "")); |
| 439 | } |
| 440 | |
| 441 | if (tmp_instance->config.type == EXPORTING_CONNECTOR_TYPE_PUBSUB) { |
| 442 | struct pubsub_specific_config *connector_specific_config = |
| 443 | callocz(1, sizeof(struct pubsub_specific_config)); |
| 444 | |
| 445 | default_destination = "pubsub.googleapis.com"; |
| 446 | |
| 447 | tmp_instance->config.connector_specific_config = connector_specific_config; |
| 448 | |
| 449 | connector_specific_config->credentials_file = strdupz(exporter_get(instance_name, "credentials file", "")); |
| 450 | connector_specific_config->project_id = strdupz(exporter_get(instance_name, "project id", "")); |
| 451 | connector_specific_config->topic_id = strdupz(exporter_get(instance_name, "topic id", "")); |
| 452 | } |
| 453 | |
| 454 | if (tmp_instance->config.type == EXPORTING_CONNECTOR_TYPE_MONGODB) { |
| 455 | struct mongodb_specific_config *connector_specific_config = |
| 456 | callocz(1, sizeof(struct mongodb_specific_config)); |
| 457 | |
| 458 | tmp_instance->config.connector_specific_config = connector_specific_config; |
| 459 | |
| 460 | connector_specific_config->database = strdupz(exporter_get( |
| 461 | instance_name, "database", "")); |
| 462 | |
| 463 | connector_specific_config->collection = strdupz(exporter_get( |
| 464 | instance_name, "collection", "")); |
| 465 | } |
| 466 | |
| 467 | tmp_instance->config.destination = strdupz(exporter_get(instance_name, "destination", default_destination)); |
| 468 | |
| 469 | tmp_instance->config.username = strdupz(exporter_get(instance_name, "username", "")); |
| 470 | |
| 471 | tmp_instance->config.password = strdupz(exporter_get(instance_name, "password", "")); |
| 472 | |
| 473 | tmp_instance->config.prefix = strdupz(exporter_get(instance_name, "prefix", "netdata")); |
| 474 | |
| 475 | tmp_instance->config.hostname = strdupz(exporter_get(instance_name, "hostname", engine->config.hostname)); |
| 476 | |
| 477 | #define STR_GRAPHITE_HTTPS "graphite:https" |
| 478 | #define STR_JSON_HTTPS "json:https" |
| 479 | #define STR_OPENTSDB_HTTPS "opentsdb:https" |
| 480 | #define STR_PROMETHEUS_REMOTE_WRITE_HTTPS "prometheus_remote_write:https" |
| 481 | |
| 482 | if ((tmp_instance->config.type == EXPORTING_CONNECTOR_TYPE_GRAPHITE_HTTP && |
| 483 | !strncmp(tmp_ci_list->local_ci.connector_name, STR_GRAPHITE_HTTPS, strlen(STR_GRAPHITE_HTTPS))) || |
| 484 | (tmp_instance->config.type == EXPORTING_CONNECTOR_TYPE_JSON_HTTP && |
| 485 | !strncmp(tmp_ci_list->local_ci.connector_name, STR_JSON_HTTPS, strlen(STR_JSON_HTTPS))) || |
| 486 | (tmp_instance->config.type == EXPORTING_CONNECTOR_TYPE_OPENTSDB_HTTP && |
| 487 | !strncmp(tmp_ci_list->local_ci.connector_name, STR_OPENTSDB_HTTPS, strlen(STR_OPENTSDB_HTTPS))) || |
| 488 | (tmp_instance->config.type == EXPORTING_CONNECTOR_TYPE_PROMETHEUS_REMOTE_WRITE && |
| 489 | !strncmp( |
| 490 | tmp_ci_list->local_ci.connector_name, STR_PROMETHEUS_REMOTE_WRITE_HTTPS, |
| 491 | strlen(STR_PROMETHEUS_REMOTE_WRITE_HTTPS)))) { |
| 492 | tmp_instance->config.options |= EXPORTING_OPTION_USE_TLS; |
| 493 | } |
| 494 | |
| 495 | #ifdef NETDATA_INTERNAL_CHECKS |
| 496 | netdata_log_info( |
| 497 | " Dest=[%s], upd=[%d], buffer=[%d] timeout=[%ld] options=[%u]", |
| 498 | tmp_instance->config.destination, |
| 499 | tmp_instance->config.update_every, |
| 500 | tmp_instance->config.buffer_on_failures, |
| 501 | tmp_instance->config.timeoutms, |
| 502 | tmp_instance->config.options); |
| 503 | #endif |
| 504 | |
| 505 | if (unlikely(!exporting_config_exists) && !engine->config.hostname) { |
| 506 | engine->config.hostname = strdupz(inicfg_get(&netdata_config, instance_name, "hostname", netdata_configured_hostname)); |
| 507 | engine->config.update_every = |
| 508 | inicfg_get_number(&netdata_config, instance_name, EXPORTING_UPDATE_EVERY_OPTION_NAME, EXPORTING_UPDATE_EVERY_DEFAULT); |
| 509 | } |
| 510 | |
| 511 | next_connector_instance: |
| 512 | tmp_ci_list1 = tmp_ci_list->next; |
| 513 | freez(tmp_ci_list); |
| 514 | tmp_ci_list = tmp_ci_list1; |
| 515 | } |
| 516 | |
| 517 | return engine; |
| 518 | } |