From 4978089aab9d0875dc5b304c066d6b7d2281feb6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 24 May 2025 07:26:29 +0200 Subject: [PATCH] Adding upstream version 1.34.4. Signed-off-by: Daniel Baumann --- .circleci/config.yml | 885 + .gitattributes | 8 + .github/ISSUE_TEMPLATE/BUG_REPORT.yml | 74 + .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml | 37 + .github/ISSUE_TEMPLATE/SUPPORT.yml | 22 + .github/PULL_REQUEST_TEMPLATE.md | 18 + .github/dependabot.yml | 20 + .github/workflows/linter.yml | 65 + .github/workflows/milestones.yml | 29 + .github/workflows/pr-target-branch.yml | 24 + .github/workflows/readme-linter.yml | 26 + .github/workflows/semantic.yml | 15 + .gitignore | 23 + .golangci.yml | 638 + .markdownlint.yml | 6 + .markdownlintignore | 2 + CHANGELOG-1.13.md | 2795 ++++ CHANGELOG.md | 4258 +++++ CODE_OF_CONDUCT.md | 77 + CONTRIBUTING.md | 129 + EXTERNAL_PLUGINS.md | 48 + LICENSE | 21 + Makefile | 502 + README.md | 126 + SECURITY.md | 11 + accumulator.go | 93 + agent/README.md | 6 + agent/accumulator.go | 160 + agent/accumulator_test.go | 160 + agent/agent.go | 1215 ++ agent/agent_posix.go | 19 + agent/agent_test.go | 259 + agent/agent_windows.go | 13 + .../aggregators-rerun-processors/expected.out | 2 + .../aggregators-rerun-processors/input.influx | 1 + .../telegraf.conf | 22 + .../aggregators-skip-processors/expected.out | 2 + .../aggregators-skip-processors/input.influx | 1 + .../aggregators-skip-processors/telegraf.conf | 22 + .../processor-order-appearance/expected.out | 2 + .../processor-order-appearance/input.influx | 1 + .../processor-order-appearance/telegraf.conf | 26 + .../processor-order-explicit/expected.out | 2 + .../processor-order-explicit/input.influx | 1 + .../processor-order-explicit/telegraf.conf | 27 + .../processor-order-mixed/expected.out | 2 + .../processor-order-mixed/input.influx | 1 + .../processor-order-mixed/telegraf.conf | 25 + .../processor-order-no-starlark/expected.out | 2 + .../processor-order-no-starlark/input.influx | 1 + .../processor-order-no-starlark/telegraf.conf | 26 + agent/tick.go | 281 + agent/tick_test.go | 395 + aggregator.go | 18 + assets/GopherAndTiger.png | Bin 0 -> 74224 bytes assets/TelegrafTiger.png | Bin 0 -> 7748 bytes assets/TelegrafTigerSmall.png | Bin 0 -> 3448 bytes assets/windows/icon.icns | Bin 0 -> 508472 bytes assets/windows/tiger.ico | Bin 0 -> 17598 bytes build_version.txt | 1 + cmd/telegraf/README.md | 1 + cmd/telegraf/agent.conf | 104 + cmd/telegraf/cmd_config.go | 240 + cmd/telegraf/cmd_plugins.go | 192 + cmd/telegraf/cmd_secretstore.go | 261 + cmd/telegraf/cmd_win_service.go | 203 + cmd/telegraf/cmd_win_service_notwindows.go | 17 + cmd/telegraf/main.go | 417 + cmd/telegraf/main_test.go | 574 + cmd/telegraf/main_win_test.go | 38 + cmd/telegraf/pprof.go | 52 + cmd/telegraf/printer.go | 408 + cmd/telegraf/telegraf.go | 493 + cmd/telegraf/telegraf_posix.go | 42 + cmd/telegraf/telegraf_windows.go | 408 + config/README.md | 1 + config/config.go | 1924 +++ config/config_test.go | 1540 ++ config/deprecation.go | 393 + config/deprecation_test.go | 277 + config/envvar.go | 252 + config/internal_test.go | 411 + config/migration.go | 261 + config/plugin_id.go | 79 + config/plugin_printer.go | 106 + config/secret.go | 315 + config/secret_protected.go | 131 + config/secret_test.go | 845 + config/secret_unprotected.go | 94 + config/testdata/addressbook.proto | 28 + config/testdata/azure_monitor.toml | 4 + config/testdata/default_parser.toml | 2 + config/testdata/default_parser_exec.toml | 2 + config/testdata/deprecated_field_filter.toml | 8 + config/testdata/envvar_comments.toml | 99 + config/testdata/envvar_comments_expected.toml | 99 + config/testdata/filter_metricpass.toml | 2 + config/testdata/inline_table.toml | 7 + config/testdata/invalid_field.toml | 2 + .../invalid_field_in_parser_table.toml | 5 + .../invalid_field_in_parserfunc_table.toml | 5 + config/testdata/invalid_field_processor.toml | 2 + .../invalid_field_processor_in_parser.toml | 3 + ...valid_field_processor_in_parser_table.toml | 5 + ...invalid_field_processor_in_parserfunc.toml | 3 + ...d_field_processor_in_parserfunc_table.toml | 5 + .../invalid_field_processor_with_parser.toml | 3 + ...valid_field_processor_with_parserfunc.toml | 3 + .../testdata/invalid_field_with_parser.toml | 3 + .../invalid_field_with_parserfunc.toml | 3 + config/testdata/non_slice_slice.toml | 4 + config/testdata/parsers_new.toml | 65 + .../processor_order/multiple_processors.toml | 7 + .../multiple_processors_messy_order.toml | 16 + .../multiple_processors_simple_order.toml | 9 + config/testdata/processors_with_parsers.toml | 65 + config/testdata/serializers_new.toml | 32 + config/testdata/serializers_old.toml | 32 + config/testdata/single_plugin.toml | 11 + config/testdata/single_plugin_env_vars.toml | 35 + .../single_plugin_with_comment_in_array.toml | 5 + .../single_plugin_with_separators.toml | 13 + config/testdata/slice_comment.toml | 5 + config/testdata/special_types.key | 5 + config/testdata/special_types.pem | 11 + config/testdata/special_types.toml | 8 + ...state_persistence_input_all_different.toml | 42 + .../state_persistence_input_all_same.toml | 60 + .../state_persistence_input_store_load.toml | 17 + .../state_persistence_processors.toml | 8 + config/testdata/subconfig/exec.conf | 4 + config/testdata/subconfig/memcached.conf | 11 + config/testdata/subconfig/procstat.conf | 2 + config/testdata/telegraf-agent.toml | 297 + config/testdata/wrong_cert_path.toml | 5 + config/testdata/wrong_field_type.toml | 2 + config/testdata/wrong_field_type2.toml | 2 + config/types.go | 85 + config/types_test.go | 277 + docs/AGGREGATORS.md | 150 + docs/AGGREGATORS_AND_PROCESSORS.md | 93 + docs/APPARMOR.md | 26 + docs/COMMANDS_AND_FLAGS.md | 57 + docs/CONFIGURATION.md | 918 ++ docs/CUSTOMIZATION.md | 46 + docs/DATA_FORMATS_INPUT.md | 45 + docs/DATA_FORMATS_OUTPUT.md | 32 + docs/DOCKER.md | 64 + docs/EXTERNAL_PLUGINS.md | 100 + docs/FAQ.md | 135 + docs/INPUTS.md | 189 + docs/INSTALL_GUIDE.md | 156 + docs/INTEGRATION_TESTS.md | 166 + docs/LICENSE_OF_DEPENDENCIES.md | 480 + docs/METRICS.md | 50 + docs/NIGHTLIES.md | 32 + docs/OUTPUTS.md | 150 + docs/PARSING_DATA.md | 243 + docs/PROCESSORS.md | 180 + docs/PROFILING.md | 57 + docs/QUICK_START.md | 68 + docs/README.md | 89 + docs/RELEASES.md | 23 + docs/SECRETSTORES.md | 115 + docs/SQL_DRIVERS_INPUT.md | 55 + docs/SUPPORTED_PLATFORMS.md | 60 + docs/TEMPLATE_PATTERN.md | 137 + docs/TLS.md | 126 + docs/TOML.md | 100 + docs/WINDOWS_SERVICE.md | 129 + docs/developers/CODE_STYLE.md | 8 + docs/developers/DEBUG.md | 84 + docs/developers/DEPRECATION.md | 93 + docs/developers/LOGGING.md | 79 + docs/developers/METRIC_FORMAT_CHANGES.md | 49 + docs/developers/PACKAGING.md | 70 + docs/developers/PROFILING.md | 66 + docs/developers/README.md | 1 + docs/developers/REVIEWS.md | 185 + docs/developers/SAMPLE_CONFIG.md | 81 + docs/developers/STATE_PERSISTENCE.md | 145 + docs/includes/plugin_config.md | 6 + docs/includes/secret_usage.md | 7 + docs/includes/service_input.md | 8 + docs/includes/startup_error_behavior.md | 14 + docs/specs/README.md | 71 + docs/specs/template.md | 20 + docs/specs/tsd-001-deprecation.md | 182 + docs/specs/tsd-002-custom-builder.md | 71 + docs/specs/tsd-003-state-persistence.md | 125 + docs/specs/tsd-004-configuration-migration.md | 69 + docs/specs/tsd-005-output-buffer-strategy.md | 77 + docs/specs/tsd-006-startup-error-behavior.md | 115 + docs/specs/tsd-007-url-config-behavior.md | 75 + .../tsd-008-partial-write-error-handling.md | 78 + docs/specs/tsd-009-probe-on-startup.md | 68 + etc/logrotate.d/telegraf | 11 + filter/filter.go | 140 + filter/filter_test.go | 132 + go.mod | 549 + go.sum | 3497 ++++ info.plist | 16 + input.go | 23 + internal/choice/choice.go | 36 + internal/content_coding.go | 495 + internal/content_coding_test.go | 555 + internal/customized_no.go | 5 + internal/customized_yes.go | 5 + internal/docker/docker.go | 33 + internal/docker/docker_test.go | 60 + internal/env.go | 19 + internal/errors.go | 63 + internal/exec.go | 44 + internal/exec_unix.go | 66 + internal/exec_windows.go | 41 + internal/fuzz/json.go | 42 + internal/globpath/globpath.go | 97 + internal/globpath/globpath_test.go | 124 + internal/globpath/testdata/log1.log | 0 internal/globpath/testdata/log2.log | 0 internal/globpath/testdata/log[!.log | 0 .../testdata/nested1/nested2/nested.txt | 0 internal/globpath/testdata/test.conf | 5 + internal/goplugin/noplugin.go | 9 + internal/goplugin/plugin.go | 42 + internal/host_endianness_be.go | 7 + internal/host_endianness_le.go | 7 + internal/http.go | 227 + internal/internal.go | 441 + internal/internal_test.go | 784 + internal/limiter/limiter.go | 59 + internal/process/process.go | 215 + internal/process/process_posix.go | 27 + internal/process/process_test.go | 81 + internal/process/process_windows.go | 19 + internal/rotate/file_writer.go | 183 + internal/rotate/file_writer_test.go | 150 + internal/snmp/config.go | 53 + internal/snmp/field.go | 327 + internal/snmp/field_test.go | 252 + internal/snmp/mib_loader.go | 140 + internal/snmp/mib_loader_test.go | 87 + internal/snmp/table.go | 304 + internal/snmp/table_test.go | 246 + internal/snmp/testdata/gosmi/bridgeMib | 1467 ++ internal/snmp/testdata/gosmi/bridgeMibImports | 554 + internal/snmp/testdata/gosmi/foo | 30 + internal/snmp/testdata/gosmi/fooImports | 169 + internal/snmp/testdata/gosmi/ifPhysAddress | 84 + .../snmp/testdata/gosmi/ifPhysAddressImports | 254 + internal/snmp/testdata/gosmi/server | 98 + internal/snmp/testdata/gosmi/serverImports | 174 + internal/snmp/testdata/gosmi/tableBuild | 57 + internal/snmp/testdata/gosmi/tableMib | 2613 +++ internal/snmp/testdata/gosmi/tableMibImports | 119 + internal/snmp/testdata/gosmi/tcpMib | 786 + internal/snmp/testdata/gosmi/tcpMibImports | 639 + .../loadMibsFromPath/linkTarget/emptyFile | 0 .../loadMibsFromPath/root/dirOne/dirTwo/empty | 0 .../testdata/loadMibsFromPath/root/symlink | 1 + internal/snmp/testdata/mibs/testmib | 22 + internal/snmp/translator.go | 29 + internal/snmp/translator_gosmi.go | 240 + internal/snmp/translator_gosmi_test.go | 728 + internal/snmp/translator_netsnmp.go | 272 + .../snmp/translator_netsnmp_mocks_generate.go | 102 + .../snmp/translator_netsnmp_mocks_test.go | 211 + internal/snmp/translator_netsnmp_test.go | 291 + internal/snmp/wrapper.go | 201 + internal/snmp/wrapper_test.go | 89 + internal/templating/engine.go | 88 + internal/templating/engine_test.go | 77 + internal/templating/matcher.go | 58 + internal/templating/node.go | 136 + internal/templating/template.go | 142 + internal/templating/template_test.go | 14 + internal/type_conversions.go | 763 + logger.go | 101 + logger/event_logger.go | 78 + logger/event_logger_test.go | 95 + logger/handler.go | 142 + logger/logger.go | 314 + logger/logger_test.go | 39 + logger/registry.go | 9 + logger/stdlog_redirector.go | 32 + logger/structured_logger.go | 98 + logger/structured_logger_test.go | 393 + logger/text_logger.go | 68 + logger/text_logger_test.go | 256 + metric.go | 154 + metric/deserialize.go | 85 + metric/init.go | 7 + metric/metric.go | 387 + metric/metric_test.go | 328 + metric/series_grouper.go | 106 + metric/series_grouper_test.go | 37 + metric/tracking.go | 195 + metric/tracking_test.go | 301 + migrations/all/all.go | 1 + migrations/all/general_metricfilter.go | 5 + migrations/all/global_agent.go | 5 + migrations/all/inputs.nats_consumer.go | 5 + migrations/all/inputs_cassandra.go | 5 + migrations/all/inputs_disk.go | 5 + migrations/all/inputs_gnmi.go | 5 + migrations/all/inputs_httpjson.go | 5 + migrations/all/inputs_io.go | 5 + migrations/all/inputs_jolokia.go | 5 + .../all/inputs_kafka_consumer_legacy.go | 5 + migrations/all/inputs_mqtt_consumer.go | 5 + migrations/all/inputs_procstat.go | 5 + migrations/all/inputs_sflow.go | 5 + migrations/all/inputs_snmp_legacy.go | 5 + migrations/all/inputs_tcp_listener.go | 5 + migrations/all/inputs_udp_listener.go | 5 + migrations/all/outputs_influxdb.go | 5 + migrations/all/outputs_riemann_legacy.go | 5 + migrations/common/filter_options.go | 17 + migrations/common/input_options.go | 43 + migrations/common/output_options.go | 35 + migrations/general_metricfilter/migration.go | 112 + .../general_metricfilter/migration_test.go | 96 + .../testcases/deprecated_drop/expected.conf | 3 + .../testcases/deprecated_drop/telegraf.conf | 10 + .../deprecated_fielddrop/expected.conf | 3 + .../deprecated_fielddrop/telegraf.conf | 10 + .../deprecated_fieldpass/expected.conf | 3 + .../deprecated_fieldpass/telegraf.conf | 10 + .../testcases/deprecated_pass/expected.conf | 3 + .../testcases/deprecated_pass/telegraf.conf | 10 + .../testcases/merge_all_overlap/expected.conf | 4 + .../testcases/merge_all_overlap/telegraf.conf | 15 + .../merge_fieldexclude/expected.conf | 3 + .../merge_fieldexclude/telegraf.conf | 12 + .../merge_fieldexclude_overlap/expected.conf | 3 + .../merge_fieldexclude_overlap/telegraf.conf | 12 + .../merge_fieldinclude/expected.conf | 3 + .../merge_fieldinclude/telegraf.conf | 12 + .../merge_fieldinclude_overlap/expected.conf | 3 + .../merge_fieldinclude_overlap/telegraf.conf | 12 + migrations/global_agent/migration.go | 75 + migrations/global_agent/migration_test.go | 104 + .../global_agent/testcases/default.conf | 100 + .../logtarget_eventlog/expected.conf | 10 + .../logtarget_eventlog/telegraf.conf | 102 + .../logtarget_eventlog_collision.conf | 102 + .../expected.conf | 10 + .../telegraf.conf | 102 + .../testcases/logtarget_file/expected.conf | 10 + .../testcases/logtarget_file/telegraf.conf | 102 + .../logtarget_file_no_logfile/expected.conf | 9 + .../logtarget_file_no_logfile/telegraf.conf | 102 + .../testcases/logtarget_stderr/expected.conf | 9 + .../testcases/logtarget_stderr/telegraf.conf | 102 + .../expected.conf | 9 + .../telegraf.conf | 102 + migrations/inputs_cassandra/migration.go | 247 + migrations/inputs_cassandra/migration_test.go | 61 + .../testcases/filter_options/expected.conf | 55 + .../testcases/filter_options/telegraf.conf | 11 + .../testcases/general_options/expected.conf | 64 + .../testcases/general_options/telegraf.conf | 13 + .../testcases/simple/expected.conf | 40 + .../testcases/simple/telegraf.conf | 14 + migrations/inputs_disk/migration.go | 67 + migrations/inputs_disk/migration_test.go | 86 + .../deprecated_mountpoints/expected.conf | 3 + .../deprecated_mountpoints/telegraf.conf | 7 + .../expected.conf | 3 + .../telegraf.conf | 11 + migrations/inputs_gnmi/migration.go | 47 + migrations/inputs_gnmi/migration_test.go | 73 + .../deprecated_guess_path/expected.conf | 11 + .../deprecated_guess_path/telegraf.conf | 109 + .../deprecated_guess_path_false/expected.conf | 10 + .../deprecated_guess_path_false/telegraf.conf | 109 + migrations/inputs_httpjson/migration.go | 143 + migrations/inputs_httpjson/migration_test.go | 151 + .../testcases/array/expected.conf | 5 + .../testcases/array/input.json | 20 + .../testcases/array/output.influx | 2 + .../testcases/array/telegraf.conf | 3 + .../testcases/filters/expected.conf | 8 + .../testcases/filters/telegraf.conf | 6 + .../testcases/headers/expected.conf | 8 + .../testcases/headers/telegraf.conf | 6 + .../testcases/params/expected.conf | 4 + .../testcases/params/telegraf.conf | 8 + .../testcases/single/expected.conf | 5 + .../testcases/single/input.json | 9 + .../testcases/single/output.influx | 1 + .../testcases/single/telegraf.conf | 46 + migrations/inputs_io/migration.go | 32 + migrations/inputs_io/migration_test.go | 61 + .../inputs_io/testcases/empty/expected.conf | 29 + .../inputs_io/testcases/empty/telegraf.conf | 29 + .../inputs_io/testcases/full/expected.conf | 10 + .../inputs_io/testcases/full/telegraf.conf | 34 + migrations/inputs_jolokia/README.md | 0 migrations/inputs_jolokia/migration.go | 353 + migrations/inputs_jolokia/migration_test.go | 62 + .../testcases/agent_default/expected.conf | 24 + .../testcases/agent_default/telegraf.conf | 54 + .../agent_more_complex/expected.conf | 27 + .../agent_more_complex/telegraf.conf | 54 + .../agent_response_timeout/expected.conf | 25 + .../agent_response_timeout/telegraf.conf | 54 + .../testcases/proxy_default/expected.conf | 27 + .../testcases/proxy_default/telegraf.conf | 54 + .../inputs_kafka_consumer_legacy/README.md | 0 .../inputs_kafka_consumer_legacy/migration.go | 21 + .../migration_test.go | 29 + migrations/inputs_mqtt_consumer/migration.go | 43 + .../inputs_mqtt_consumer/migration_test.go | 161 + .../deprecated_metric_buffer/expected.conf | 4 + .../deprecated_metric_buffer/telegraf.conf | 10 + .../expected.conf | 12 + .../telegraf.conf | 20 + migrations/inputs_nats_consumer/migration.go | 43 + .../inputs_nats_consumer/migration_test.go | 135 + .../deprecated_metric_buffer/expected.conf | 6 + .../deprecated_metric_buffer/telegraf.conf | 19 + .../expected.conf | 14 + .../telegraf.conf | 27 + migrations/inputs_procstat/migration.go | 114 + migrations/inputs_procstat/migration_test.go | 73 + .../expected.conf | 2 + .../telegraf.conf | 3 + .../deprecated_supervisor_unit/expected.conf | 3 + .../deprecated_supervisor_unit/telegraf.conf | 47 + .../deprecated_tagging_false/expected.conf | 3 + .../deprecated_tagging_false/telegraf.conf | 47 + .../deprecated_tagging_true/expected.conf | 4 + .../deprecated_tagging_true/telegraf.conf | 47 + .../expected.conf | 4 + .../telegraf.conf | 49 + .../expected.conf | 4 + .../telegraf.conf | 49 + migrations/inputs_sflow/migration.go | 68 + migrations/inputs_sflow/migration_test.go | 62 + .../testcases/filters/expected.conf | 7 + .../testcases/filters/telegraf.conf | 8 + .../testcases/minimal/expected.conf | 2 + .../testcases/minimal/telegraf.conf | 11 + .../testcases/read_buffer_size/expected.conf | 3 + .../testcases/read_buffer_size/telegraf.conf | 11 + migrations/inputs_snmp_legacy/migration.go | 21 + .../inputs_snmp_legacy/migration_test.go | 23 + migrations/inputs_tcp_listener/README.md | 0 migrations/inputs_tcp_listener/migration.go | 67 + .../inputs_tcp_listener/migration_test.go | 62 + .../allow_pending_messages/expected.conf | 3 + .../allow_pending_messages/telegraf.conf | 5 + .../testcases/parser/expected.conf | 10 + .../testcases/parser/telegraf.conf | 13 + .../testcases/simple/expected.conf | 3 + .../testcases/simple/telegraf.conf | 4 + migrations/inputs_udp_listener/README.md | 0 migrations/inputs_udp_listener/migration.go | 73 + .../inputs_udp_listener/migration_test.go | 62 + .../all_deprecated_messages/expected.conf | 3 + .../all_deprecated_messages/telegraf.conf | 5 + .../allow_pending_messages/expected.conf | 3 + .../allow_pending_messages/telegraf.conf | 5 + .../testcases/parser/expected.conf | 10 + .../testcases/parser/telegraf.conf | 13 + .../testcases/simple/expected.conf | 3 + .../testcases/simple/telegraf.conf | 4 + migrations/outputs_influxdb/migration.go | 65 + migrations/outputs_influxdb/migration_test.go | 73 + .../testcases/convert_url/expected.conf | 2 + .../testcases/convert_url/telegraf.conf | 78 + .../testcases/merge_url/expected.conf | 5 + .../testcases/merge_url/telegraf.conf | 7 + .../testcases/merge_url_overlap/expected.conf | 5 + .../testcases/merge_url_overlap/telegraf.conf | 7 + migrations/outputs_riemann_legacy/README.md | 0 .../outputs_riemann_legacy/migration.go | 106 + .../outputs_riemann_legacy/migration_test.go | 61 + .../testcases/general_options/expected.conf | 5 + .../testcases/general_options/telegraf.conf | 9 + .../testcases/simple/expected.conf | 3 + .../testcases/simple/telegraf.conf | 8 + migrations/registry.go | 48 + migrations/utils.go | 37 + models/buffer.go | 175 + models/buffer_disk.go | 297 + models/buffer_disk_test.go | 154 + models/buffer_mem.go | 190 + models/buffer_mem_test.go | 46 + models/buffer_suite_test.go | 960 ++ models/common.go | 38 + models/filter.go | 344 + models/filter_test.go | 744 + models/makemetric.go | 34 + models/running_aggregator.go | 202 + models/running_aggregator_test.go | 267 + models/running_input.go | 278 + models/running_input_test.go | 550 + models/running_output.go | 401 + models/running_output_test.go | 1000 ++ models/running_parsers.go | 102 + models/running_processor.go | 117 + models/running_processor_test.go | 226 + models/running_serializer.go | 106 + output.go | 29 + parser.go | 40 + persister/persister.go | 103 + plugin.go | 64 + plugins/aggregators/all/all.go | 1 + plugins/aggregators/all/basicstats.go | 5 + plugins/aggregators/all/derivative.go | 5 + plugins/aggregators/all/final.go | 5 + plugins/aggregators/all/histogram.go | 5 + plugins/aggregators/all/merge.go | 5 + plugins/aggregators/all/minmax.go | 5 + plugins/aggregators/all/quantile.go | 5 + plugins/aggregators/all/starlark.go | 5 + plugins/aggregators/all/valuecounter.go | 5 + plugins/aggregators/basicstats/README.md | 74 + plugins/aggregators/basicstats/basicstats.go | 325 + .../aggregators/basicstats/basicstats_test.go | 826 + plugins/aggregators/basicstats/sample.conf | 11 + plugins/aggregators/deprecations.go | 6 + plugins/aggregators/derivative/README.md | 228 + plugins/aggregators/derivative/derivative.go | 183 + .../aggregators/derivative/derivative_test.go | 418 + plugins/aggregators/derivative/sample.conf | 16 + plugins/aggregators/final/README.md | 92 + plugins/aggregators/final/final.go | 90 + plugins/aggregators/final/final_test.go | 308 + plugins/aggregators/final/sample.conf | 20 + plugins/aggregators/histogram/README.md | 135 + plugins/aggregators/histogram/histogram.go | 327 + .../aggregators/histogram/histogram_test.go | 529 + plugins/aggregators/histogram/sample.conf | 40 + plugins/aggregators/merge/README.md | 49 + plugins/aggregators/merge/merge.go | 63 + plugins/aggregators/merge/merge_test.go | 374 + plugins/aggregators/merge/sample.conf | 15 + plugins/aggregators/minmax/README.md | 56 + plugins/aggregators/minmax/minmax.go | 114 + plugins/aggregators/minmax/minmax_test.go | 167 + plugins/aggregators/minmax/sample.conf | 9 + plugins/aggregators/quantile/README.md | 145 + plugins/aggregators/quantile/algorithms.go | 108 + plugins/aggregators/quantile/quantile.go | 149 + plugins/aggregators/quantile/quantile_test.go | 671 + plugins/aggregators/quantile/sample.conf | 26 + plugins/aggregators/registry.go | 11 + plugins/aggregators/starlark/README.md | 137 + plugins/aggregators/starlark/sample.conf | 29 + plugins/aggregators/starlark/starlark.go | 114 + plugins/aggregators/starlark/starlark_test.go | 434 + .../aggregators/starlark/testdata/merge.star | 31 + .../starlark/testdata/min_max.star | 53 + plugins/aggregators/valuecounter/README.md | 90 + plugins/aggregators/valuecounter/sample.conf | 12 + .../aggregators/valuecounter/valuecounter.go | 86 + .../valuecounter/valuecounter_test.go | 125 + plugins/all_test.go | 115 + plugins/common/adx/adx.go | 189 + plugins/common/adx/adx_test.go | 219 + plugins/common/auth/basic_auth.go | 23 + plugins/common/auth/basic_auth_test.go | 34 + plugins/common/aws/credentials.go | 84 + plugins/common/cookie/cookie.go | 136 + plugins/common/cookie/cookie_test.go | 281 + plugins/common/docker/stats_helpers.go | 79 + plugins/common/encoding/decoder.go | 34 + plugins/common/encoding/decoder_reader.go | 164 + plugins/common/encoding/decoder_test.go | 78 + plugins/common/http/config.go | 78 + plugins/common/jolokia2/client.go | 275 + plugins/common/jolokia2/gatherer.go | 266 + plugins/common/jolokia2/gatherer_test.go | 104 + plugins/common/jolokia2/metric.go | 128 + plugins/common/jolokia2/point_builder.go | 274 + plugins/common/kafka/config.go | 158 + plugins/common/kafka/config_test.go | 22 + plugins/common/kafka/logger.go | 41 + plugins/common/kafka/sasl.go | 127 + plugins/common/kafka/scram_client.go | 35 + plugins/common/logrus/hook.go | 35 + plugins/common/mqtt/mqtt.go | 95 + plugins/common/mqtt/mqtt_logger.go | 17 + plugins/common/mqtt/mqtt_test.go | 26 + plugins/common/mqtt/mqtt_v3.go | 139 + plugins/common/mqtt/mqtt_v5.go | 165 + plugins/common/oauth/config.go | 42 + plugins/common/opcua/client.go | 241 + plugins/common/opcua/client_test.go | 33 + plugins/common/opcua/input/input_client.go | 500 + .../common/opcua/input/input_client_test.go | 890 ++ plugins/common/opcua/logger.go | 15 + plugins/common/opcua/opcua_util.go | 359 + plugins/common/parallel/ordered.go | 84 + plugins/common/parallel/parallel.go | 8 + plugins/common/parallel/parallel_test.go | 117 + plugins/common/parallel/unordered.go | 60 + plugins/common/postgresql/config.go | 184 + plugins/common/postgresql/config_test.go | 240 + plugins/common/postgresql/service.go | 42 + plugins/common/proxy/connect.go | 140 + plugins/common/proxy/dialer.go | 37 + plugins/common/proxy/proxy.go | 57 + plugins/common/proxy/socks5.go | 22 + plugins/common/proxy/socks5_test.go | 74 + plugins/common/psutil/mock_ps.go | 155 + plugins/common/psutil/ps.go | 256 + plugins/common/ratelimiter/config.go | 23 + plugins/common/ratelimiter/limiters.go | 66 + plugins/common/ratelimiter/limiters_test.go | 189 + plugins/common/ratelimiter/serializers.go | 100 + .../common/ratelimiter/serializers_test.go | 352 + plugins/common/shim/README.md | 64 + plugins/common/shim/config.go | 170 + plugins/common/shim/config_test.go | 87 + plugins/common/shim/example/cmd/main.go | 64 + plugins/common/shim/example/cmd/plugin.conf | 2 + plugins/common/shim/goshim.go | 145 + plugins/common/shim/goshim_test.go | 78 + plugins/common/shim/input.go | 116 + plugins/common/shim/input_test.go | 140 + plugins/common/shim/output.go | 54 + plugins/common/shim/output_test.go | 81 + plugins/common/shim/processor.go | 81 + plugins/common/shim/processor_test.go | 113 + plugins/common/shim/testdata/plugin.conf | 4 + plugins/common/shim/testdata/processor.conf | 2 + plugins/common/shim/testdata/special.conf | 5 + plugins/common/socket/datagram.go | 267 + plugins/common/socket/socket.conf | 37 + plugins/common/socket/socket.go | 181 + plugins/common/socket/socket_test.go | 845 + plugins/common/socket/splitter.conf | 37 + plugins/common/socket/splitters.go | 167 + plugins/common/socket/stream.go | 476 + plugins/common/starlark/builtins.go | 305 + plugins/common/starlark/field_dict.go | 308 + plugins/common/starlark/logging.go | 48 + plugins/common/starlark/metric.go | 156 + plugins/common/starlark/starlark.go | 282 + plugins/common/starlark/tag_dict.go | 226 + plugins/common/tls/client.conf | 24 + plugins/common/tls/common.go | 34 + plugins/common/tls/config.go | 298 + plugins/common/tls/config_test.go | 614 + plugins/common/tls/utils.go | 112 + plugins/common/yangmodel/decoder.go | 263 + plugins/inputs/activemq/README.md | 100 + plugins/inputs/activemq/activemq.go | 285 + plugins/inputs/activemq/activemq_test.go | 186 + plugins/inputs/activemq/sample.conf | 21 + plugins/inputs/aerospike/README.md | 173 + plugins/inputs/aerospike/aerospike.go | 457 + plugins/inputs/aerospike/aerospike_test.go | 480 + plugins/inputs/aerospike/sample.conf | 41 + plugins/inputs/aliyuncms/README.md | 195 + plugins/inputs/aliyuncms/aliyuncms.go | 496 + plugins/inputs/aliyuncms/aliyuncms_test.go | 514 + plugins/inputs/aliyuncms/discovery.go | 458 + plugins/inputs/aliyuncms/sample.conf | 120 + plugins/inputs/all/activemq.go | 5 + plugins/inputs/all/aerospike.go | 5 + plugins/inputs/all/aliyuncms.go | 5 + plugins/inputs/all/all.go | 1 + plugins/inputs/all/amd_rocm_smi.go | 5 + plugins/inputs/all/amqp_consumer.go | 5 + plugins/inputs/all/apache.go | 5 + plugins/inputs/all/apcupsd.go | 5 + plugins/inputs/all/aurora.go | 5 + plugins/inputs/all/azure_monitor.go | 5 + plugins/inputs/all/azure_storage_queue.go | 5 + plugins/inputs/all/bcache.go | 5 + plugins/inputs/all/beanstalkd.go | 5 + plugins/inputs/all/beat.go | 5 + plugins/inputs/all/bind.go | 5 + plugins/inputs/all/bond.go | 5 + plugins/inputs/all/burrow.go | 5 + plugins/inputs/all/ceph.go | 5 + plugins/inputs/all/cgroup.go | 5 + plugins/inputs/all/chrony.go | 5 + plugins/inputs/all/cisco_telemetry_mdt.go | 5 + plugins/inputs/all/clickhouse.go | 5 + plugins/inputs/all/cloud_pubsub.go | 5 + plugins/inputs/all/cloud_pubsub_push.go | 5 + plugins/inputs/all/cloudwatch.go | 5 + .../inputs/all/cloudwatch_metric_streams.go | 5 + plugins/inputs/all/conntrack.go | 5 + plugins/inputs/all/consul.go | 5 + plugins/inputs/all/consul_agent.go | 5 + plugins/inputs/all/couchbase.go | 5 + plugins/inputs/all/couchdb.go | 5 + plugins/inputs/all/cpu.go | 5 + plugins/inputs/all/csgo.go | 5 + plugins/inputs/all/ctrlx_datalayer.go | 5 + plugins/inputs/all/dcos.go | 5 + plugins/inputs/all/directory_monitor.go | 5 + plugins/inputs/all/disk.go | 5 + plugins/inputs/all/diskio.go | 5 + plugins/inputs/all/disque.go | 5 + plugins/inputs/all/dmcache.go | 5 + plugins/inputs/all/dns_query.go | 5 + plugins/inputs/all/docker.go | 5 + plugins/inputs/all/docker_log.go | 5 + plugins/inputs/all/dovecot.go | 5 + plugins/inputs/all/dpdk.go | 5 + plugins/inputs/all/ecs.go | 5 + plugins/inputs/all/elasticsearch.go | 5 + plugins/inputs/all/elasticsearch_query.go | 5 + plugins/inputs/all/ethtool.go | 5 + plugins/inputs/all/eventhub_consumer.go | 5 + plugins/inputs/all/exec.go | 5 + plugins/inputs/all/execd.go | 5 + plugins/inputs/all/fail2ban.go | 5 + plugins/inputs/all/fibaro.go | 5 + plugins/inputs/all/file.go | 5 + plugins/inputs/all/filecount.go | 5 + plugins/inputs/all/filestat.go | 5 + plugins/inputs/all/fireboard.go | 5 + plugins/inputs/all/firehose.go | 5 + plugins/inputs/all/fluentd.go | 5 + plugins/inputs/all/github.go | 5 + plugins/inputs/all/gnmi.go | 5 + plugins/inputs/all/google_cloud_storage.go | 5 + plugins/inputs/all/graylog.go | 5 + plugins/inputs/all/haproxy.go | 5 + plugins/inputs/all/hddtemp.go | 5 + plugins/inputs/all/http.go | 5 + plugins/inputs/all/http_listener_v2.go | 5 + plugins/inputs/all/http_response.go | 5 + plugins/inputs/all/huebridge.go | 5 + plugins/inputs/all/hugepages.go | 5 + plugins/inputs/all/icinga2.go | 5 + plugins/inputs/all/infiniband.go | 5 + plugins/inputs/all/influxdb.go | 5 + plugins/inputs/all/influxdb_listener.go | 5 + plugins/inputs/all/influxdb_v2_listener.go | 5 + plugins/inputs/all/intel_baseband.go | 5 + plugins/inputs/all/intel_dlb.go | 5 + plugins/inputs/all/intel_pmt.go | 5 + plugins/inputs/all/intel_pmu.go | 5 + plugins/inputs/all/intel_powerstat.go | 5 + plugins/inputs/all/intel_rdt.go | 5 + plugins/inputs/all/internal.go | 5 + plugins/inputs/all/internet_speed.go | 5 + plugins/inputs/all/interrupts.go | 5 + plugins/inputs/all/ipmi_sensor.go | 5 + plugins/inputs/all/ipset.go | 5 + plugins/inputs/all/iptables.go | 5 + plugins/inputs/all/ipvs.go | 5 + plugins/inputs/all/jenkins.go | 5 + plugins/inputs/all/jolokia2_agent.go | 5 + plugins/inputs/all/jolokia2_proxy.go | 5 + .../inputs/all/jti_openconfig_telemetry.go | 5 + plugins/inputs/all/kafka_consumer.go | 5 + plugins/inputs/all/kapacitor.go | 5 + plugins/inputs/all/kernel.go | 5 + plugins/inputs/all/kernel_vmstat.go | 5 + plugins/inputs/all/kibana.go | 5 + plugins/inputs/all/kinesis_consumer.go | 5 + plugins/inputs/all/knx_listener.go | 5 + plugins/inputs/all/kube_inventory.go | 5 + plugins/inputs/all/kubernetes.go | 5 + plugins/inputs/all/lanz.go | 5 + plugins/inputs/all/ldap.go | 5 + plugins/inputs/all/leofs.go | 5 + plugins/inputs/all/libvirt.go | 5 + plugins/inputs/all/linux_cpu.go | 5 + plugins/inputs/all/linux_sysctl_fs.go | 5 + plugins/inputs/all/logparser.go | 5 + plugins/inputs/all/logstash.go | 5 + plugins/inputs/all/lustre2.go | 5 + plugins/inputs/all/lvm.go | 5 + plugins/inputs/all/mailchimp.go | 5 + plugins/inputs/all/marklogic.go | 5 + plugins/inputs/all/mcrouter.go | 5 + plugins/inputs/all/mdstat.go | 5 + plugins/inputs/all/mem.go | 5 + plugins/inputs/all/memcached.go | 5 + plugins/inputs/all/mesos.go | 5 + plugins/inputs/all/minecraft.go | 5 + plugins/inputs/all/mock.go | 5 + plugins/inputs/all/modbus.go | 5 + plugins/inputs/all/mongodb.go | 5 + plugins/inputs/all/monit.go | 5 + plugins/inputs/all/mqtt_consumer.go | 5 + plugins/inputs/all/multifile.go | 5 + plugins/inputs/all/mysql.go | 5 + plugins/inputs/all/nats.go | 5 + plugins/inputs/all/nats_consumer.go | 5 + plugins/inputs/all/neoom_beaam.go | 5 + plugins/inputs/all/neptune_apex.go | 5 + plugins/inputs/all/net.go | 5 + plugins/inputs/all/net_response.go | 5 + plugins/inputs/all/netflow.go | 5 + plugins/inputs/all/netstat.go | 5 + plugins/inputs/all/nfsclient.go | 5 + plugins/inputs/all/nginx.go | 5 + plugins/inputs/all/nginx_plus.go | 5 + plugins/inputs/all/nginx_plus_api.go | 5 + plugins/inputs/all/nginx_sts.go | 5 + plugins/inputs/all/nginx_upstream_check.go | 5 + plugins/inputs/all/nginx_vts.go | 5 + plugins/inputs/all/nomad.go | 5 + plugins/inputs/all/nsd.go | 5 + plugins/inputs/all/nsdp.go | 5 + plugins/inputs/all/nsq.go | 5 + plugins/inputs/all/nsq_consumer.go | 5 + plugins/inputs/all/nstat.go | 5 + plugins/inputs/all/ntpq.go | 5 + plugins/inputs/all/nvidia_smi.go | 5 + plugins/inputs/all/opcua.go | 5 + plugins/inputs/all/opcua_listener.go | 5 + plugins/inputs/all/openldap.go | 5 + plugins/inputs/all/openntpd.go | 5 + plugins/inputs/all/opensearch_query.go | 5 + plugins/inputs/all/opensmtpd.go | 5 + plugins/inputs/all/openstack.go | 5 + plugins/inputs/all/opentelemetry.go | 5 + plugins/inputs/all/openweathermap.go | 5 + plugins/inputs/all/p4runtime.go | 5 + plugins/inputs/all/passenger.go | 5 + plugins/inputs/all/pf.go | 5 + plugins/inputs/all/pgbouncer.go | 5 + plugins/inputs/all/phpfpm.go | 5 + plugins/inputs/all/ping.go | 5 + plugins/inputs/all/postfix.go | 5 + plugins/inputs/all/postgresql.go | 5 + plugins/inputs/all/postgresql_extensible.go | 5 + plugins/inputs/all/powerdns.go | 5 + plugins/inputs/all/powerdns_recursor.go | 5 + plugins/inputs/all/processes.go | 5 + plugins/inputs/all/procstat.go | 5 + plugins/inputs/all/prometheus.go | 5 + plugins/inputs/all/proxmox.go | 5 + plugins/inputs/all/puppetagent.go | 5 + plugins/inputs/all/rabbitmq.go | 5 + plugins/inputs/all/radius.go | 5 + plugins/inputs/all/raindrops.go | 5 + plugins/inputs/all/ras.go | 5 + plugins/inputs/all/ravendb.go | 5 + plugins/inputs/all/redfish.go | 5 + plugins/inputs/all/redis.go | 5 + plugins/inputs/all/redis_sentinel.go | 5 + plugins/inputs/all/rethinkdb.go | 5 + plugins/inputs/all/riak.go | 5 + plugins/inputs/all/riemann_listener.go | 5 + plugins/inputs/all/s7comm.go | 5 + plugins/inputs/all/salesforce.go | 5 + plugins/inputs/all/sensors.go | 5 + plugins/inputs/all/sflow.go | 5 + plugins/inputs/all/slab.go | 5 + plugins/inputs/all/slurm.go | 5 + plugins/inputs/all/smart.go | 5 + plugins/inputs/all/smartctl.go | 5 + plugins/inputs/all/snmp.go | 5 + plugins/inputs/all/snmp_trap.go | 5 + plugins/inputs/all/socket_listener.go | 5 + plugins/inputs/all/socketstat.go | 5 + plugins/inputs/all/solr.go | 5 + plugins/inputs/all/sql.go | 5 + plugins/inputs/all/sqlserver.go | 5 + plugins/inputs/all/stackdriver.go | 5 + plugins/inputs/all/statsd.go | 5 + plugins/inputs/all/supervisor.go | 5 + plugins/inputs/all/suricata.go | 5 + plugins/inputs/all/swap.go | 5 + plugins/inputs/all/synproxy.go | 5 + plugins/inputs/all/syslog.go | 5 + plugins/inputs/all/sysstat.go | 5 + plugins/inputs/all/system.go | 5 + plugins/inputs/all/systemd_units.go | 5 + plugins/inputs/all/tacacs.go | 5 + plugins/inputs/all/tail.go | 5 + plugins/inputs/all/teamspeak.go | 5 + plugins/inputs/all/temp.go | 5 + plugins/inputs/all/tengine.go | 5 + plugins/inputs/all/tomcat.go | 5 + plugins/inputs/all/trig.go | 5 + plugins/inputs/all/twemproxy.go | 5 + plugins/inputs/all/unbound.go | 5 + plugins/inputs/all/upsd.go | 5 + plugins/inputs/all/uwsgi.go | 5 + plugins/inputs/all/varnish.go | 5 + plugins/inputs/all/vault.go | 5 + plugins/inputs/all/vsphere.go | 5 + plugins/inputs/all/webhooks.go | 5 + plugins/inputs/all/win_eventlog.go | 5 + plugins/inputs/all/win_perf_counters.go | 5 + plugins/inputs/all/win_services.go | 5 + plugins/inputs/all/win_wmi.go | 5 + plugins/inputs/all/wireguard.go | 5 + plugins/inputs/all/wireless.go | 5 + plugins/inputs/all/x509_cert.go | 5 + plugins/inputs/all/xtremio.go | 5 + plugins/inputs/all/zfs.go | 5 + plugins/inputs/all/zipkin.go | 5 + plugins/inputs/all/zookeeper.go | 5 + plugins/inputs/amd_rocm_smi/README.md | 110 + plugins/inputs/amd_rocm_smi/amd_rocm_smi.go | 305 + .../inputs/amd_rocm_smi/amd_rocm_smi_test.go | 610 + plugins/inputs/amd_rocm_smi/sample.conf | 7 + .../amd_rocm_smi/testdata/mi100_rocm571.json | 532 + .../amd_rocm_smi/testdata/mi100_rocm602.json | 311 + .../testdata/rx6700xt_rocm430.json | 69 + .../testdata/rx6700xt_rocm571.json | 66 + .../testdata/rx6700xt_rocm602.json | 68 + .../testdata/rx6700xt_rocm612.json | 75 + .../amd_rocm_smi/testdata/vega-10-XT.json | 77 + .../testdata/vega-20-WKS-GL-XE.json | 165 + plugins/inputs/amqp_consumer/README.md | 193 + plugins/inputs/amqp_consumer/amqp_consumer.go | 504 + .../amqp_consumer/amqp_consumer_test.go | 444 + plugins/inputs/amqp_consumer/sample.conf | 95 + plugins/inputs/apache/README.md | 106 + plugins/inputs/apache/apache.go | 208 + plugins/inputs/apache/apache_test.go | 79 + plugins/inputs/apache/sample.conf | 20 + plugins/inputs/apcupsd/README.md | 69 + plugins/inputs/apcupsd/apcupsd.go | 117 + plugins/inputs/apcupsd/apcupsd_test.go | 252 + plugins/inputs/apcupsd/sample.conf | 8 + plugins/inputs/aurora/README.md | 82 + plugins/inputs/aurora/aurora.go | 258 + plugins/inputs/aurora/aurora_test.go | 278 + plugins/inputs/aurora/sample.conf | 24 + plugins/inputs/azure_monitor/README.md | 178 + plugins/inputs/azure_monitor/azure_monitor.go | 195 + .../azure_monitor/azure_monitor_test.go | 1084 ++ plugins/inputs/azure_monitor/sample.conf | 77 + .../azure_metric_definitions_responses.json | 114 + .../json/azure_metrics_responses.json | 243 + .../json/azure_resources_response.json | 14 + .../testdata/toml/gather_success.toml | 34 + .../gather_success_cloud_option_china.toml | 10 + ...ather_success_cloud_option_government.toml | 10 + .../gather_success_cloud_option_public.toml | 10 + .../testdata/toml/init_all_target_types.toml | 90 + .../testdata/toml/init_bad_credentials.toml | 9 + .../testdata/toml/init_no_client_id.toml | 8 + .../testdata/toml/init_no_client_secret.toml | 8 + .../toml/init_no_subscription_id.toml | 8 + .../testdata/toml/init_no_targets.toml | 4 + .../testdata/toml/init_no_tenant_id.toml | 8 + ...source_group_target_no_resource_found.toml | 12 + ...group_target_with_invalid_aggregation.toml | 12 + ...urce_group_target_with_invalid_metric.toml | 12 + ...up_target_with_invalid_resource_group.toml | 12 + ...oup_target_with_invalid_resource_type.toml | 12 + ...t_with_resource_without_resource_type.toml | 11 + ...e_group_target_without_resource_group.toml | 11 + ...source_group_target_without_resources.toml | 7 + .../init_resource_group_targets_only.toml | 40 + ...ource_target_with_invalid_aggregation.toml | 9 + ...t_resource_target_with_invalid_metric.toml | 9 + ...ource_target_with_invalid_resource_id.toml | 9 + ...t_resource_target_without_resource_id.toml | 8 + .../toml/init_resource_targets_only.toml | 29 + ...subscription_target_no_resource_found.toml | 9 + ...ption_target_with_invalid_aggregation.toml | 9 + ...bscription_target_with_invalid_metric.toml | 9 + ...ion_target_with_invalid_resource_type.toml | 9 + ...cription_target_without_resource_type.toml | 8 + .../toml/init_subscription_targets_only.toml | 29 + plugins/inputs/azure_storage_queue/README.md | 51 + .../azure_storage_queue.go | 123 + .../azure_storage_queue_test.go | 150 + .../inputs/azure_storage_queue/sample.conf | 8 + plugins/inputs/bcache/README.md | 65 + plugins/inputs/bcache/bcache.go | 145 + plugins/inputs/bcache/bcache_notlinux.go | 33 + plugins/inputs/bcache/bcache_test.go | 111 + plugins/inputs/bcache/sample.conf | 11 + plugins/inputs/beanstalkd/README.md | 121 + plugins/inputs/beanstalkd/beanstalkd.go | 266 + plugins/inputs/beanstalkd/beanstalkd_test.go | 351 + plugins/inputs/beanstalkd/sample.conf | 8 + plugins/inputs/beat/README.md | 160 + plugins/inputs/beat/beat.go | 200 + plugins/inputs/beat/beat6_info.json | 7 + plugins/inputs/beat/beat6_stats.json | 137 + plugins/inputs/beat/beat_test.go | 237 + plugins/inputs/beat/sample.conf | 33 + plugins/inputs/bind/README.md | 157 + plugins/inputs/bind/bind.go | 89 + plugins/inputs/bind/bind_test.go | 1886 +++ plugins/inputs/bind/json_stats.go | 187 + plugins/inputs/bind/sample.conf | 15 + plugins/inputs/bind/testdata/json/v1/mem | 133 + plugins/inputs/bind/testdata/json/v1/net | 241 + plugins/inputs/bind/testdata/json/v1/server | 172 + plugins/inputs/bind/testdata/xml/v2 | 926 ++ plugins/inputs/bind/testdata/xml/v3/mem | 142 + plugins/inputs/bind/testdata/xml/v3/net | 156 + plugins/inputs/bind/testdata/xml/v3/server | 328 + plugins/inputs/bind/xml_stats_v2.go | 171 + plugins/inputs/bind/xml_stats_v3.go | 204 + plugins/inputs/bond/README.md | 104 + plugins/inputs/bond/bond.go | 310 + plugins/inputs/bond/bond_test.go | 193 + plugins/inputs/bond/sample.conf | 18 + plugins/inputs/burrow/README.md | 121 + plugins/inputs/burrow/burrow.go | 457 + plugins/inputs/burrow/burrow_test.go | 288 + plugins/inputs/burrow/sample.conf | 41 + plugins/inputs/burrow/testdata/error.json | 11 + plugins/inputs/burrow/testdata/v3_kafka.json | 11 + .../v3_kafka_clustername1_consumer.json | 11 + ...afka_clustername1_consumer_group1_lag.json | 90 + .../testdata/v3_kafka_clustername1_topic.json | 11 + .../v3_kafka_clustername1_topic_topicA.json | 13 + plugins/inputs/ceph/README.md | 477 + plugins/inputs/ceph/ceph.go | 765 + plugins/inputs/ceph/ceph_test.go | 2506 +++ plugins/inputs/ceph/sample.conf | 43 + plugins/inputs/cgroup/README.md | 75 + plugins/inputs/cgroup/cgroup.go | 33 + plugins/inputs/cgroup/cgroup_linux.go | 305 + plugins/inputs/cgroup/cgroup_notlinux.go | 11 + plugins/inputs/cgroup/cgroup_test.go | 445 + plugins/inputs/cgroup/cgroupv2_test.go | 328 + plugins/inputs/cgroup/sample.conf | 15 + .../backslash/machine-qemu-1-ubuntu/cpu.stat | 4 + .../cgroup/testdata/blkio/blkio.io_serviced | 1 + .../testdata/blkio/blkio.throttle.io_serviced | 131 + .../cgroup/testdata/broken/malformed.file | 1 + .../testdata/broken/memory.limit_in_bytes | 1 + .../cgroup/testdata/cpu/cpu.cfs_quota_us | 1 + plugins/inputs/cgroup/testdata/cpu/cpu.stat | 4 + .../cgroup/testdata/cpu/cpuacct.usage_percpu | 1 + .../group_1/group_1_1/memory.limit_in_bytes | 1 + .../memory/group_1/group_1_1/memory.stat | 5 + .../group_1/group_1_2/memory.limit_in_bytes | 1 + .../memory/group_1/group_1_2/memory.stat | 5 + .../memory/group_1/memory.kmem.limit_in_bytes | 1 + .../group_1/memory.kmem.max_usage_in_bytes | 1 + .../memory/group_1/memory.limit_in_bytes | 1 + .../testdata/memory/group_1/memory.stat | 5 + .../group_2/group_1_1/memory.limit_in_bytes | 1 + .../memory/group_2/group_1_1/memory.stat | 5 + .../memory/group_2/memory.limit_in_bytes | 1 + .../testdata/memory/group_2/memory.stat | 5 + .../cgroup/testdata/memory/memory.empty | 0 .../memory/memory.kmem.limit_in_bytes | 1 + .../testdata/memory/memory.limit_in_bytes | 1 + .../testdata/memory/memory.max_usage_in_bytes | 3 + .../cgroup/testdata/memory/memory.numa_stat | 8 + .../inputs/cgroup/testdata/memory/memory.stat | 5 + .../testdata/memory/memory.usage_in_bytes | 1 + .../testdata/memory/memory.use_hierarchy | 1 + .../cgroup/testdata/memory/notify_on_release | 1 + plugins/inputs/cgroup/testdata/v2/cpu.idle | 1 + plugins/inputs/cgroup/testdata/v2/cpu.max | 1 + .../inputs/cgroup/testdata/v2/cpu.max.burst | 1 + .../inputs/cgroup/testdata/v2/cpu.pressure | 2 + plugins/inputs/cgroup/testdata/v2/cpu.stat | 9 + plugins/inputs/cgroup/testdata/v2/cpu.weight | 1 + .../inputs/cgroup/testdata/v2/cpu.weight.nice | 1 + plugins/inputs/cgroup/testdata/v2/cpuset.cpus | 1 + .../cgroup/testdata/v2/cpuset.cpus.effective | 1 + .../cgroup/testdata/v2/cpuset.cpus.partition | 1 + plugins/inputs/cgroup/testdata/v2/cpuset.mems | 1 + .../cgroup/testdata/v2/cpuset.mems.effective | 1 + .../cgroup/testdata/v2/hugetlb.1GB.current | 1 + .../cgroup/testdata/v2/hugetlb.1GB.events | 1 + .../testdata/v2/hugetlb.1GB.events.local | 1 + .../inputs/cgroup/testdata/v2/hugetlb.1GB.max | 1 + .../cgroup/testdata/v2/hugetlb.1GB.numa_stat | 1 + .../testdata/v2/hugetlb.1GB.rsvd.current | 1 + .../cgroup/testdata/v2/hugetlb.1GB.rsvd.max | 1 + .../cgroup/testdata/v2/hugetlb.2MB.current | 1 + .../cgroup/testdata/v2/hugetlb.2MB.events | 1 + .../testdata/v2/hugetlb.2MB.events.local | 1 + .../inputs/cgroup/testdata/v2/hugetlb.2MB.max | 1 + .../cgroup/testdata/v2/hugetlb.2MB.numa_stat | 1 + .../testdata/v2/hugetlb.2MB.rsvd.current | 1 + .../cgroup/testdata/v2/hugetlb.2MB.rsvd.max | 1 + .../inputs/cgroup/testdata/v2/io.bfq.weight | 1 + plugins/inputs/cgroup/testdata/v2/io.max | 0 plugins/inputs/cgroup/testdata/v2/io.pressure | 2 + plugins/inputs/cgroup/testdata/v2/io.stat | 1 + .../inputs/cgroup/testdata/v2/memory.current | 1 + .../inputs/cgroup/testdata/v2/memory.events | 6 + .../cgroup/testdata/v2/memory.events.local | 6 + plugins/inputs/cgroup/testdata/v2/memory.high | 1 + plugins/inputs/cgroup/testdata/v2/memory.low | 1 + plugins/inputs/cgroup/testdata/v2/memory.max | 1 + plugins/inputs/cgroup/testdata/v2/memory.min | 1 + .../cgroup/testdata/v2/memory.numa_stat | 27 + .../cgroup/testdata/v2/memory.oom.group | 1 + plugins/inputs/cgroup/testdata/v2/memory.peak | 1 + .../inputs/cgroup/testdata/v2/memory.pressure | 2 + .../inputs/cgroup/testdata/v2/memory.reclaim | 0 plugins/inputs/cgroup/testdata/v2/memory.stat | 47 + .../cgroup/testdata/v2/memory.swap.current | 1 + .../cgroup/testdata/v2/memory.swap.events | 3 + .../cgroup/testdata/v2/memory.swap.high | 1 + .../inputs/cgroup/testdata/v2/memory.swap.max | 1 + .../inputs/cgroup/testdata/v2/pids.current | 1 + plugins/inputs/cgroup/testdata/v2/pids.events | 1 + plugins/inputs/cgroup/testdata/v2/pids.max | 1 + plugins/inputs/cgroup/testdata/v2/pids.peak | 1 + plugins/inputs/chrony/README.md | 89 + plugins/inputs/chrony/chrony.go | 531 + plugins/inputs/chrony/chrony_test.go | 1126 ++ plugins/inputs/chrony/sample.conf | 29 + plugins/inputs/chrony/testdata/chrony.conf | 11 + plugins/inputs/chrony/testdata/start.sh | 17 + plugins/inputs/cisco_telemetry_mdt/README.md | 166 + .../cisco_telemetry_mdt.go | 809 + .../cisco_telemetry_mdt_test.go | 1381 ++ .../cisco_telemetry_util.go | 876 + .../inputs/cisco_telemetry_mdt/sample.conf | 59 + .../cisco_telemetry_mdt/testdata/microburst | Bin 0 -> 5804 bytes plugins/inputs/clickhouse/README.md | 240 + plugins/inputs/clickhouse/clickhouse.go | 640 + plugins/inputs/clickhouse/clickhouse_test.go | 736 + plugins/inputs/clickhouse/dev/dhparam.pem | 13 + .../inputs/clickhouse/dev/docker-compose.yml | 30 + plugins/inputs/clickhouse/dev/init_schema.sql | 6 + plugins/inputs/clickhouse/dev/mysql_port.xml | 3 + plugins/inputs/clickhouse/dev/part_log.xml | 12 + plugins/inputs/clickhouse/dev/telegraf.conf | 12 + .../inputs/clickhouse/dev/telegraf_ssl.conf | 16 + .../inputs/clickhouse/dev/test_dictionary.xml | 62 + plugins/inputs/clickhouse/dev/text_log.xml | 12 + .../inputs/clickhouse/dev/tls_settings.xml | 4 + plugins/inputs/clickhouse/dev/zookeeper.xml | 19 + plugins/inputs/clickhouse/sample.conf | 69 + plugins/inputs/cloud_pubsub/README.md | 137 + plugins/inputs/cloud_pubsub/cloud_pubsub.go | 357 + .../inputs/cloud_pubsub/cloud_pubsub_test.go | 300 + plugins/inputs/cloud_pubsub/sample.conf | 85 + .../inputs/cloud_pubsub/subscription_gcp.go | 85 + .../cloud_pubsub/subscription_stub_test.go | 108 + plugins/inputs/cloud_pubsub_push/README.md | 103 + .../cloud_pubsub_push/cloud_pubsub_push.go | 286 + .../cloud_pubsub_push_test.go | 264 + plugins/inputs/cloud_pubsub_push/sample.conf | 51 + plugins/inputs/cloudwatch/README.md | 344 + plugins/inputs/cloudwatch/cloudwatch.go | 490 + plugins/inputs/cloudwatch/cloudwatch_test.go | 700 + plugins/inputs/cloudwatch/sample.conf | 120 + plugins/inputs/cloudwatch/utils.go | 48 + .../cloudwatch_metric_streams/README.md | 169 + .../cloudwatch_metric_streams.go | 424 + .../cloudwatch_metric_streams_test.go | 382 + .../cloudwatch_metric_streams/sample.conf | 32 + .../testdata/record.json | 9 + .../testdata/records.gz | Bin 0 -> 38037 bytes .../testdata/records.json | 18 + plugins/inputs/conntrack/README.md | 109 + plugins/inputs/conntrack/conntrack.go | 164 + .../inputs/conntrack/conntrack_notlinux.go | 33 + plugins/inputs/conntrack/conntrack_test.go | 342 + plugins/inputs/conntrack/sample.conf | 21 + plugins/inputs/consul/README.md | 109 + plugins/inputs/consul/consul.go | 151 + plugins/inputs/consul/consul_test.go | 138 + plugins/inputs/consul/sample.conf | 37 + plugins/inputs/consul_agent/README.md | 50 + plugins/inputs/consul_agent/consul_agent.go | 175 + .../inputs/consul_agent/consul_agent_test.go | 106 + plugins/inputs/consul_agent/consul_structs.go | 32 + plugins/inputs/consul_agent/sample.conf | 19 + .../testdata/response_key_metrics.json | 42 + plugins/inputs/couchbase/README.md | 337 + plugins/inputs/couchbase/couchbase.go | 483 + plugins/inputs/couchbase/couchbase_data.go | 228 + plugins/inputs/couchbase/couchbase_test.go | 274 + plugins/inputs/couchbase/sample.conf | 35 + .../couchbase/testdata/bucket_response.json | 4464 ++++++ .../testdata/bucket_stats_response.json | 13346 ++++++++++++++++ .../bucket_stats_response_with_missing.json | 78 + .../testdata/node_bucket_stats_response.json | 10655 ++++++++++++ .../testdata/pools_default_response.json | 404 + .../couchbase/testdata/pools_response.json | 8 + .../testdata/settings_autofailover.json | 11 + plugins/inputs/couchdb/README.md | 97 + plugins/inputs/couchdb/couchdb.go | 290 + plugins/inputs/couchdb/couchdb_test.go | 326 + plugins/inputs/couchdb/dev/telegraf.conf | 9 + plugins/inputs/couchdb/sample.conf | 9 + plugins/inputs/cpu/README.md | 86 + plugins/inputs/cpu/cpu.go | 167 + plugins/inputs/cpu/cpu_test.go | 249 + plugins/inputs/cpu/sample.conf | 13 + plugins/inputs/csgo/README.md | 58 + plugins/inputs/csgo/csgo.go | 151 + plugins/inputs/csgo/csgo_test.go | 82 + plugins/inputs/csgo/sample.conf | 10 + plugins/inputs/ctrlx_datalayer/README.md | 390 + .../inputs/ctrlx_datalayer/ctrlx_datalayer.go | 371 + .../ctrlx_datalayer_payload_types.go | 19 + .../ctrlx_datalayer_subscription.go | 188 + .../ctrlx_datalayer_subscription_test.go | 249 + .../ctrlx_datalayer/ctrlx_datalayer_test.go | 293 + plugins/inputs/ctrlx_datalayer/sample.conf | 110 + plugins/inputs/dcos/README.md | 241 + plugins/inputs/dcos/client.go | 328 + plugins/inputs/dcos/client_test.go | 223 + plugins/inputs/dcos/creds.go | 72 + plugins/inputs/dcos/dcos.go | 387 + plugins/inputs/dcos/dcos_test.go | 436 + plugins/inputs/dcos/sample.conf | 42 + plugins/inputs/deprecations.go | 77 + plugins/inputs/directory_monitor/README.md | 106 + .../directory_monitor/directory_monitor.go | 479 + .../directory_monitor_test.go | 682 + plugins/inputs/directory_monitor/sample.conf | 50 + plugins/inputs/disk/README.md | 103 + plugins/inputs/disk/disk.go | 117 + plugins/inputs/disk/disk_test.go | 661 + plugins/inputs/disk/sample.conf | 13 + .../testdata/issue_10297/proc/1/mountinfo | 2 + .../issue_10297/sys/block/sda1/dm/name | 1 + .../issue_10297/sys/block/sdb/dm/name | 1 + .../disk/testdata/success/proc/1/mountinfo | 2 + plugins/inputs/diskio/README.md | 174 + plugins/inputs/diskio/diskio.go | 225 + plugins/inputs/diskio/diskio_linux.go | 192 + plugins/inputs/diskio/diskio_linux_test.go | 84 + plugins/inputs/diskio/diskio_other.go | 17 + plugins/inputs/diskio/diskio_test.go | 192 + plugins/inputs/diskio/sample.conf | 25 + plugins/inputs/diskio/testdata/udev.txt | 4 + plugins/inputs/diskio/testdata/uevent | 5 + plugins/inputs/disque/README.md | 55 + plugins/inputs/disque/disque.go | 204 + plugins/inputs/disque/disque_test.go | 226 + plugins/inputs/disque/sample.conf | 7 + plugins/inputs/dmcache/README.md | 64 + plugins/inputs/dmcache/dmcache.go | 31 + plugins/inputs/dmcache/dmcache_linux.go | 189 + plugins/inputs/dmcache/dmcache_linux_test.go | 174 + plugins/inputs/dmcache/dmcache_notlinux.go | 15 + plugins/inputs/dmcache/sample.conf | 5 + plugins/inputs/dns_query/README.md | 93 + plugins/inputs/dns_query/dns_query.go | 254 + plugins/inputs/dns_query/dns_query_test.go | 284 + plugins/inputs/dns_query/sample.conf | 26 + plugins/inputs/docker/README.md | 414 + plugins/inputs/docker/client.go | 120 + plugins/inputs/docker/docker.go | 1085 ++ plugins/inputs/docker/docker_test.go | 1621 ++ plugins/inputs/docker/docker_testdata.go | 586 + plugins/inputs/docker/errors.go | 11 + plugins/inputs/docker/sample.conf | 64 + plugins/inputs/docker_log/README.md | 114 + plugins/inputs/docker_log/client.go | 70 + plugins/inputs/docker_log/docker_log.go | 498 + plugins/inputs/docker_log/docker_log_test.go | 178 + plugins/inputs/docker_log/sample.conf | 39 + plugins/inputs/dovecot/README.md | 92 + plugins/inputs/dovecot/dovecot.go | 197 + plugins/inputs/dovecot/dovecot_test.go | 228 + plugins/inputs/dovecot/sample.conf | 18 + plugins/inputs/dovecot/testdata/dovecot.conf | 49 + plugins/inputs/dpdk/README.md | 305 + plugins/inputs/dpdk/dpdk.go | 292 + plugins/inputs/dpdk/dpdk_cmds.go | 55 + plugins/inputs/dpdk/dpdk_cmds_test.go | 131 + plugins/inputs/dpdk/dpdk_connector.go | 243 + plugins/inputs/dpdk/dpdk_connector_test.go | 240 + plugins/inputs/dpdk/dpdk_notlinux.go | 33 + plugins/inputs/dpdk/dpdk_test.go | 918 ++ plugins/inputs/dpdk/dpdk_utils.go | 136 + plugins/inputs/dpdk/dpdk_utils_test.go | 129 + plugins/inputs/dpdk/mocks/conn.go | 197 + plugins/inputs/dpdk/sample.conf | 58 + plugins/inputs/ecs/README.md | 255 + plugins/inputs/ecs/cgroupv2_test.go | 61 + plugins/inputs/ecs/client.go | 173 + plugins/inputs/ecs/client_test.go | 320 + plugins/inputs/ecs/ecs.go | 244 + plugins/inputs/ecs/ecs_test.go | 840 + plugins/inputs/ecs/sample.conf | 26 + plugins/inputs/ecs/stats.go | 295 + plugins/inputs/ecs/stats_test.go | 226 + .../inputs/ecs/testdata/cgroupv2/meta.json | 48 + plugins/inputs/ecs/testdata/cgroupv2/meta.out | 1 + .../inputs/ecs/testdata/cgroupv2/stats.json | 101 + .../inputs/ecs/testdata/cgroupv2/stats.out | 5 + plugins/inputs/ecs/testdata/metadata.golden | 78 + plugins/inputs/ecs/testdata/stats.golden | 663 + plugins/inputs/ecs/types.go | 78 + plugins/inputs/ecs/types_test.go | 47 + plugins/inputs/elasticsearch/README.md | 888 + plugins/inputs/elasticsearch/elasticsearch.go | 787 + .../elasticsearch/elasticsearch_test.go | 373 + plugins/inputs/elasticsearch/sample.conf | 73 + plugins/inputs/elasticsearch/testdata_test.go | 5916 +++++++ plugins/inputs/elasticsearch_query/README.md | 207 + .../elasticsearch_query/aggregation_parser.go | 154 + .../elasticsearch_query/aggregation_query.go | 217 + .../elasticsearch_query.go | 248 + .../elasticsearch_query_test.go | 760 + .../inputs/elasticsearch_query/sample.conf | 79 + .../elasticsearch_query/testdata/nginx_logs | 500 + plugins/inputs/ethtool/README.md | 110 + plugins/inputs/ethtool/ethtool.go | 15 + plugins/inputs/ethtool/ethtool_linux.go | 366 + plugins/inputs/ethtool/ethtool_notlinux.go | 45 + plugins/inputs/ethtool/ethtool_test.go | 987 ++ plugins/inputs/ethtool/namespace_linux.go | 181 + plugins/inputs/ethtool/sample.conf | 40 + plugins/inputs/eventhub_consumer/README.md | 150 + .../eventhub_consumer/eventhub_consumer.go | 346 + plugins/inputs/eventhub_consumer/sample.conf | 93 + plugins/inputs/example/README.md | 93 + plugins/inputs/example/example.go | 139 + plugins/inputs/example/example_test.go | 439 + plugins/inputs/example/sample.conf | 3 + plugins/inputs/exec/README.md | 100 + plugins/inputs/exec/dev/telegraf.conf | 26 + plugins/inputs/exec/exec.go | 192 + plugins/inputs/exec/exec_test.go | 512 + plugins/inputs/exec/run_notwindows.go | 41 + plugins/inputs/exec/run_windows.go | 61 + plugins/inputs/exec/sample.conf | 30 + plugins/inputs/execd/README.md | 100 + plugins/inputs/execd/examples/count.go | 24 + plugins/inputs/execd/examples/count.py | 12 + plugins/inputs/execd/examples/count.rb | 21 + plugins/inputs/execd/examples/count.sh | 12 + plugins/inputs/execd/execd.go | 186 + plugins/inputs/execd/execd_posix.go | 46 + plugins/inputs/execd/execd_test.go | 459 + plugins/inputs/execd/execd_windows.go | 38 + plugins/inputs/execd/sample.conf | 38 + plugins/inputs/execd/shim/README.md | 3 + plugins/inputs/execd/shim/example/cmd/main.go | 3 + .../inputs/execd/shim/example/cmd/plugin.conf | 2 + plugins/inputs/execd/shim/goshim.go | 330 + plugins/inputs/execd/shim/goshim_posix.go | 20 + plugins/inputs/execd/shim/goshim_windows.go | 20 + plugins/inputs/execd/shim/input.go | 23 + plugins/inputs/execd/shim/shim_posix_test.go | 62 + plugins/inputs/execd/shim/shim_test.go | 169 + .../inputs/execd/shim/testdata/plugin.conf | 4 + plugins/inputs/fail2ban/README.md | 88 + plugins/inputs/fail2ban/fail2ban.go | 146 + plugins/inputs/fail2ban/fail2ban_test.go | 133 + plugins/inputs/fail2ban/sample.conf | 7 + plugins/inputs/fibaro/README.md | 78 + plugins/inputs/fibaro/fibaro.go | 123 + plugins/inputs/fibaro/fibaro_test.go | 306 + plugins/inputs/fibaro/hc2/parser.go | 96 + plugins/inputs/fibaro/hc2/types.go | 37 + plugins/inputs/fibaro/hc3/parser.go | 81 + plugins/inputs/fibaro/hc3/types.go | 37 + plugins/inputs/fibaro/sample.conf | 17 + .../inputs/fibaro/testdata/device_hc2.json | 66 + .../inputs/fibaro/testdata/device_hc3.json | 65 + plugins/inputs/fibaro/testdata/rooms.json | 30 + plugins/inputs/fibaro/testdata/sections.json | 17 + plugins/inputs/file/README.md | 69 + plugins/inputs/file/dev/docker-compose.yml | 13 + plugins/inputs/file/dev/telegraf.conf | 7 + plugins/inputs/file/dev/testfiles/grok_a.log | 2 + plugins/inputs/file/dev/testfiles/json_a.log | 14 + plugins/inputs/file/file.go | 129 + plugins/inputs/file/file_test.go | 466 + plugins/inputs/file/sample.conf | 32 + .../file/testdata/csv_behavior_input.csv | 3 + plugins/inputs/file/testdata/mtr-utf-16be.csv | Bin 0 -> 884 bytes plugins/inputs/file/testdata/mtr-utf-16le.csv | Bin 0 -> 884 bytes plugins/inputs/file/testdata/mtr-utf-8.csv | 5 + plugins/inputs/filecount/README.md | 71 + plugins/inputs/filecount/filecount.go | 318 + plugins/inputs/filecount/filecount_test.go | 249 + .../inputs/filecount/filesystem_helpers.go | 33 + .../filesystem_helpers_notwindows_test.go | 57 + .../filecount/filesystem_helpers_test.go | 93 + plugins/inputs/filecount/sample.conf | 32 + plugins/inputs/filecount/testdata/bar | 0 plugins/inputs/filecount/testdata/baz | 0 plugins/inputs/filecount/testdata/foo | 0 plugins/inputs/filecount/testdata/qux | 7 + .../filecount/testdata/subdir/nested2/qux | 7 + plugins/inputs/filecount/testdata/subdir/quux | 0 plugins/inputs/filecount/testdata/subdir/quuz | 0 plugins/inputs/filestat/README.md | 53 + plugins/inputs/filestat/filestat.go | 141 + plugins/inputs/filestat/filestat_test.go | 211 + plugins/inputs/filestat/sample.conf | 9 + plugins/inputs/filestat/testdata/log1.log | 0 plugins/inputs/filestat/testdata/log2.log | 0 plugins/inputs/filestat/testdata/test.conf | 5 + plugins/inputs/fireboard/README.md | 80 + plugins/inputs/fireboard/fireboard.go | 138 + plugins/inputs/fireboard/fireboard_test.go | 79 + plugins/inputs/fireboard/sample.conf | 10 + plugins/inputs/firehose/README.md | 122 + plugins/inputs/firehose/firehose.go | 239 + .../inputs/firehose/firehose_request_test.go | 375 + plugins/inputs/firehose/firehose_test.go | 1 + plugins/inputs/firehose/message.go | 125 + plugins/inputs/firehose/sample.conf | 42 + .../testcases/common-attributes/body.json | 5 + .../testcases/common-attributes/expected.out | 1 + .../testcases/common-attributes/headers.json | 5 + .../testcases/common-attributes/telegraf.conf | 4 + plugins/inputs/fluentd/README.md | 88 + plugins/inputs/fluentd/fluentd.go | 223 + plugins/inputs/fluentd/fluentd_test.go | 243 + plugins/inputs/fluentd/sample.conf | 14 + plugins/inputs/github/README.md | 100 + plugins/inputs/github/github.go | 229 + plugins/inputs/github/github_test.go | 140 + plugins/inputs/github/sample.conf | 24 + plugins/inputs/gnmi/README.md | 276 + .../GnmiJuniperTelemetryHeaderExtension.pb.go | 381 + plugins/inputs/gnmi/gnmi.go | 490 + plugins/inputs/gnmi/gnmi_test.go | 1229 ++ plugins/inputs/gnmi/handler.go | 351 + plugins/inputs/gnmi/path.go | 403 + plugins/inputs/gnmi/sample.conf | 158 + plugins/inputs/gnmi/sample.conf.in | 135 + plugins/inputs/gnmi/tag_store.go | 188 + .../canonical_field_names/expected.out | 1 + .../canonical_field_names/responses.json | 79 + .../canonical_field_names/telegraf.conf | 23 + .../canonical_field_names_trim/expected.out | 1 + .../canonical_field_names_trim/responses.json | 79 + .../canonical_field_names_trim/telegraf.conf | 24 + .../gnmi/testcases/issue_11011/expected.out | 1 + .../gnmi/testcases/issue_11011/responses.json | 116 + .../gnmi/testcases/issue_11011/telegraf.conf | 14 + .../gnmi/testcases/issue_11778/expected.out | 1 + .../gnmi/testcases/issue_11778/responses.json | 49 + .../gnmi/testcases/issue_11778/telegraf.conf | 15 + .../issue_11778_tag_only/expected.out | 1 + .../issue_11778_tag_only/responses.json | 49 + .../issue_11778_tag_only/telegraf.conf | 16 + .../gnmi/testcases/issue_12831/expected.out | 7 + .../gnmi/testcases/issue_12831/responses.json | 1101 ++ .../gnmi/testcases/issue_12831/telegraf.conf | 10 + .../gnmi/testcases/issue_12931/expected.out | 1 + .../gnmi/testcases/issue_12931/responses.json | 94 + .../gnmi/testcases/issue_12931/telegraf.conf | 10 + .../gnmi/testcases/issue_13052/expected.out | 119 + .../gnmi/testcases/issue_13052/responses.json | 2524 +++ .../gnmi/testcases/issue_13052/telegraf.conf | 13 + .../gnmi/testcases/issue_13512/expected.out | 1 + .../gnmi/testcases/issue_13512/responses.json | 79 + .../gnmi/testcases/issue_13512/telegraf.conf | 22 + .../gnmi/testcases/issue_14044/expected.out | 1 + .../gnmi/testcases/issue_14044/responses.json | 33 + .../gnmi/testcases/issue_14044/telegraf.conf | 13 + .../gnmi/testcases/issue_14063/expected.out | 1 + .../gnmi/testcases/issue_14063/responses.json | 445 + .../gnmi/testcases/issue_14063/telegraf.conf | 11 + .../gnmi/testcases/issue_14530/expected.out | 1 + .../gnmi/testcases/issue_14530/responses.json | 208 + .../gnmi/testcases/issue_14530/telegraf.conf | 14 + .../gnmi/testcases/issue_14833/expected.out | 2 + .../gnmi/testcases/issue_14833/responses.json | 51 + .../gnmi/testcases/issue_14833/telegraf.conf | 9 + .../gnmi/testcases/issue_14946/expected.out | 4 + .../gnmi/testcases/issue_14946/responses.json | 182 + .../gnmi/testcases/issue_14946/telegraf.conf | 15 + .../expected.out | 4 + .../responses.json | 182 + .../telegraf.conf | 15 + .../gnmi/testcases/issue_15046/expected.out | 5 + .../gnmi/testcases/issue_15046/models/LICENSE | 202 + .../testcases/issue_15046/models/README.md | 2 + .../models/openconfig-alarm-types.yang | 109 + .../models/openconfig-extensions.yang | 110 + .../models/openconfig-platform-psu.yang | 92 + .../models/openconfig-platform-types.yang | 80 + .../models/openconfig-platform.yang | 162 + .../issue_15046/models/openconfig-types.yang | 66 + .../gnmi/testcases/issue_15046/responses.json | 141 + .../gnmi/testcases/issue_15046/telegraf.conf | 18 + .../gnmi/testcases/issue_15546/expected.out | 1 + .../gnmi/testcases/issue_15546/responses.json | 70 + .../gnmi/testcases/issue_15546/telegraf.conf | 10 + .../gnmi/testcases/issue_16476/expected.out | 1 + .../gnmi/testcases/issue_16476/responses.json | 481 + .../gnmi/testcases/issue_16476/telegraf.conf | 10 + .../gnmi/testcases/issue_16515/expected.out | 11 + .../gnmi/testcases/issue_16515/responses.json | 2853 ++++ .../gnmi/testcases/issue_16515/telegraf.conf | 9 + .../testcases/tagging_name_based/expected.out | 5 + .../tagging_name_based/responses.json | 13 + .../tagging_name_based/telegraf.conf | 15 + .../tagging_name_based_old/expected.out | 5 + .../tagging_name_based_old/responses.json | 13 + .../tagging_name_based_old/telegraf.conf | 16 + .../tagging_subinterfaces/expected.out | 3 + .../tagging_subinterfaces/responses.json | 9 + .../tagging_subinterfaces/telegraf.conf | 16 + plugins/inputs/gnmi/update_fields.go | 166 + plugins/inputs/google_cloud_storage/README.md | 81 + .../google_cloud_storage.go | 281 + .../google_cloud_storage_test.go | 445 + .../inputs/google_cloud_storage/sample.conf | 24 + .../testdata/file_listing.json | 3 + .../testdata/first_file.json | 16 + .../testdata/first_file_listing.json | 19 + .../testdata/fourth_file.json | 16 + .../testdata/fourth_file_listing.json | 19 + .../testdata/second_file.json | 16 + .../testdata/second_file_listing.json | 19 + .../testdata/single_file_list.json | 24 + .../testdata/single_object_not_found.json | 13 + .../testdata/third_file.json | 16 + .../testdata/third_file_listing.json | 19 + plugins/inputs/graylog/README.md | 79 + plugins/inputs/graylog/graylog.go | 267 + plugins/inputs/graylog/graylog_test.go | 201 + plugins/inputs/graylog/sample.conf | 38 + plugins/inputs/haproxy/README.md | 128 + plugins/inputs/haproxy/haproxy.go | 283 + plugins/inputs/haproxy/haproxy_test.go | 344 + plugins/inputs/haproxy/sample.conf | 26 + .../inputs/haproxy/testdata/sample_output.csv | 15 + plugins/inputs/hddtemp/README.md | 68 + plugins/inputs/hddtemp/go-hddtemp/LICENSE | 21 + plugins/inputs/hddtemp/go-hddtemp/hddtemp.go | 71 + .../inputs/hddtemp/go-hddtemp/hddtemp_test.go | 99 + plugins/inputs/hddtemp/hddtemp.go | 77 + plugins/inputs/hddtemp/hddtemp_test.go | 82 + plugins/inputs/hddtemp/sample.conf | 11 + plugins/inputs/http/README.md | 166 + plugins/inputs/http/http.go | 266 + plugins/inputs/http/http_test.go | 549 + plugins/inputs/http/sample.conf | 88 + plugins/inputs/http/sample.conf.in | 65 + plugins/inputs/http_listener_v2/README.md | 143 + .../http_listener_v2/http_listener_v2.go | 433 + .../http_listener_v2/http_listener_v2_test.go | 778 + plugins/inputs/http_listener_v2/sample.conf | 73 + .../http_listener_v2/testdata/huge_metric | 1 + .../http_listener_v2/testdata/testmsgs.gz | Bin 0 -> 97 bytes plugins/inputs/http_response/README.md | 177 + plugins/inputs/http_response/http_response.go | 483 + .../http_response/http_response_test.go | 1481 ++ plugins/inputs/http_response/sample.conf | 92 + plugins/inputs/huebridge/README.md | 183 + plugins/inputs/huebridge/bridge.go | 424 + plugins/inputs/huebridge/huebridge.go | 103 + plugins/inputs/huebridge/huebridge_test.go | 150 + plugins/inputs/huebridge/sample.conf | 20 + .../huebridge/testdata/conf/huebridge.conf | 30 + .../huebridge/testdata/metrics/huebridge.txt | 14 + plugins/inputs/hugepages/README.md | 86 + plugins/inputs/hugepages/hugepages.go | 280 + .../inputs/hugepages/hugepages_notlinux.go | 35 + plugins/inputs/hugepages/hugepages_test.go | 227 + plugins/inputs/hugepages/sample.conf | 10 + .../testdata/invalid/1/anode3/dir_lock | 0 .../free_hugepages/dir_lock | 0 .../hugepages-1048576kB/nry_hugepages | 1 + .../1/node0/hugepages/hugepages-2048kB | 0 .../hugepages-aaaa1048576kB/free_hugepages | 1 + .../hugepages1048576kB/free_hugepages | 1 + .../inputs/hugepages/testdata/invalid/1/node1 | 1 + .../testdata/invalid/1/node4b/dir_lock | 0 .../hugepages-1048576kB/nr_hugepages | 1 + .../inputs/hugepages/testdata/invalid/meminfo | 8 + .../inputs/hugepages/testdata/valid/meminfo | 51 + .../hugepages-1048576kB/free_hugepages | 1 + .../hugepages-1048576kB/nr_hugepages | 1 + .../nr_hugepages_mempolicy | 1 + .../nr_overcommit_hugepages | 1 + .../hugepages-1048576kB/resv_hugepages | 1 + .../hugepages-1048576kB/surplus_hugepages | 1 + .../hugepages/hugepages-2048kB/free_hugepages | 1 + .../hugepages/hugepages-2048kB/nr_hugepages | 1 + .../hugepages-2048kB/nr_hugepages_mempolicy | 1 + .../hugepages-2048kB/nr_overcommit_hugepages | 1 + .../hugepages/hugepages-2048kB/resv_hugepages | 1 + .../hugepages-2048kB/surplus_hugepages | 1 + .../hugepages-1048576kB/free_hugepages | 1 + .../hugepages-1048576kB/nr_hugepages | 1 + .../hugepages-1048576kB/surplus_hugepages | 1 + .../hugepages/hugepages-2048kB/free_hugepages | 1 + .../hugepages/hugepages-2048kB/nr_hugepages | 1 + .../hugepages-2048kB/surplus_hugepages | 1 + .../hugepages-1048576kB/free_hugepages | 1 + .../hugepages-1048576kB/nr_hugepages | 1 + .../hugepages-1048576kB/surplus_hugepages | 1 + .../hugepages/hugepages-2048kB/free_hugepages | 1 + .../hugepages/hugepages-2048kB/nr_hugepages | 1 + .../hugepages-2048kB/surplus_hugepages | 1 + plugins/inputs/icinga2/README.md | 179 + plugins/inputs/icinga2/icinga2.go | 299 + plugins/inputs/icinga2/icinga2_test.go | 304 + plugins/inputs/icinga2/sample.conf | 27 + plugins/inputs/infiniband/README.md | 112 + plugins/inputs/infiniband/infiniband.go | 26 + plugins/inputs/infiniband/infiniband_linux.go | 62 + .../inputs/infiniband/infiniband_notlinux.go | 23 + plugins/inputs/infiniband/infiniband_test.go | 299 + plugins/inputs/infiniband/sample.conf | 7 + plugins/inputs/influxdb/README.md | 459 + plugins/inputs/influxdb/influxdb.go | 313 + plugins/inputs/influxdb/influxdb_test.go | 343 + plugins/inputs/influxdb/sample.conf | 25 + .../inputs/influxdb/testdata/cloud1.influx | 184 + plugins/inputs/influxdb/testdata/cloud1.json | 4666 ++++++ .../influxdb/testdata/influx_return.json | 1255 ++ .../influxdb/testdata/influx_return2.json | 1255 ++ plugins/inputs/influxdb/types.go | 57 + plugins/inputs/influxdb_listener/README.md | 125 + .../influxdb_listener/influxdb_listener.go | 543 + .../influxdb_listener_benchmark_test.go | 106 + .../influxdb_listener_test.go | 900 ++ plugins/inputs/influxdb_listener/sample.conf | 55 + .../influxdb_listener/testdata/huge_metric | 1 + .../influxdb_listener/testdata/testmsgs.gz | Bin 0 -> 97 bytes plugins/inputs/influxdb_v2_listener/README.md | 108 + .../influxdb_v2_listener.go | 454 + .../influxdb_v2_listener_benchmark_test.go | 106 + .../influxdb_v2_listener_test.go | 668 + .../inputs/influxdb_v2_listener/sample.conf | 42 + .../influxdb_v2_listener/testdata/huge_metric | 1 + .../influxdb_v2_listener/testdata/testmsgs.gz | Bin 0 -> 97 bytes plugins/inputs/intel_baseband/README.md | 129 + .../inputs/intel_baseband/intel_baseband.go | 227 + .../intel_baseband_notamd64linux.go | 32 + .../intel_baseband/intel_baseband_test.go | 179 + .../inputs/intel_baseband/log_connector.go | 273 + .../intel_baseband/log_connector_test.go | 257 + plugins/inputs/intel_baseband/mocks/conn.go | 197 + plugins/inputs/intel_baseband/sample.conf | 31 + .../inputs/intel_baseband/sock_connector.go | 102 + .../intel_baseband/sock_connector_test.go | 77 + .../testdata/logfiles/empty.log | 0 .../testdata/logfiles/example.log | 16 + plugins/inputs/intel_baseband/utils.go | 81 + plugins/inputs/intel_baseband/utils_test.go | 182 + plugins/inputs/intel_dlb/README.md | 86 + plugins/inputs/intel_dlb/intel_dlb.go | 474 + .../inputs/intel_dlb/intel_dlb_notlinux.go | 32 + plugins/inputs/intel_dlb/intel_dlb_test.go | 1133 ++ plugins/inputs/intel_dlb/ras_reader.go | 37 + plugins/inputs/intel_dlb/ras_reader_mock.go | 84 + plugins/inputs/intel_dlb/sample.conf | 22 + plugins/inputs/intel_pmt/README.md | 402 + plugins/inputs/intel_pmt/filtering.go | 179 + plugins/inputs/intel_pmt/filtering_test.go | 655 + plugins/inputs/intel_pmt/intel_pmt.go | 405 + .../intel_pmt/intel_pmt_notamd64linux.go | 33 + plugins/inputs/intel_pmt/intel_pmt_test.go | 592 + plugins/inputs/intel_pmt/sample.conf | 18 + plugins/inputs/intel_pmt/tags_extraction.go | 34 + .../inputs/intel_pmt/tags_extraction_test.go | 155 + plugins/inputs/intel_pmt/xml_parser.go | 274 + plugins/inputs/intel_pmt/xml_parser_test.go | 155 + plugins/inputs/intel_pmu/README.md | 261 + plugins/inputs/intel_pmu/activators.go | 205 + plugins/inputs/intel_pmu/activators_test.go | 431 + plugins/inputs/intel_pmu/config.go | 239 + plugins/inputs/intel_pmu/config_test.go | 236 + plugins/inputs/intel_pmu/intel_pmu.go | 434 + .../intel_pmu/intel_pmu_notamd64linux.go | 37 + plugins/inputs/intel_pmu/intel_pmu_test.go | 555 + plugins/inputs/intel_pmu/mocks.go | 410 + plugins/inputs/intel_pmu/reader.go | 240 + plugins/inputs/intel_pmu/reader_test.go | 522 + plugins/inputs/intel_pmu/resolver.go | 150 + plugins/inputs/intel_pmu/resolver_test.go | 377 + plugins/inputs/intel_pmu/sample.conf | 48 + plugins/inputs/intel_powerstat/README.md | 478 + plugins/inputs/intel_powerstat/fetcher.go | 139 + .../inputs/intel_powerstat/intel_powerstat.go | 1202 ++ .../intel_powerstat_notlinux.go | 33 + .../intel_powerstat/intel_powerstat_test.go | 5223 ++++++ plugins/inputs/intel_powerstat/metrics.go | 320 + .../inputs/intel_powerstat/metrics_test.go | 151 + plugins/inputs/intel_powerstat/options.go | 184 + .../inputs/intel_powerstat/options_test.go | 306 + plugins/inputs/intel_powerstat/sample.conf | 48 + .../aperfmperf_flag_not_found/cpuinfo | 27 + .../testdata/cpu_model_missing/cpuinfo | 26 + .../inputs/intel_powerstat/testdata/cpuinfo | 111 + .../testdata/dts_flag_not_found/cpuinfo | 27 + .../testdata/model_not_supported/cpuinfo | 27 + .../testdata/msr_flag_not_found/cpuinfo | 27 + .../testdata/sapphirerapids_core.json | 299 + .../testdata/vendor_not_supported/cpuinfo | 25 + plugins/inputs/intel_rdt/README.md | 142 + plugins/inputs/intel_rdt/intel_rdt.go | 556 + plugins/inputs/intel_rdt/intel_rdt_test.go | 277 + plugins/inputs/intel_rdt/intel_rdt_windows.go | 36 + plugins/inputs/intel_rdt/processes.go | 41 + plugins/inputs/intel_rdt/publisher.go | 176 + plugins/inputs/intel_rdt/publisher_test.go | 435 + plugins/inputs/intel_rdt/sample.conf | 29 + plugins/inputs/internal/README.md | 106 + plugins/inputs/internal/internal.go | 142 + plugins/inputs/internal/internal_test.go | 113 + plugins/inputs/internal/sample.conf | 8 + plugins/inputs/internet_speed/README.md | 99 + .../inputs/internet_speed/internet_speed.go | 210 + .../internet_speed/internet_speed_test.go | 41 + plugins/inputs/internet_speed/sample.conf | 36 + plugins/inputs/interrupts/README.md | 101 + plugins/inputs/interrupts/interrupts.go | 145 + plugins/inputs/interrupts/interrupts_test.go | 160 + plugins/inputs/interrupts/sample.conf | 13 + plugins/inputs/ipmi_sensor/README.md | 213 + plugins/inputs/ipmi_sensor/connection.go | 73 + plugins/inputs/ipmi_sensor/connection_test.go | 87 + plugins/inputs/ipmi_sensor/ipmi_sensor.go | 407 + .../inputs/ipmi_sensor/ipmi_sensor_test.go | 936 ++ plugins/inputs/ipmi_sensor/sample.conf | 49 + plugins/inputs/ipset/README.md | 104 + plugins/inputs/ipset/ipset.go | 149 + plugins/inputs/ipset/ipset_entries.go | 86 + plugins/inputs/ipset/ipset_entries_test.go | 97 + plugins/inputs/ipset/ipset_test.go | 150 + plugins/inputs/ipset/sample.conf | 16 + plugins/inputs/iptables/README.md | 133 + plugins/inputs/iptables/iptables.go | 139 + plugins/inputs/iptables/iptables_notlinux.go | 33 + plugins/inputs/iptables/iptables_test.go | 251 + plugins/inputs/iptables/sample.conf | 24 + plugins/inputs/ipvs/README.md | 115 + plugins/inputs/ipvs/ipvs.go | 153 + plugins/inputs/ipvs/ipvs_notlinux.go | 33 + plugins/inputs/ipvs/sample.conf | 4 + plugins/inputs/jenkins/README.md | 137 + plugins/inputs/jenkins/client.go | 152 + plugins/inputs/jenkins/jenkins.go | 468 + plugins/inputs/jenkins/jenkins_test.go | 998 ++ plugins/inputs/jenkins/sample.conf | 52 + plugins/inputs/jolokia2_agent/README.md | 202 + .../jolokia2_agent/examples/activemq.conf | 57 + .../jolokia2_agent/examples/bitbucket.conf | 39 + .../jolokia2_agent/examples/cassandra.conf | 109 + .../jolokia2_agent/examples/hadoop-hdfs.conf | 85 + .../inputs/jolokia2_agent/examples/java.conf | 40 + .../inputs/jolokia2_agent/examples/jboss.conf | 59 + .../examples/kafka-connect.conf | 90 + .../inputs/jolokia2_agent/examples/kafka.conf | 109 + .../jolokia2_agent/examples/tomcat.conf | 65 + .../jolokia2_agent/examples/weblogic.conf | 56 + .../jolokia2_agent/examples/zookeeper.conf | 18 + .../inputs/jolokia2_agent/jolokia2_agent.go | 104 + .../jolokia2_agent/jolokia2_agent_test.go | 932 ++ plugins/inputs/jolokia2_agent/sample.conf | 27 + .../jolokia2_agent/testdata/response.json | 241 + plugins/inputs/jolokia2_proxy/README.md | 104 + .../inputs/jolokia2_proxy/jolokia2_proxy.go | 105 + .../jolokia2_proxy/jolokia2_proxy_test.go | 194 + plugins/inputs/jolokia2_proxy/sample.conf | 35 + .../inputs/jti_openconfig_telemetry/README.md | 105 + .../auth/authentication_service.pb.go | 238 + .../auth/authentication_service.proto | 49 + .../auth/authentication_service_grpc.pb.go | 102 + .../jti_openconfig_telemetry/collection.go | 59 + .../inputs/jti_openconfig_telemetry/gen.go | 11 + .../jti_openconfig_telemetry.go | 461 + .../jti_openconfig_telemetry_test.go | 269 + .../jti_openconfig_telemetry/oc/oc.pb.go | 1974 +++ .../jti_openconfig_telemetry/oc/oc.proto | 320 + .../jti_openconfig_telemetry/oc/oc_grpc.pb.go | 294 + .../jti_openconfig_telemetry/sample.conf | 60 + plugins/inputs/kafka_consumer/README.md | 237 + .../inputs/kafka_consumer/kafka_consumer.go | 591 + .../kafka_consumer/kafka_consumer_test.go | 929 ++ plugins/inputs/kafka_consumer/sample.conf | 163 + plugins/inputs/kapacitor/README.md | 473 + plugins/inputs/kapacitor/kapacitor.go | 240 + plugins/inputs/kapacitor/kapacitor_test.go | 143 + plugins/inputs/kapacitor/sample.conf | 17 + .../kapacitor/testdata/kapacitor_return.json | 1818 +++ plugins/inputs/kernel/README.md | 115 + plugins/inputs/kernel/kernel.go | 207 + plugins/inputs/kernel/kernel_notlinux.go | 33 + plugins/inputs/kernel/kernel_test.go | 208 + plugins/inputs/kernel/psi.go | 51 + plugins/inputs/kernel/psi_test.go | 170 + plugins/inputs/kernel/sample.conf | 8 + .../kernel/testdata/entropy_stat_file_full | 1 + .../kernel/testdata/entropy_stat_file_invalid | 0 .../kernel/testdata/entropy_stat_file_partial | 1 + .../kernel/testdata/ksm/invalid/full_scans | 1 + .../testdata/ksm/invalid/max_page_sharing | 1 + .../testdata/ksm/invalid/merge_across_nodes | 1 + .../kernel/testdata/ksm/invalid/pages_shared | 1 + .../kernel/testdata/ksm/invalid/pages_sharing | 1 + .../kernel/testdata/ksm/invalid/pages_to_scan | 1 + .../testdata/ksm/invalid/pages_unshared | 1 + .../testdata/ksm/invalid/pages_volatile | 1 + .../inputs/kernel/testdata/ksm/invalid/run | 1 + .../testdata/ksm/invalid/sleep_millisecs | 1 + .../testdata/ksm/invalid/stable_node_chains | 1 + .../stable_node_chains_prune_millisecs | 1 + .../testdata/ksm/invalid/stable_node_dups | 1 + .../testdata/ksm/invalid/use_zero_pages | 1 + .../kernel/testdata/ksm/missing/full_scans | 1 + .../testdata/ksm/missing/max_page_sharing | 1 + .../testdata/ksm/missing/merge_across_nodes | 1 + .../kernel/testdata/ksm/missing/pages_shared | 1 + .../kernel/testdata/ksm/missing/pages_sharing | 1 + .../kernel/testdata/ksm/missing/pages_to_scan | 1 + .../testdata/ksm/missing/pages_unshared | 1 + .../testdata/ksm/missing/pages_volatile | 1 + .../testdata/ksm/missing/sleep_millisecs | 1 + .../testdata/ksm/missing/stable_node_chains | 1 + .../stable_node_chains_prune_millisecs | 1 + .../testdata/ksm/missing/stable_node_dups | 1 + .../testdata/ksm/missing/use_zero_pages | 1 + .../kernel/testdata/ksm/valid/full_scans | 1 + .../testdata/ksm/valid/max_page_sharing | 1 + .../testdata/ksm/valid/merge_across_nodes | 1 + .../kernel/testdata/ksm/valid/pages_shared | 1 + .../kernel/testdata/ksm/valid/pages_sharing | 1 + .../kernel/testdata/ksm/valid/pages_to_scan | 1 + .../kernel/testdata/ksm/valid/pages_unshared | 1 + .../kernel/testdata/ksm/valid/pages_volatile | 1 + plugins/inputs/kernel/testdata/ksm/valid/run | 1 + .../kernel/testdata/ksm/valid/sleep_millisecs | 1 + .../testdata/ksm/valid/stable_node_chains | 1 + .../valid/stable_node_chains_prune_millisecs | 1 + .../testdata/ksm/valid/stable_node_dups | 1 + .../kernel/testdata/ksm/valid/use_zero_pages | 1 + plugins/inputs/kernel/testdata/pressure/cpu | 2 + plugins/inputs/kernel/testdata/pressure/io | 2 + .../inputs/kernel/testdata/pressure/memory | 2 + plugins/inputs/kernel/testdata/stat_file_full | 12 + .../inputs/kernel/testdata/stat_file_invalid | 12 + .../inputs/kernel/testdata/stat_file_invalid2 | 10 + .../inputs/kernel/testdata/stat_file_partial | 9 + plugins/inputs/kernel_vmstat/README.md | 133 + plugins/inputs/kernel_vmstat/kernel_vmstat.go | 77 + .../kernel_vmstat/kernel_vmstat_notlinux.go | 33 + .../kernel_vmstat/kernel_vmstat_test.go | 310 + plugins/inputs/kernel_vmstat/sample.conf | 4 + plugins/inputs/kibana/README.md | 100 + plugins/inputs/kibana/kibana.go | 254 + plugins/inputs/kibana/kibana_test.go | 87 + plugins/inputs/kibana/sample.conf | 25 + .../basic_kibana_telegraf.conf | 75 + .../test_environment/docker-compose.yml | 48 + .../kibana/test_environment/run_test_env.sh | 5 + plugins/inputs/kibana/testdata_test6_3.go | 200 + plugins/inputs/kibana/testdata_test6_5.go | 228 + plugins/inputs/kinesis_consumer/README.md | 142 + plugins/inputs/kinesis_consumer/consumer.go | 355 + plugins/inputs/kinesis_consumer/encoding.go | 45 + .../kinesis_consumer/kinesis_consumer.go | 278 + .../kinesis_consumer/kinesis_consumer_test.go | 164 + plugins/inputs/kinesis_consumer/logging.go | 29 + plugins/inputs/kinesis_consumer/sample.conf | 74 + plugins/inputs/kinesis_consumer/store.go | 179 + plugins/inputs/knx_listener/README.md | 102 + .../knx_listener/knx_dummy_interface.go | 31 + plugins/inputs/knx_listener/knx_listener.go | 215 + .../inputs/knx_listener/knx_listener_test.go | 280 + plugins/inputs/knx_listener/sample.conf | 25 + plugins/inputs/kube_inventory/README.md | 399 + plugins/inputs/kube_inventory/certificate.go | 94 + plugins/inputs/kube_inventory/client.go | 165 + plugins/inputs/kube_inventory/client_test.go | 26 + plugins/inputs/kube_inventory/daemonset.go | 49 + .../inputs/kube_inventory/daemonset_test.go | 279 + plugins/inputs/kube_inventory/deployment.go | 39 + .../inputs/kube_inventory/deployment_test.go | 295 + plugins/inputs/kube_inventory/endpoint.go | 63 + .../inputs/kube_inventory/endpoint_test.go | 264 + plugins/inputs/kube_inventory/ingress.go | 61 + plugins/inputs/kube_inventory/ingress_test.go | 237 + .../inputs/kube_inventory/kube_inventory.go | 211 + plugins/inputs/kube_inventory/node.go | 99 + plugins/inputs/kube_inventory/node_test.go | 181 + .../inputs/kube_inventory/persistentvolume.go | 47 + .../kube_inventory/persistentvolume_test.go | 97 + .../kube_inventory/persistentvolumeclaim.go | 53 + .../persistentvolumeclaim_test.go | 362 + plugins/inputs/kube_inventory/pod.go | 169 + plugins/inputs/kube_inventory/pod_test.go | 998 ++ .../inputs/kube_inventory/resourcequotas.go | 77 + .../kube_inventory/resourcequotas_test.go | 112 + plugins/inputs/kube_inventory/sample.conf | 53 + plugins/inputs/kube_inventory/service.go | 71 + plugins/inputs/kube_inventory/service_test.go | 281 + plugins/inputs/kube_inventory/statefulset.go | 49 + .../inputs/kube_inventory/statefulset_test.go | 378 + plugins/inputs/kubernetes/README.md | 185 + plugins/inputs/kubernetes/kubernetes.go | 369 + .../inputs/kubernetes/kubernetes_metrics.go | 93 + plugins/inputs/kubernetes/kubernetes_pods.go | 27 + plugins/inputs/kubernetes/kubernetes_test.go | 391 + plugins/inputs/kubernetes/sample.conf | 36 + plugins/inputs/lanz/README.md | 110 + plugins/inputs/lanz/lanz.go | 128 + plugins/inputs/lanz/lanz_test.go | 136 + plugins/inputs/lanz/sample.conf | 7 + plugins/inputs/ldap/389ds.go | 115 + plugins/inputs/ldap/README.md | 103 + plugins/inputs/ldap/ldap.go | 179 + plugins/inputs/ldap/ldap_test.go | 579 + plugins/inputs/ldap/openldap.go | 89 + plugins/inputs/ldap/sample.conf | 47 + plugins/inputs/ldap/sample.conf.in | 24 + plugins/inputs/leofs/README.md | 190 + plugins/inputs/leofs/leofs.go | 249 + plugins/inputs/leofs/leofs_test.go | 195 + plugins/inputs/leofs/sample.conf | 5 + plugins/inputs/libvirt/README.md | 273 + plugins/inputs/libvirt/libvirt.go | 266 + .../inputs/libvirt/libvirt_metric_format.go | 571 + plugins/inputs/libvirt/libvirt_test.go | 1066 ++ plugins/inputs/libvirt/libvirt_utils.go | 146 + plugins/inputs/libvirt/libvirt_utils_mock.go | 181 + plugins/inputs/libvirt/sample.conf | 29 + plugins/inputs/linux_cpu/README.md | 80 + plugins/inputs/linux_cpu/linux_cpu.go | 213 + .../inputs/linux_cpu/linux_cpu_nonlinux.go | 32 + plugins/inputs/linux_cpu/linux_cpu_test.go | 184 + plugins/inputs/linux_cpu/sample.conf | 13 + plugins/inputs/linux_sysctl_fs/README.md | 56 + .../inputs/linux_sysctl_fs/linux_sysctl_fs.go | 109 + .../linux_sysctl_fs/linux_sysctl_fs_test.go | 39 + plugins/inputs/linux_sysctl_fs/sample.conf | 3 + plugins/inputs/logparser/README.md | 136 + .../inputs/logparser/dev/docker-compose.yml | 13 + plugins/inputs/logparser/dev/telegraf.conf | 12 + plugins/inputs/logparser/dev/test.log | 2 + plugins/inputs/logparser/logparser.go | 307 + plugins/inputs/logparser/logparser_solaris.go | 3 + plugins/inputs/logparser/logparser_test.go | 228 + plugins/inputs/logparser/sample.conf | 52 + .../inputs/logparser/testdata/test-patterns | 18 + plugins/inputs/logparser/testdata/test_a.log | 1 + plugins/inputs/logparser/testdata/test_b.log | 1 + plugins/inputs/logparser/testdata/test_c.log | 1 + plugins/inputs/logstash/README.md | 187 + plugins/inputs/logstash/logstash.go | 519 + plugins/inputs/logstash/logstash_test.go | 830 + plugins/inputs/logstash/sample.conf | 38 + plugins/inputs/logstash/samples_logstash5.go | 156 + plugins/inputs/logstash/samples_logstash6.go | 256 + plugins/inputs/logstash/samples_logstash7.go | 140 + plugins/inputs/lustre2/README.md | 203 + plugins/inputs/lustre2/lustre2.go | 772 + plugins/inputs/lustre2/lustre2_notlinux.go | 33 + plugins/inputs/lustre2/lustre2_test.go | 605 + plugins/inputs/lustre2/sample.conf | 26 + plugins/inputs/lvm/README.md | 107 + plugins/inputs/lvm/lvm.go | 288 + plugins/inputs/lvm/lvm_test.go | 214 + plugins/inputs/lvm/sample.conf | 13 + plugins/inputs/mailchimp/README.md | 80 + plugins/inputs/mailchimp/chimp_api.go | 248 + plugins/inputs/mailchimp/mailchimp.go | 112 + plugins/inputs/mailchimp/mailchimp_test.go | 788 + plugins/inputs/mailchimp/sample.conf | 12 + plugins/inputs/marklogic/README.md | 80 + plugins/inputs/marklogic/marklogic.go | 232 + plugins/inputs/marklogic/marklogic_test.go | 1286 ++ plugins/inputs/marklogic/sample.conf | 18 + plugins/inputs/mcrouter/README.md | 120 + plugins/inputs/mcrouter/mcrouter.go | 280 + plugins/inputs/mcrouter/mcrouter_test.go | 188 + plugins/inputs/mcrouter/sample.conf | 8 + .../inputs/mcrouter/testdata/mcrouter_stats | 70 + plugins/inputs/mdstat/README.md | 63 + plugins/inputs/mdstat/mdstat.go | 293 + plugins/inputs/mdstat/mdstat_notlinux.go | 33 + plugins/inputs/mdstat/mdstat_test.go | 190 + plugins/inputs/mdstat/sample.conf | 6 + plugins/inputs/mem/README.md | 79 + plugins/inputs/mem/mem.go | 107 + plugins/inputs/mem/mem_test.go | 117 + plugins/inputs/mem/sample.conf | 3 + plugins/inputs/memcached/README.md | 152 + plugins/inputs/memcached/memcached.go | 238 + plugins/inputs/memcached/memcached_test.go | 303 + plugins/inputs/memcached/sample.conf | 15 + plugins/inputs/mesos/README.md | 367 + plugins/inputs/mesos/mesos.go | 544 + plugins/inputs/mesos/mesos_test.go | 428 + plugins/inputs/mesos/sample.conf | 42 + plugins/inputs/minecraft/README.md | 100 + plugins/inputs/minecraft/client.go | 171 + plugins/inputs/minecraft/client_test.go | 187 + plugins/inputs/minecraft/minecraft.go | 80 + plugins/inputs/minecraft/minecraft_test.go | 123 + plugins/inputs/minecraft/sample.conf | 13 + plugins/inputs/mock/README.md | 88 + plugins/inputs/mock/mock.go | 162 + plugins/inputs/mock/mock_test.go | 110 + plugins/inputs/mock/sample.conf | 31 + plugins/inputs/modbus/README.md | 885 + plugins/inputs/modbus/configuration.go | 64 + plugins/inputs/modbus/configuration_metric.go | 399 + .../modbus/configuration_metric_test.go | 393 + .../inputs/modbus/configuration_register.go | 348 + .../modbus/configuration_register_test.go | 1284 ++ .../inputs/modbus/configuration_request.go | 439 + .../modbus/configuration_request_test.go | 3339 ++++ plugins/inputs/modbus/modbus.go | 566 + plugins/inputs/modbus/modbus_test.go | 744 + plugins/inputs/modbus/request.go | 305 + .../inputs/modbus/sample_general_begin.conf | 57 + plugins/inputs/modbus/sample_general_end.conf | 51 + plugins/inputs/modbus/sample_metric.conf | 73 + plugins/inputs/modbus/sample_register.conf | 55 + plugins/inputs/modbus/sample_request.conf | 120 + .../init.err | 1 + .../telegraf.conf | 24 + .../expected.out | 2 + .../telegraf.conf | 28 + .../expected.out | 3 + .../telegraf.conf | 40 + .../duplicate_fields_issue_12091/expected.out | 7 + .../telegraf.conf | 71 + .../init.err | 1 + .../telegraf.conf | 18 + .../duplicate_fields_same_tags/init.err | 1 + .../duplicate_fields_same_tags/telegraf.conf | 28 + .../init.err | 1 + .../telegraf.conf | 9 + .../metric_style_issue_16031/expected.out | 1 + .../metric_style_issue_16031/telegraf.conf | 15 + .../overflow_issue_14387/expected.out | 1 + .../overflow_issue_14387/telegraf.conf | 125 + plugins/inputs/modbus/type_conversions.go | 104 + plugins/inputs/modbus/type_conversions16.go | 187 + plugins/inputs/modbus/type_conversions32.go | 200 + plugins/inputs/modbus/type_conversions64.go | 184 + plugins/inputs/modbus/type_conversions8.go | 253 + plugins/inputs/modbus/type_conversions_bit.go | 14 + .../inputs/modbus/type_conversions_string.go | 63 + plugins/inputs/mongodb/README.md | 346 + plugins/inputs/mongodb/dev/docker-compose.yml | 16 + plugins/inputs/mongodb/dev/telegraf.conf | 9 + plugins/inputs/mongodb/mongodb.go | 200 + plugins/inputs/mongodb/mongodb_data.go | 478 + plugins/inputs/mongodb/mongodb_data_test.go | 543 + plugins/inputs/mongodb/mongodb_server.go | 379 + plugins/inputs/mongodb/mongodb_server_test.go | 189 + plugins/inputs/mongodb/mongostat.go | 1445 ++ plugins/inputs/mongodb/mongostat_test.go | 597 + plugins/inputs/mongodb/sample.conf | 44 + plugins/inputs/monit/README.md | 251 + plugins/inputs/monit/monit.go | 384 + plugins/inputs/monit/monit_test.go | 690 + plugins/inputs/monit/sample.conf | 18 + .../monit/testdata/response_invalidxml_1.xml | 51 + .../monit/testdata/response_invalidxml_2.xml | 52 + .../monit/testdata/response_invalidxml_3.xml | 52 + .../monit/testdata/response_servicetype_0.xml | 51 + .../monit/testdata/response_servicetype_1.xml | 41 + .../monit/testdata/response_servicetype_2.xml | 42 + .../monit/testdata/response_servicetype_3.xml | 52 + .../monit/testdata/response_servicetype_4.xml | 45 + .../monit/testdata/response_servicetype_5.xml | 57 + .../monit/testdata/response_servicetype_6.xml | 41 + .../monit/testdata/response_servicetype_7.xml | 42 + .../monit/testdata/response_servicetype_8.xml | 70 + .../response_servicetype_8_failure.xml | 70 + ...esponse_servicetype_8_initializingmode.xml | 70 + .../response_servicetype_8_passivemode.xml | 70 + .../response_servicetype_8_pendingaction.xml | 70 + plugins/inputs/mqtt_consumer/README.md | 276 + plugins/inputs/mqtt_consumer/mqtt_consumer.go | 366 + .../mqtt_consumer/mqtt_consumer_test.go | 1040 ++ plugins/inputs/mqtt_consumer/mqtt_logger.go | 19 + plugins/inputs/mqtt_consumer/sample.conf | 97 + .../mqtt_consumer/testdata/mosquitto.conf | 3 + plugins/inputs/mqtt_consumer/topic_parser.go | 230 + plugins/inputs/multifile/README.md | 96 + plugins/inputs/multifile/multifile.go | 116 + plugins/inputs/multifile/multifile_test.go | 78 + plugins/inputs/multifile/sample.conf | 23 + plugins/inputs/multifile/testdata/bool.txt | 1 + plugins/inputs/multifile/testdata/float.txt | 1 + plugins/inputs/multifile/testdata/int.txt | 1 + plugins/inputs/multifile/testdata/string.txt | 1 + plugins/inputs/multifile/testdata/tag.txt | 1 + plugins/inputs/mysql/README.md | 403 + plugins/inputs/mysql/dev/docker-compose.yml | 42 + plugins/inputs/mysql/dev/telegraf.conf | 61 + plugins/inputs/mysql/mysql.go | 1990 +++ plugins/inputs/mysql/mysql_test.go | 576 + plugins/inputs/mysql/sample.conf | 103 + plugins/inputs/mysql/v1/mysql.go | 199 + plugins/inputs/mysql/v2/convert.go | 178 + plugins/inputs/mysql/v2/convert_test.go | 127 + plugins/inputs/nats/README.md | 60 + plugins/inputs/nats/nats.go | 106 + plugins/inputs/nats/nats_freebsd.go | 3 + plugins/inputs/nats/nats_test.go | 111 + plugins/inputs/nats/sample.conf | 8 + plugins/inputs/nats_consumer/README.md | 117 + plugins/inputs/nats_consumer/nats_consumer.go | 282 + .../nats_consumer/nats_consumer_test.go | 212 + plugins/inputs/nats_consumer/sample.conf | 64 + plugins/inputs/neoom_beaam/README.md | 126 + plugins/inputs/neoom_beaam/neoom_beaam.go | 310 + .../inputs/neoom_beaam/neoom_beaam_test.go | 115 + plugins/inputs/neoom_beaam/sample.conf | 36 + plugins/inputs/neoom_beaam/sample.conf.in | 13 + .../testcases/small/configuration.json | 333 + .../neoom_beaam/testcases/small/expected.out | 28 + .../neoom_beaam/testcases/small/state.json | 96 + .../neoom_beaam/testcases/small/telegraf.conf | 2 + ..._22222222-bbbb-2222-bbbb-222222222222.json | 1 + ..._33333333-cccc-3333-cccc-333333333333.json | 1 + ..._44444444-dddd-4444-dddd-444444444444.json | 35 + ..._55555555-eeee-5555-eeee-555555555555.json | 71 + plugins/inputs/neoom_beaam/types.go | 38 + plugins/inputs/neptune_apex/README.md | 164 + plugins/inputs/neptune_apex/neptune_apex.go | 271 + .../inputs/neptune_apex/neptune_apex_test.go | 589 + plugins/inputs/neptune_apex/sample.conf | 14 + plugins/inputs/net/README.md | 89 + plugins/inputs/net/net.go | 163 + plugins/inputs/net/net_test.go | 216 + plugins/inputs/net/sample.conf | 15 + .../testdata/general/sys/class/net/eth0/speed | 1 + .../testdata/general/sys/class/net/eth1/speed | 1 + plugins/inputs/net_response/README.md | 69 + plugins/inputs/net_response/net_response.go | 267 + .../inputs/net_response/net_response_test.go | 341 + plugins/inputs/net_response/sample.conf | 25 + plugins/inputs/netflow/README.md | 208 + plugins/inputs/netflow/ipv4_options.csv | 27 + .../netflow/layer4_protocol_numbers.csv | 151 + plugins/inputs/netflow/mappings.go | 44 + .../netflow/mappings_ipfix_pen/ntop-35632.csv | 101 + plugins/inputs/netflow/netflow.go | 162 + plugins/inputs/netflow/netflow_decoder.go | 877 + plugins/inputs/netflow/netflow_test.go | 296 + plugins/inputs/netflow/netflow_v5.go | 91 + plugins/inputs/netflow/sample.conf | 28 + plugins/inputs/netflow/sflow_v5.go | 544 + .../testcases/ipfix_example/expected.out | 31 + .../testcases/ipfix_example/ipfix_0.bin | Bin 0 -> 1348 bytes .../testcases/ipfix_example/ipfix_1.bin | Bin 0 -> 432 bytes .../testcases/ipfix_example/ipfix_2.bin | Bin 0 -> 77 bytes .../testcases/ipfix_example/ipfix_3.bin | Bin 0 -> 132 bytes .../testcases/ipfix_example/ipfix_4.bin | Bin 0 -> 1387 bytes .../testcases/ipfix_example/ipfix_5.bin | Bin 0 -> 704 bytes .../testcases/ipfix_example/ipfix_6.bin | Bin 0 -> 58 bytes .../testcases/ipfix_example/telegraf.conf | 2 + .../testcases/ipfix_options/expected.out | 126 + .../testcases/ipfix_options/message-001.bin | Bin 0 -> 1204 bytes .../testcases/ipfix_options/message-002.bin | Bin 0 -> 1182 bytes .../testcases/ipfix_options/message-003.bin | Bin 0 -> 1182 bytes .../testcases/ipfix_options/message-004.bin | Bin 0 -> 1182 bytes .../testcases/ipfix_options/message-005.bin | Bin 0 -> 1182 bytes .../testcases/ipfix_options/message-006.bin | Bin 0 -> 1182 bytes .../testcases/ipfix_options/message-007.bin | Bin 0 -> 1182 bytes .../testcases/ipfix_options/message-008.bin | Bin 0 -> 1182 bytes .../testcases/ipfix_options/message-009.bin | Bin 0 -> 1182 bytes .../testcases/ipfix_options/telegraf.conf | 2 + .../testcases/ipfix_pen_35632/expected.out | 2 + .../testcases/ipfix_pen_35632/message-1.bin | Bin 0 -> 980 bytes .../testcases/ipfix_pen_35632/message-2.bin | Bin 0 -> 588 bytes .../testcases/ipfix_pen_35632/message-3.bin | Bin 0 -> 152 bytes .../testcases/ipfix_pen_35632/message-4.bin | Bin 0 -> 152 bytes .../testcases/ipfix_pen_35632/telegraf.conf | 3 + .../testcases/issue_13305/expected.out | 2 + .../testcases/issue_13305/message-1.bin | Bin 0 -> 980 bytes .../testcases/issue_13305/message-2.bin | Bin 0 -> 588 bytes .../testcases/issue_13305/message-3.bin | Bin 0 -> 152 bytes .../testcases/issue_13305/message-4.bin | Bin 0 -> 152 bytes .../testcases/issue_13305/telegraf.conf | 2 + .../testcases/issue_14370/expected.out | 2 + .../netflow/testcases/issue_14370/message.bin | Bin 0 -> 292 bytes .../testcases/issue_14370/telegraf.conf | 2 + .../netflow/testcases/netflow_mapping.csv | 7 + .../testcases/netflow_v5_example/expected.out | 8 + .../netflow_v5_example/netflow_v5.bin | Bin 0 -> 408 bytes .../netflow_v5_example/telegraf.conf | 3 + .../testcases/netflow_v9_example/expected.out | 8 + .../netflow_v9_example/netflow_v9.bin | Bin 0 -> 508 bytes .../netflow_v9_example/telegraf.conf | 2 + .../testcases/netflow_v9_options/expected.out | 8 + .../testcases/netflow_v9_options/message.bin | Bin 0 -> 934 bytes .../netflow_v9_options/telegraf.conf | 2 + .../testcases/sflow_issue_15375/expected.out | 1 + .../sflow_issue_15375/sflow_drop_1036.bin | Bin 0 -> 80 bytes .../testcases/sflow_issue_15375/telegraf.conf | 3 + .../testcases/sflow_issue_15918/expected.out | 7 + .../testcases/sflow_issue_15918/message.bin | Bin 0 -> 1396 bytes .../testcases/sflow_issue_15918/telegraf.conf | 3 + .../testcases/sflow_v5_example/expected.out | 1 + .../testcases/sflow_v5_example/sflow_v5.bin | Bin 0 -> 160 bytes .../testcases/sflow_v5_example/telegraf.conf | 3 + plugins/inputs/netflow/type_conversion.go | 728 + .../inputs/netflow/type_conversion_test.go | 466 + plugins/inputs/netstat/README.md | 81 + plugins/inputs/netstat/netstat.go | 71 + plugins/inputs/netstat/netstat_test.go | 66 + plugins/inputs/netstat/sample.conf | 3 + plugins/inputs/nfsclient/README.md | 230 + plugins/inputs/nfsclient/nfsclient.go | 514 + plugins/inputs/nfsclient/nfsclient_test.go | 341 + plugins/inputs/nfsclient/sample.conf | 27 + plugins/inputs/nfsclient/testdata/mountstats | 231 + plugins/inputs/nginx/README.md | 79 + plugins/inputs/nginx/nginx.go | 193 + plugins/inputs/nginx/nginx_test.go | 114 + plugins/inputs/nginx/sample.conf | 14 + plugins/inputs/nginx_plus/README.md | 157 + plugins/inputs/nginx_plus/nginx_plus.go | 569 + plugins/inputs/nginx_plus/nginx_plus_test.go | 410 + plugins/inputs/nginx_plus/sample.conf | 14 + plugins/inputs/nginx_plus_api/README.md | 329 + .../inputs/nginx_plus_api/nginx_plus_api.go | 116 + .../nginx_plus_api/nginx_plus_api_metrics.go | 669 + .../nginx_plus_api_metrics_test.go | 1585 ++ .../nginx_plus_api/nginx_plus_api_types.go | 180 + plugins/inputs/nginx_plus_api/sample.conf | 16 + plugins/inputs/nginx_sts/README.md | 132 + plugins/inputs/nginx_sts/nginx_sts.go | 291 + plugins/inputs/nginx_sts/nginx_sts_test.go | 397 + plugins/inputs/nginx_sts/sample.conf | 14 + plugins/inputs/nginx_upstream_check/README.md | 93 + .../nginx_upstream_check.go | 199 + .../nginx_upstream_check_test.go | 154 + .../inputs/nginx_upstream_check/sample.conf | 28 + plugins/inputs/nginx_vts/README.md | 153 + plugins/inputs/nginx_vts/nginx_vts.go | 343 + plugins/inputs/nginx_vts/nginx_vts_test.go | 485 + plugins/inputs/nginx_vts/sample.conf | 14 + plugins/inputs/nomad/README.md | 49 + plugins/inputs/nomad/nomad.go | 160 + plugins/inputs/nomad/nomad_metrics.go | 54 + plugins/inputs/nomad/nomad_test.go | 114 + plugins/inputs/nomad/sample.conf | 12 + .../nomad/testdata/response_key_metrics.json | 48 + plugins/inputs/nsd/README.md | 195 + plugins/inputs/nsd/nsd.go | 147 + plugins/inputs/nsd/nsd_test.go | 241 + plugins/inputs/nsd/sample.conf | 17 + plugins/inputs/nsdp/README.md | 62 + plugins/inputs/nsdp/nsdp.go | 134 + plugins/inputs/nsdp/nsdp_test.go | 112 + plugins/inputs/nsdp/sample.conf | 15 + plugins/inputs/nsdp/testdata/conf/nsdp.conf | 15 + .../testdata/metrics/nsdp_device_port.txt | 16 + plugins/inputs/nsq/README.md | 104 + plugins/inputs/nsq/nsq.go | 307 + plugins/inputs/nsq/nsq_test.go | 536 + plugins/inputs/nsq/sample.conf | 11 + plugins/inputs/nsq_consumer/README.md | 73 + plugins/inputs/nsq_consumer/nsq_consumer.go | 197 + .../inputs/nsq_consumer/nsq_consumer_test.go | 248 + plugins/inputs/nsq_consumer/sample.conf | 28 + plugins/inputs/nstat/README.md | 377 + plugins/inputs/nstat/nstat.go | 200 + plugins/inputs/nstat/nstat_test.go | 51 + plugins/inputs/nstat/sample.conf | 10 + plugins/inputs/ntpq/README.md | 108 + plugins/inputs/ntpq/ntpq.go | 314 + plugins/inputs/ntpq/ntpq_test.go | 166 + plugins/inputs/ntpq/sample.conf | 21 + .../testcases/bad_float_parse/expected.err | 1 + .../testcases/bad_float_parse/expected.out | 1 + .../ntpq/testcases/bad_float_parse/input.txt | 3 + .../testcases/bad_float_parse/telegraf.conf | 1 + .../ntpq/testcases/bad_header/expected.out | 1 + .../ntpq/testcases/bad_header/input.txt | 3 + .../ntpq/testcases/bad_header/telegraf.conf | 1 + .../ntpq/testcases/bad_int_parse/expected.err | 1 + .../ntpq/testcases/bad_int_parse/expected.out | 1 + .../ntpq/testcases/bad_int_parse/input.txt | 3 + .../testcases/bad_int_parse/telegraf.conf | 1 + .../ntpq/testcases/bad_when/expected.err | 1 + .../ntpq/testcases/bad_when/expected.out | 1 + .../inputs/ntpq/testcases/bad_when/input.txt | 3 + .../ntpq/testcases/bad_when/telegraf.conf | 1 + .../inputs/ntpq/testcases/days/expected.out | 1 + plugins/inputs/ntpq/testcases/days/input.txt | 3 + .../inputs/ntpq/testcases/days/telegraf.conf | 1 + .../inputs/ntpq/testcases/failed/expected.err | 1 + .../inputs/ntpq/testcases/failed/input.err | 1 + .../inputs/ntpq/testcases/failed/input.txt | 3 + .../ntpq/testcases/failed/telegraf.conf | 1 + .../inputs/ntpq/testcases/hours/expected.out | 1 + plugins/inputs/ntpq/testcases/hours/input.txt | 3 + .../inputs/ntpq/testcases/hours/telegraf.conf | 1 + .../ntpq/testcases/issue_2386/expected.out | 5 + .../ntpq/testcases/issue_2386/input.txt | 7 + .../ntpq/testcases/issue_2386/telegraf.conf | 3 + .../ntpq/testcases/long_poll/expected.out | 1 + .../inputs/ntpq/testcases/long_poll/input.txt | 3 + .../ntpq/testcases/long_poll/telegraf.conf | 1 + .../ntpq/testcases/minutes/expected.out | 1 + .../inputs/ntpq/testcases/minutes/input.txt | 3 + .../ntpq/testcases/minutes/telegraf.conf | 1 + .../missing_delay_column/expected.out | 1 + .../testcases/missing_delay_column/input.txt | 3 + .../missing_delay_column/telegraf.conf | 1 + .../inputs/ntpq/testcases/multi/expected.out | 5 + plugins/inputs/ntpq/testcases/multi/input.txt | 7 + .../inputs/ntpq/testcases/multi/telegraf.conf | 1 + .../ntpq/testcases/no_ref_id/expected.out | 2 + .../inputs/ntpq/testcases/no_ref_id/input.txt | 5 + .../ntpq/testcases/no_ref_id/telegraf.conf | 4 + .../testcases/pool_when_minus/expected.out | 2 + .../ntpq/testcases/pool_when_minus/input.txt | 4 + .../testcases/pool_when_minus/telegraf.conf | 1 + .../ntpq/testcases/servers/expected.out | 6 + .../ntpq/testcases/servers/input_serverA.txt | 3 + .../ntpq/testcases/servers/input_serverB.txt | 7 + .../ntpq/testcases/servers/telegraf.conf | 2 + .../testcases/servers_one_fail/expected.err | 1 + .../testcases/servers_one_fail/expected.out | 6 + .../servers_one_fail/input_serverA.txt | 3 + .../servers_one_fail/input_serverB.txt | 7 + .../servers_one_fail/input_serverC.err | 1 + .../testcases/servers_one_fail/telegraf.conf | 2 + .../inputs/ntpq/testcases/single/expected.out | 1 + .../inputs/ntpq/testcases/single/input.txt | 3 + .../ntpq/testcases/single/telegraf.conf | 1 + .../testcases/single_reach_count/expected.out | 1 + .../testcases/single_reach_count/input.txt | 3 + .../single_reach_count/telegraf.conf | 2 + .../single_reach_decimal/expected.out | 1 + .../testcases/single_reach_decimal/input.txt | 3 + .../single_reach_decimal/telegraf.conf | 2 + .../testcases/single_reach_octal/expected.out | 1 + .../testcases/single_reach_octal/input.txt | 3 + .../single_reach_octal/telegraf.conf | 2 + .../testcases/single_reach_ratio/expected.out | 1 + .../testcases/single_reach_ratio/input.txt | 3 + .../single_reach_ratio/telegraf.conf | 2 + plugins/inputs/nvidia_smi/README.md | 165 + plugins/inputs/nvidia_smi/common/setters.go | 47 + plugins/inputs/nvidia_smi/nvidia_smi.go | 135 + plugins/inputs/nvidia_smi/nvidia_smi_test.go | 794 + plugins/inputs/nvidia_smi/sample.conf | 9 + .../inputs/nvidia_smi/schema_v11/parser.go | 75 + plugins/inputs/nvidia_smi/schema_v11/types.go | 119 + .../inputs/nvidia_smi/schema_v12/parser.go | 127 + plugins/inputs/nvidia_smi/schema_v12/types.go | 302 + .../nvidia_smi/testdata/a100-sxm4-v12.xml | 452 + plugins/inputs/nvidia_smi/testdata/a10g.xml | 355 + .../nvidia_smi/testdata/gtx-1070-ti.xml | 47 + .../nvidia_smi/testdata/gtx-1660-ti.xml | 189 + .../nvidia_smi/testdata/quadro-p2000-v12.xml | 558 + .../nvidia_smi/testdata/quadro-p400.xml | 447 + .../nvidia_smi/testdata/rtx-3060-v12.xml | 319 + .../nvidia_smi/testdata/rtx-3080-v12.xml | 826 + .../nvidia_smi/testdata/rtx-3090-v12.xml | 765 + .../inputs/nvidia_smi/testdata/tesla-t4.xml | 348 + plugins/inputs/opcua/README.md | 290 + plugins/inputs/opcua/opcua.go | 81 + plugins/inputs/opcua/opcua_test.go | 613 + plugins/inputs/opcua/read_client.go | 224 + plugins/inputs/opcua/sample.conf | 152 + plugins/inputs/opcua_listener/README.md | 371 + .../inputs/opcua_listener/opcua_listener.go | 108 + .../opcua_listener/opcua_listener_test.go | 816 + plugins/inputs/opcua_listener/sample.conf | 221 + .../inputs/opcua_listener/subscribe_client.go | 229 + plugins/inputs/openldap/README.md | 112 + plugins/inputs/openldap/openldap.go | 203 + plugins/inputs/openldap/openldap_test.go | 357 + plugins/inputs/openldap/sample.conf | 23 + plugins/inputs/openntpd/README.md | 106 + plugins/inputs/openntpd/openntpd.go | 201 + plugins/inputs/openntpd/openntpd_test.go | 327 + plugins/inputs/openntpd/sample.conf | 10 + plugins/inputs/opensearch_query/README.md | 258 + .../opensearch_query/aggregation.bucket.go | 45 + .../inputs/opensearch_query/aggregation.go | 60 + .../opensearch_query/aggregation.metric.go | 18 + .../opensearch_query/aggregation.response.go | 145 + .../opensearch_query/opensearch_query.go | 271 + .../opensearch_query/opensearch_query_test.go | 691 + plugins/inputs/opensearch_query/query.go | 45 + plugins/inputs/opensearch_query/sample.conf | 59 + .../opensearch_query/testdata/nginx_logs | 500 + plugins/inputs/opensmtpd/README.md | 116 + plugins/inputs/opensmtpd/opensmtpd.go | 121 + plugins/inputs/opensmtpd/opensmtpd_test.go | 109 + plugins/inputs/opensmtpd/sample.conf | 10 + plugins/inputs/openstack/README.md | 381 + plugins/inputs/openstack/openstack.go | 1076 ++ plugins/inputs/openstack/sample.conf | 54 + plugins/inputs/opentelemetry/README.md | 174 + .../opentelemetry/grpc_service_profile.go | 135 + plugins/inputs/opentelemetry/grpc_services.go | 103 + plugins/inputs/opentelemetry/logger.go | 17 + plugins/inputs/opentelemetry/opentelemetry.go | 143 + .../opentelemetry/opentelemetry_test.go | 256 + plugins/inputs/opentelemetry/sample.conf | 58 + .../testcases/profiles/expected.out | 11 + .../testcases/profiles/profiles.json | 699 + .../testcases/profiles/telegraf.conf | 1 + plugins/inputs/opentelemetry/writer.go | 57 + plugins/inputs/openweathermap/README.md | 102 + .../inputs/openweathermap/openweathermap.go | 360 + .../openweathermap/openweathermap_test.go | 180 + plugins/inputs/openweathermap/sample.conf | 39 + .../testcases/forecast/expected.out | 2 + .../testcases/forecast/response_forecast.json | 84 + .../testcases/forecast/response_group.json | 1 + .../testcases/forecast/telegraf.conf | 4 + .../testcases/rain_batch/expected.out | 4 + .../testcases/rain_batch/response_group.json | 141 + .../testcases/rain_batch/telegraf.conf | 4 + .../testcases/snow_batch/expected.out | 4 + .../testcases/snow_batch/response_group.json | 141 + .../testcases/snow_batch/telegraf.conf | 4 + .../testcases/weather/expected.out | 1 + .../testcases/weather/response_group.json | 42 + .../testcases/weather/telegraf.conf | 4 + .../testcases/weather_batch/expected.out | 3 + .../weather_batch/response_forecast.json | 1 + .../weather_batch/response_group.json | 114 + .../testcases/weather_batch/telegraf.conf | 4 + .../testcases/weather_single/expected.out | 3 + .../weather_single/response_forecast.json | 1 + .../response_weather_2643743.json | 43 + .../response_weather_524901.json | 39 + .../response_weather_703448.json | 38 + .../testcases/weather_single/telegraf.conf | 5 + plugins/inputs/openweathermap/types.go | 71 + plugins/inputs/p4runtime/README.md | 95 + plugins/inputs/p4runtime/p4runtime.go | 232 + .../p4runtime/p4runtime_fake_client_test.go | 122 + plugins/inputs/p4runtime/p4runtime_test.go | 614 + plugins/inputs/p4runtime/sample.conf | 23 + plugins/inputs/passenger/README.md | 117 + plugins/inputs/passenger/passenger.go | 236 + plugins/inputs/passenger/passenger_test.go | 321 + plugins/inputs/passenger/sample.conf | 11 + plugins/inputs/pf/README.md | 100 + plugins/inputs/pf/pf.go | 220 + plugins/inputs/pf/pf_test.go | 273 + plugins/inputs/pf/sample.conf | 7 + plugins/inputs/pgbouncer/README.md | 137 + plugins/inputs/pgbouncer/pgbouncer.go | 317 + plugins/inputs/pgbouncer/pgbouncer_test.go | 215 + plugins/inputs/pgbouncer/sample.conf | 15 + plugins/inputs/phpfpm/README.md | 120 + plugins/inputs/phpfpm/child.go | 315 + plugins/inputs/phpfpm/fcgi.go | 270 + plugins/inputs/phpfpm/fcgi_client.go | 100 + plugins/inputs/phpfpm/fcgi_test.go | 277 + plugins/inputs/phpfpm/phpfpm.go | 404 + plugins/inputs/phpfpm/phpfpm_test.go | 495 + plugins/inputs/phpfpm/sample.conf | 40 + plugins/inputs/phpfpm/testdata/expected.out | 11 + plugins/inputs/phpfpm/testdata/phpfpm.json | 168 + plugins/inputs/ping/README.md | 199 + plugins/inputs/ping/ping.go | 313 + plugins/inputs/ping/ping_notwindows.go | 286 + plugins/inputs/ping/ping_test.go | 531 + plugins/inputs/ping/ping_windows.go | 182 + plugins/inputs/ping/ping_windows_test.go | 378 + plugins/inputs/ping/sample.conf | 56 + plugins/inputs/postfix/README.md | 73 + plugins/inputs/postfix/postfix.go | 114 + plugins/inputs/postfix/postfix_test.go | 57 + plugins/inputs/postfix/postfix_windows.go | 32 + plugins/inputs/postfix/sample.conf | 6 + plugins/inputs/postfix/stat_ctim.go | 16 + plugins/inputs/postfix/stat_ctimespec.go | 16 + plugins/inputs/postgresql/README.md | 180 + plugins/inputs/postgresql/postgresql.go | 166 + plugins/inputs/postgresql/postgresql_test.go | 379 + plugins/inputs/postgresql/sample.conf | 43 + .../inputs/postgresql_extensible/README.md | 317 + .../postgresql_extensible.go | 240 + .../postgresql_extensible_test.go | 368 + .../inputs/postgresql_extensible/sample.conf | 66 + .../postgresql_extensible/testdata/test.sql | 1 + plugins/inputs/powerdns/README.md | 88 + plugins/inputs/powerdns/powerdns.go | 124 + .../inputs/powerdns/powerdns_linux_test.go | 71 + plugins/inputs/powerdns/powerdns_test.go | 232 + plugins/inputs/powerdns/sample.conf | 7 + plugins/inputs/powerdns_recursor/README.md | 194 + .../powerdns_recursor/powerdns_recursor.go | 84 + .../powerdns_recursor_test.go | 675 + .../powerdns_recursor/protocol_commons.go | 89 + .../inputs/powerdns_recursor/protocol_v1.go | 81 + .../inputs/powerdns_recursor/protocol_v2.go | 95 + .../inputs/powerdns_recursor/protocol_v3.go | 91 + plugins/inputs/powerdns_recursor/sample.conf | 19 + plugins/inputs/processes/README.md | 98 + plugins/inputs/processes/processes.go | 11 + .../inputs/processes/processes_notwindows.go | 239 + plugins/inputs/processes/processes_test.go | 198 + plugins/inputs/processes/processes_windows.go | 27 + plugins/inputs/processes/sample.conf | 6 + plugins/inputs/procstat/README.md | 300 + plugins/inputs/procstat/filter.go | 234 + plugins/inputs/procstat/native_finder.go | 131 + plugins/inputs/procstat/native_finder_test.go | 98 + plugins/inputs/procstat/os_linux.go | 381 + plugins/inputs/procstat/os_others.go | 103 + plugins/inputs/procstat/os_windows.go | 160 + plugins/inputs/procstat/pgrep.go | 85 + plugins/inputs/procstat/process.go | 380 + plugins/inputs/procstat/procstat.go | 711 + plugins/inputs/procstat/procstat_test.go | 676 + plugins/inputs/procstat/sample.conf | 106 + plugins/inputs/procstat/service_finders.go | 166 + plugins/inputs/prometheus/README.md | 467 + plugins/inputs/prometheus/consul.go | 209 + plugins/inputs/prometheus/kubernetes.go | 500 + plugins/inputs/prometheus/kubernetes_test.go | 368 + plugins/inputs/prometheus/prometheus.go | 638 + plugins/inputs/prometheus/prometheus_test.go | 942 ++ plugins/inputs/prometheus/sample.conf | 170 + .../prometheus/testdata/openmetric-proto.bin | Bin 0 -> 348 bytes plugins/inputs/proxmox/README.md | 100 + plugins/inputs/proxmox/proxmox.go | 293 + plugins/inputs/proxmox/proxmox_test.go | 257 + plugins/inputs/proxmox/sample.conf | 24 + plugins/inputs/proxmox/structs.go | 55 + plugins/inputs/puppetagent/README.md | 168 + .../inputs/puppetagent/last_run_summary.yaml | 43 + plugins/inputs/puppetagent/puppetagent.go | 139 + .../inputs/puppetagent/puppetagent_test.go | 61 + plugins/inputs/puppetagent/sample.conf | 4 + plugins/inputs/rabbitmq/README.md | 253 + plugins/inputs/rabbitmq/rabbitmq.go | 777 + plugins/inputs/rabbitmq/rabbitmq_test.go | 688 + plugins/inputs/rabbitmq/sample.conf | 50 + .../rabbitmq/testdata/set1/exchanges.json | 22 + .../testdata/set1/federation-links.json | 63 + .../inputs/rabbitmq/testdata/set1/memory.json | 24 + .../inputs/rabbitmq/testdata/set1/nodes.json | 87 + .../rabbitmq/testdata/set1/overview.json | 63 + .../inputs/rabbitmq/testdata/set1/queues.json | 120 + .../rabbitmq/testdata/set2/exchanges.json | 104 + .../testdata/set2/federation-links.json | 1 + .../inputs/rabbitmq/testdata/set2/memory.json | 31 + .../inputs/rabbitmq/testdata/set2/nodes.json | 417 + .../rabbitmq/testdata/set2/overview.json | 1 + .../inputs/rabbitmq/testdata/set2/queues.json | 356 + plugins/inputs/radius/README.md | 48 + plugins/inputs/radius/radius.go | 158 + plugins/inputs/radius/radius_test.go | 345 + plugins/inputs/radius/sample.conf | 15 + .../testdata/invalidSourceIP/clients.conf | 4 + .../mods-config/files/authorize | 1 + .../testdata/invalidSourceIP/radiusd.conf | 118 + .../inputs/radius/testdata/raddb/clients.conf | 4 + .../raddb/mods-config/files/authorize | 1 + .../inputs/radius/testdata/raddb/radiusd.conf | 118 + plugins/inputs/raindrops/README.md | 58 + plugins/inputs/raindrops/raindrops.go | 181 + plugins/inputs/raindrops/raindrops_test.go | 107 + plugins/inputs/raindrops/sample.conf | 4 + plugins/inputs/ras/README.md | 77 + plugins/inputs/ras/ras.go | 335 + plugins/inputs/ras/ras_notlinux.go | 33 + plugins/inputs/ras/ras_test.go | 254 + plugins/inputs/ras/sample.conf | 6 + plugins/inputs/ravendb/README.md | 235 + plugins/inputs/ravendb/ravendb.go | 394 + plugins/inputs/ravendb/ravendb_dto.go | 204 + plugins/inputs/ravendb/ravendb_test.go | 411 + plugins/inputs/ravendb/sample.conf | 36 + .../ravendb/testdata/collections_full.json | 19 + .../ravendb/testdata/collections_min.json | 19 + .../ravendb/testdata/databases_full.json | 54 + .../ravendb/testdata/databases_min.json | 49 + .../inputs/ravendb/testdata/indexes_full.json | 25 + .../inputs/ravendb/testdata/indexes_min.json | 25 + .../inputs/ravendb/testdata/server_full.json | 73 + .../inputs/ravendb/testdata/server_min.json | 72 + plugins/inputs/redfish/README.md | 166 + plugins/inputs/redfish/redfish.go | 536 + plugins/inputs/redfish/redfish_test.go | 1214 ++ plugins/inputs/redfish/sample.conf | 37 + .../inputs/redfish/testdata/dell_chassis.json | 187 + .../redfish/testdata/dell_chassisinvalid.json | 188 + .../inputs/redfish/testdata/dell_power.json | 207 + .../redfish/testdata/dell_powerinvalid.json | 207 + .../inputs/redfish/testdata/dell_systems.json | 329 + .../redfish/testdata/dell_systemsinvalid.json | 329 + .../inputs/redfish/testdata/dell_thermal.json | 589 + .../redfish/testdata/dell_thermalinvalid.json | 589 + .../inputs/redfish/testdata/hp_chassis.json | 31 + plugins/inputs/redfish/testdata/hp_power.json | 144 + .../redfish/testdata/hp_powerinvalid.json | 145 + .../inputs/redfish/testdata/hp_systems.json | 319 + .../redfish/testdata/hp_systemsinvalid.json | 320 + .../inputs/redfish/testdata/hp_thermal.json | 116 + .../redfish/testdata/hp_thermal_ilo4.json | 72 + .../redfish/testdata/hp_thermalinvalid.json | 117 + plugins/inputs/redis/README.md | 250 + plugins/inputs/redis/redis.go | 783 + plugins/inputs/redis/redis_test.go | 584 + plugins/inputs/redis/sample.conf | 37 + plugins/inputs/redis_sentinel/README.md | 214 + .../inputs/redis_sentinel/redis_sentinel.go | 436 + .../redis_sentinel/redis_sentinel_test.go | 373 + .../redis_sentinel/redis_sentinel_types.go | 113 + plugins/inputs/redis_sentinel/sample.conf | 19 + .../testdata/sentinel.info.response | 71 + plugins/inputs/registry.go | 14 + plugins/inputs/rethinkdb/README.md | 70 + plugins/inputs/rethinkdb/rethinkdb.go | 92 + plugins/inputs/rethinkdb/rethinkdb_data.go | 111 + .../inputs/rethinkdb/rethinkdb_data_test.go | 113 + plugins/inputs/rethinkdb/rethinkdb_server.go | 209 + .../inputs/rethinkdb/rethinkdb_server_test.go | 81 + plugins/inputs/rethinkdb/rethinkdb_test.go | 73 + plugins/inputs/rethinkdb/sample.conf | 16 + plugins/inputs/riak/README.md | 87 + plugins/inputs/riak/riak.go | 194 + plugins/inputs/riak/riak_test.go | 281 + plugins/inputs/riak/sample.conf | 4 + plugins/inputs/riemann_listener/README.md | 67 + .../riemann_listener/riemann_listener.go | 359 + .../riemann_listener/riemann_listener_test.go | 49 + plugins/inputs/riemann_listener/sample.conf | 27 + plugins/inputs/s7comm/README.md | 108 + plugins/inputs/s7comm/s7comm.go | 431 + plugins/inputs/s7comm/s7comm_test.go | 963 ++ plugins/inputs/s7comm/sample.conf | 59 + plugins/inputs/s7comm/type_conversions.go | 67 + plugins/inputs/salesforce/README.md | 68 + plugins/inputs/salesforce/salesforce.go | 233 + plugins/inputs/salesforce/salesforce_test.go | 519 + plugins/inputs/salesforce/sample.conf | 18 + plugins/inputs/sensors/README.md | 62 + plugins/inputs/sensors/sample.conf | 9 + plugins/inputs/sensors/sensors.go | 135 + plugins/inputs/sensors/sensors_notlinux.go | 33 + plugins/inputs/sensors/sensors_test.go | 382 + plugins/inputs/sflow/README.md | 140 + plugins/inputs/sflow/binaryio/minreader.go | 37 + .../inputs/sflow/binaryio/minreader_test.go | 39 + plugins/inputs/sflow/decoder_test.go | 840 + plugins/inputs/sflow/metricencoder.go | 43 + plugins/inputs/sflow/packetdecoder.go | 480 + plugins/inputs/sflow/packetdecoder_test.go | 205 + plugins/inputs/sflow/sample.conf | 11 + plugins/inputs/sflow/sflow.go | 139 + plugins/inputs/sflow/sflow_test.go | 156 + plugins/inputs/sflow/types.go | 297 + plugins/inputs/sflow/types_test.go | 43 + plugins/inputs/slab/README.md | 69 + plugins/inputs/slab/sample.conf | 5 + plugins/inputs/slab/slab.go | 113 + plugins/inputs/slab/slab_notlinux.go | 33 + plugins/inputs/slab/slab_test.go | 48 + plugins/inputs/slab/testdata/slabinfo | 23 + plugins/inputs/slurm/README.md | 197 + plugins/inputs/slurm/sample.conf | 46 + plugins/inputs/slurm/sample.conf.in | 23 + plugins/inputs/slurm/slurm.go | 476 + plugins/inputs/slurm/slurm_test.go | 161 + .../slurm/testcases/gather/expected.out | 11 + .../testcases/gather/responses/diag.json | 224 + .../testcases/gather/responses/jobs.json | 448 + .../testcases/gather/responses/nodes.json | 175 + .../gather/responses/partitions.json | 56 + .../gather/responses/reservations.json | 20 + .../slurm/testcases/gather/telegraf.conf | 8 + .../slurm/testcases/panic/responses/diag.json | 5 + .../slurm/testcases/panic/responses/jobs.json | 5 + .../testcases/panic/responses/nodes.json | 5 + .../testcases/panic/responses/partitions.json | 5 + .../panic/responses/reservations.json | 5 + .../slurm/testcases/panic/telegraf.conf | 8 + plugins/inputs/smart/README.md | 310 + plugins/inputs/smart/sample.conf | 53 + plugins/inputs/smart/smart.go | 1119 ++ plugins/inputs/smart/smart_test.go | 2624 +++ plugins/inputs/smartctl/README.md | 110 + plugins/inputs/smartctl/sample.conf | 30 + plugins/inputs/smartctl/smartctl.go | 93 + plugins/inputs/smartctl/smartctl_device.go | 196 + plugins/inputs/smartctl/smartctl_json.go | 156 + plugins/inputs/smartctl/smartctl_scan.go | 46 + plugins/inputs/smartctl/smartctl_test.go | 198 + .../smartctl/testcases_device/megaraid/device | 1 + .../testcases_device/megaraid/deviceType | 1 + .../testcases_device/megaraid/expected.out | 25 + .../testcases_device/megaraid/response.json | 733 + .../smartctl/testcases_device/nvme/device | 1 + .../smartctl/testcases_device/nvme/deviceType | 1 + .../testcases_device/nvme/expected.out | 1 + .../testcases_device/nvme/response.json | 145 + .../smartctl/testcases_device/scsi/device | 1 + .../smartctl/testcases_device/scsi/deviceType | 1 + .../testcases_device/scsi/expected.out | 4 + .../testcases_device/scsi/response.json | 96 + .../testcases_device/scsi_extended/device | 1 + .../testcases_device/scsi_extended/deviceType | 1 + .../scsi_extended/expected.out | 4 + .../scsi_extended/response.json | 196 + .../smartctl/testcases_device/usb/device | 1 + .../smartctl/testcases_device/usb/deviceType | 1 + .../testcases_device/usb/expected.out | 14 + .../testcases_device/usb/response.json | 486 + .../smartctl/testcases_scan/all/expected.out | 1 + .../smartctl/testcases_scan/all/response.json | 42 + .../smartctl/testcases_scan/all/telegraf.toml | 1 + .../testcases_scan/exclude/expected.out | 1 + .../testcases_scan/exclude/response.json | 42 + .../testcases_scan/exclude/telegraf.toml | 2 + .../testcases_scan/include/expected.out | 1 + .../testcases_scan/include/response.json | 42 + .../testcases_scan/include/telegraf.toml | 2 + .../testcases_scan/megaraid/expected.out | 1 + .../testcases_scan/megaraid/response.json | 83 + .../testcases_scan/megaraid/telegraf.toml | 1 + plugins/inputs/snmp/README.md | 418 + plugins/inputs/snmp/sample.conf | 87 + plugins/inputs/snmp/snmp.go | 206 + plugins/inputs/snmp/snmp_test.go | 801 + plugins/inputs/snmp_trap/README.md | 138 + plugins/inputs/snmp_trap/gosmi.go | 21 + plugins/inputs/snmp_trap/logger.go | 17 + plugins/inputs/snmp_trap/netsnmp.go | 91 + plugins/inputs/snmp_trap/sample.conf | 35 + plugins/inputs/snmp_trap/snmp_trap.go | 355 + plugins/inputs/snmp_trap/snmp_trap_test.go | 1574 ++ plugins/inputs/socket_listener/README.md | 207 + plugins/inputs/socket_listener/sample.conf | 96 + plugins/inputs/socket_listener/sample.conf.in | 24 + .../inputs/socket_listener/socket_listener.go | 106 + .../socket_listener/socket_listener_test.go | 524 + .../invalid_line_format/expected.err | 1 + .../invalid_line_format/expected.out | 3 + .../invalid_line_format/sequence.json | 14 + .../invalid_line_format/telegraf.conf | 3 + .../testcases/powerdns/dnsmessage.proto | 184 + .../testcases/powerdns/expected.out | 1 + .../testcases/powerdns/powerdns_message.bin | Bin 0 -> 103 bytes .../testcases/powerdns/sequence.json | 5 + .../testcases/powerdns/telegraf.conf | 17 + .../splitting_delimiter/expected.out | 3 + .../testcases/splitting_delimiter/message.bin | Bin 0 -> 90 bytes .../splitting_delimiter/sequence.json | 5 + .../splitting_delimiter/telegraf.conf | 5 + .../splitting_fixed_length/expected.out | 4 + .../splitting_fixed_length/sequence.json | 11 + .../splitting_fixed_length/telegraf.conf | 7 + .../testcases/splitting_newline/expected.out | 3 + .../testcases/splitting_newline/sequence.json | 5 + .../testcases/splitting_newline/telegraf.conf | 4 + .../testcases/splitting_null/expected.out | 3 + .../testcases/splitting_null/message.bin | Bin 0 -> 84 bytes .../testcases/splitting_null/sequence.json | 5 + .../testcases/splitting_null/telegraf.conf | 4 + .../splitting_variable_length/expected.out | 4 + .../splitting_variable_length/message_1.bin | Bin 0 -> 30 bytes .../splitting_variable_length/message_2.bin | Bin 0 -> 30 bytes .../splitting_variable_length/message_3.bin | Bin 0 -> 30 bytes .../splitting_variable_length/message_4.bin | Bin 0 -> 28 bytes .../splitting_variable_length/message_5.bin | 1 + .../splitting_variable_length/sequence.json | 20 + .../splitting_variable_length/telegraf.conf | 5 + .../testcases/timeout/sequence.json | 5 + .../testcases/timeout/telegraf.conf | 4 + plugins/inputs/socketstat/README.md | 79 + plugins/inputs/socketstat/sample.conf | 9 + plugins/inputs/socketstat/socketstat.go | 212 + plugins/inputs/socketstat/socketstat_test.go | 162 + .../inputs/socketstat/socketstat_windows.go | 32 + .../socketstat/testdata/tcp_no_sockets.txt | 1 + .../socketstat/testdata/tcp_traffic.txt | 7 + .../socketstat/testdata/udp_no_sockets.txt | 1 + .../socketstat/testdata/udp_traffic.txt | 4 + plugins/inputs/solr/README.md | 53 + plugins/inputs/solr/api.go | 263 + plugins/inputs/solr/sample.conf | 14 + plugins/inputs/solr/solr.go | 228 + plugins/inputs/solr/solr_test.go | 209 + .../solr/testcases/integration-v6.result | 23 + .../solr/testcases/integration-v7.result | 24 + .../solr/testcases/integration-v8.result | 23 + .../solr/testcases/integration-v9.result | 31 + .../testcases/no_core_data/admin/cores.json | 62 + .../no_core_data/core1/admin/mbeans.json | 1 + .../solr/testcases/no_core_data/expected.out | 2 + .../no_core_data/main/admin/mbeans.json | 1 + .../solr/testcases/no_core_data/telegraf.conf | 2 + .../solr/testcases/v3.5/admin/cores.json | 62 + .../testcases/v3.5/core1/admin/mbeans.json | 728 + .../inputs/solr/testcases/v3.5/expected.out | 74 + .../testcases/v3.5/main/admin/mbeans.json | 728 + .../inputs/solr/testcases/v3.5/telegraf.conf | 2 + .../solr/testcases/v4.3/admin/cores.json | 62 + .../testcases/v4.3/core1/admin/mbeans.json | 841 + .../inputs/solr/testcases/v4.3/expected.out | 78 + .../testcases/v4.3/main/admin/mbeans.json | 841 + .../inputs/solr/testcases/v4.3/telegraf.conf | 2 + .../inputs/solr/testcases/v7/admin/cores.json | 62 + plugins/inputs/solr/testcases/v7/expected.out | 3 + .../solr/testcases/v7/main/admin/mbeans.json | 38 + .../inputs/solr/testcases/v7/telegraf.conf | 2 + plugins/inputs/solr/types.go | 69 + plugins/inputs/solr/util.go | 26 + plugins/inputs/sql/README.md | 206 + plugins/inputs/sql/drivers.go | 13 + plugins/inputs/sql/drivers_sqlite.go | 8 + plugins/inputs/sql/sample.conf | 83 + plugins/inputs/sql/sql.go | 546 + plugins/inputs/sql/sql_test.go | 306 + .../sql/testdata/clickhouse/expected.sql | 15 + .../inputs/sql/testdata/mariadb/expected.sql | 36 + .../inputs/sql/testdata/postgres/expected.sql | 41 + plugins/inputs/sqlserver/README.md | 537 + .../inputs/sqlserver/azurearcsqlmiqueries.go | 515 + .../sqlserver/azurearcsqlmiqueries_test.go | 313 + plugins/inputs/sqlserver/azuresqldbqueries.go | 702 + .../sqlserver/azuresqldbqueries_test.go | 462 + .../sqlserver/azuresqlmanagedqueries.go | 572 + .../sqlserver/azuresqlmanagedqueries_test.go | 391 + .../inputs/sqlserver/azuresqlpoolqueries.go | 478 + .../sqlserver/azuresqlpoolqueries_test.go | 322 + plugins/inputs/sqlserver/azuretoken.go | 17 + plugins/inputs/sqlserver/connectionstring.go | 98 + plugins/inputs/sqlserver/sample.conf | 131 + plugins/inputs/sqlserver/sqlqueriesV1.go | 1409 ++ plugins/inputs/sqlserver/sqlqueriesV2.go | 1427 ++ plugins/inputs/sqlserver/sqlserver.go | 720 + plugins/inputs/sqlserver/sqlserver_test.go | 1609 ++ plugins/inputs/sqlserver/sqlserverqueries.go | 1482 ++ plugins/inputs/stackdriver/README.md | 185 + plugins/inputs/stackdriver/sample.conf | 92 + plugins/inputs/stackdriver/stackdriver.go | 707 + .../inputs/stackdriver/stackdriver_test.go | 1233 ++ plugins/inputs/statsd/README.md | 316 + plugins/inputs/statsd/datadog.go | 179 + plugins/inputs/statsd/datadog_test.go | 485 + plugins/inputs/statsd/running_stats.go | 150 + plugins/inputs/statsd/running_stats_test.go | 196 + plugins/inputs/statsd/sample.conf | 104 + plugins/inputs/statsd/statsd.go | 1095 ++ plugins/inputs/statsd/statsd_test.go | 2399 +++ plugins/inputs/supervisor/README.md | 111 + plugins/inputs/supervisor/sample.conf | 10 + plugins/inputs/supervisor/supervisor.go | 179 + plugins/inputs/supervisor/supervisor_test.go | 171 + .../supervisor/testdata/supervisord.conf | 22 + plugins/inputs/suricata/README.md | 194 + plugins/inputs/suricata/sample.conf | 26 + plugins/inputs/suricata/suricata.go | 352 + plugins/inputs/suricata/suricata_test.go | 570 + plugins/inputs/suricata/testdata/test1.json | 1 + plugins/inputs/suricata/testdata/test2.json | 21 + plugins/inputs/suricata/testdata/test3.json | 1 + .../inputs/suricata/testdata/v2/alert.json | 35 + plugins/inputs/suricata/testdata/v2/dns.json | 18 + plugins/inputs/suricata/testdata/v2/drop.json | 29 + plugins/inputs/suricata/testdata/v2/flow.json | 21 + plugins/inputs/suricata/testdata/v2/http.json | 22 + .../inputs/suricata/testdata/v2/status.json | 30 + plugins/inputs/swap/README.md | 40 + plugins/inputs/swap/sample.conf | 3 + plugins/inputs/swap/swap.go | 51 + plugins/inputs/swap/swap_test.go | 40 + plugins/inputs/synproxy/README.md | 63 + plugins/inputs/synproxy/sample.conf | 4 + plugins/inputs/synproxy/synproxy.go | 118 + plugins/inputs/synproxy/synproxy_notlinux.go | 33 + plugins/inputs/synproxy/synproxy_test.go | 168 + plugins/inputs/syslog/README.md | 268 + plugins/inputs/syslog/sample.conf | 75 + plugins/inputs/syslog/sample.conf.in | 39 + plugins/inputs/syslog/syslog.go | 333 + plugins/inputs/syslog/syslog_test.go | 357 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 4 + .../expected.out | 2 + .../input.txt | 2 + .../telegraf.conf | 4 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 5 + .../expected.out | 2 + .../input.txt | 2 + .../telegraf.conf | 5 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 4 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 5 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 3 + .../expected.out | 2 + .../input.txt | 2 + .../telegraf.conf | 3 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 4 + .../expected.out | 2 + .../input.txt | 2 + .../telegraf.conf | 4 + .../non_transparent_strict_unix/expected.out | 1 + .../non_transparent_strict_unix/input.txt | 1 + .../non_transparent_strict_unix/telegraf.conf | 3 + .../expected.out | 1 + .../non_transparent_strict_unixtls/input.txt | 1 + .../telegraf.conf | 4 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 3 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 3 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 3 + .../expected.out | 2 + .../input.txt | 1 + .../telegraf.conf | 3 + .../expected.out | 1 + .../input.txt | 2 + .../telegraf.conf | 3 + .../expected.err | 1 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 3 + .../expected.err | 1 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 3 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 3 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 4 + .../expected.out | 1 + .../octet_counting_best_effort_unix/input.txt | 1 + .../telegraf.conf | 3 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 4 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 2 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 2 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 2 + .../expected.out | 2 + .../input.txt | 1 + .../telegraf.conf | 2 + .../expected.out | 1 + .../input.txt | 2 + .../telegraf.conf | 2 + .../expected.err | 1 + .../input.txt | 1 + .../telegraf.conf | 2 + .../expected.err | 1 + .../input.txt | 1 + .../telegraf.conf | 2 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 2 + .../octet_counting_strict_tcptls/expected.out | 1 + .../octet_counting_strict_tcptls/input.txt | 1 + .../telegraf.conf | 3 + .../octet_counting_strict_unix/expected.out | 1 + .../octet_counting_strict_unix/input.txt | 1 + .../octet_counting_strict_unix/telegraf.conf | 2 + .../expected.out | 1 + .../octet_counting_strict_unixtls/input.txt | 1 + .../telegraf.conf | 3 + .../rfc3164_best_effort_udp/expected.out | 1 + .../rfc3164_best_effort_udp/input.txt | 1 + .../rfc3164_best_effort_udp/telegraf.conf | 4 + .../testcases/rfc3164_strict_udp/expected.out | 1 + .../testcases/rfc3164_strict_udp/input.txt | 1 + .../rfc3164_strict_udp/telegraf.conf | 3 + .../expected.err | 1 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 4 + .../rfc5424_best_effort_udp/expected.out | 1 + .../rfc5424_best_effort_udp/input.txt | 1 + .../rfc5424_best_effort_udp/telegraf.conf | 4 + .../expected.out | 1 + .../rfc5424_best_effort_udp_average/input.txt | 1 + .../telegraf.conf | 4 + .../rfc5424_best_effort_udp_max/expected.out | 1 + .../rfc5424_best_effort_udp_max/input.txt | 1 + .../rfc5424_best_effort_udp_max/telegraf.conf | 4 + .../expected.err | 1 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 4 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 4 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 4 + .../rfc5424_long_appname/expected.out | 1 + .../testcases/rfc5424_long_appname/input.txt | 1 + .../rfc5424_long_appname/telegraf.conf | 3 + .../expected.err | 1 + .../rfc5424_strict_toolong_appname/input.txt | 1 + .../telegraf.conf | 3 + .../testcases/rfc5424_strict_udp/expected.out | 1 + .../testcases/rfc5424_strict_udp/input.txt | 1 + .../rfc5424_strict_udp/telegraf.conf | 3 + .../rfc5424_strict_udp_average/expected.out | 1 + .../rfc5424_strict_udp_average/input.txt | 1 + .../rfc5424_strict_udp_average/telegraf.conf | 3 + .../rfc5424_strict_udp_max/expected.out | 1 + .../rfc5424_strict_udp_max/input.txt | 1 + .../rfc5424_strict_udp_max/telegraf.conf | 3 + .../expected.err | 1 + .../input.txt | 1 + .../telegraf.conf | 3 + .../expected.out | 1 + .../input.txt | 1 + .../telegraf.conf | 3 + .../expected.out | 1 + .../rfc5424_strict_udp_trim_message/input.txt | 1 + .../telegraf.conf | 3 + plugins/inputs/sysstat/README.md | 458 + plugins/inputs/sysstat/sample.conf | 53 + plugins/inputs/sysstat/sysstat.go | 317 + .../inputs/sysstat/sysstat_interval_test.go | 54 + plugins/inputs/sysstat/sysstat_notlinux.go | 33 + plugins/inputs/sysstat/sysstat_test.go | 328 + plugins/inputs/system/README.md | 54 + plugins/inputs/system/sample.conf | 3 + plugins/inputs/system/system.go | 117 + plugins/inputs/system/system_test.go | 64 + plugins/inputs/systemd_units/README.md | 218 + plugins/inputs/systemd_units/sample.conf | 29 + plugins/inputs/systemd_units/systemd_units.go | 467 + .../systemd_units/systemd_units_notlinux.go | 33 + .../systemd_units/systemd_units_test.go | 1049 ++ plugins/inputs/tacacs/README.md | 75 + plugins/inputs/tacacs/sample.conf | 15 + plugins/inputs/tacacs/tacacs.go | 209 + plugins/inputs/tacacs/tacacs_test.go | 389 + plugins/inputs/tail/README.md | 141 + plugins/inputs/tail/multiline.go | 194 + plugins/inputs/tail/multiline_test.go | 475 + plugins/inputs/tail/sample.conf | 87 + plugins/inputs/tail/tail.go | 525 + plugins/inputs/tail/tail_solaris.go | 36 + plugins/inputs/tail/tail_test.go | 1343 ++ .../inputs/tail/testdata/cpu-utf-16be.influx | Bin 0 -> 522 bytes .../inputs/tail/testdata/cpu-utf-16le.influx | Bin 0 -> 522 bytes plugins/inputs/tail/testdata/cpu-utf-8.influx | 5 + .../testdata/multiline_quoted_backticks.csv | 12 + .../tail/testdata/multiline_quoted_double.csv | 12 + .../testdata/multiline_quoted_messed_up.csv | 4 + .../multiline_quoted_missing_close.csv | 2 + .../tail/testdata/multiline_quoted_single.csv | 12 + plugins/inputs/tail/testdata/test-patterns | 3 + .../inputs/tail/testdata/test_multiline.log | 7 + plugins/inputs/teamspeak/README.md | 61 + plugins/inputs/teamspeak/sample.conf | 12 + plugins/inputs/teamspeak/teamspeak.go | 119 + plugins/inputs/teamspeak/teamspeak_test.go | 139 + plugins/inputs/temp/README.md | 61 + plugins/inputs/temp/sample.conf | 10 + plugins/inputs/temp/temp.go | 28 + plugins/inputs/temp/temp_linux.go | 249 + plugins/inputs/temp/temp_notlinux.go | 47 + plugins/inputs/temp/temp_test.go | 344 + .../temp/testcases/general/expected_v1.out | 13 + .../temp/testcases/general/expected_v2.out | 5 + .../general/sys/class/hwmon/hwmon0/name | 1 + .../sys/class/hwmon/hwmon0/temp1_alarm | 1 + .../general/sys/class/hwmon/hwmon0/temp1_crit | 1 + .../sys/class/hwmon/hwmon0/temp1_input | 1 + .../sys/class/hwmon/hwmon0/temp1_label | 1 + .../general/sys/class/hwmon/hwmon0/temp1_max | 1 + .../general/sys/class/hwmon/hwmon0/temp1_min | 1 + .../sys/class/hwmon/hwmon0/temp2_input | 1 + .../sys/class/hwmon/hwmon0/temp2_label | 1 + .../general/sys/class/hwmon/hwmon0/temp2_max | 1 + .../general/sys/class/hwmon/hwmon0/temp2_min | 1 + .../sys/class/hwmon/hwmon0/temp3_input | 1 + .../sys/class/hwmon/hwmon0/temp3_label | 1 + .../general/sys/class/hwmon/hwmon0/temp3_max | 1 + .../general/sys/class/hwmon/hwmon0/temp3_min | 1 + .../general/sys/class/hwmon/hwmon1/name | 1 + .../sys/class/hwmon/hwmon1/temp1_input | 1 + .../sys/class/hwmon/hwmon1/temp1_label | 1 + .../sys/class/hwmon/hwmon1/temp3_input | 1 + .../sys/class/hwmon/hwmon1/temp3_label | 1 + .../general/sys/class/hwmon/hwmon1/uevent | 0 .../temp/testcases/general/telegraf.conf | 2 + .../testcases/with_device_tag/expected_v1.out | 24 + .../testcases/with_device_tag/expected_v2.out | 8 + .../sys/class/hwmon/hwmon0/device | 1 + .../sys/class/hwmon/hwmon0/name | 1 + .../sys/class/hwmon/hwmon0/temp1_alarm | 1 + .../sys/class/hwmon/hwmon0/temp1_crit | 1 + .../sys/class/hwmon/hwmon0/temp1_input | 1 + .../sys/class/hwmon/hwmon0/temp1_label | 1 + .../sys/class/hwmon/hwmon0/temp1_max | 1 + .../sys/class/hwmon/hwmon0/temp1_min | 1 + .../sys/class/hwmon/hwmon0/temp2_input | 1 + .../sys/class/hwmon/hwmon0/temp2_label | 1 + .../sys/class/hwmon/hwmon0/temp2_max | 1 + .../sys/class/hwmon/hwmon0/temp2_min | 1 + .../sys/class/hwmon/hwmon0/temp3_input | 1 + .../sys/class/hwmon/hwmon0/temp3_label | 1 + .../sys/class/hwmon/hwmon0/temp3_max | 1 + .../sys/class/hwmon/hwmon0/temp3_min | 1 + .../sys/class/hwmon/hwmon0/uevent | 0 .../sys/class/hwmon/hwmon1/device | 1 + .../sys/class/hwmon/hwmon1/name | 1 + .../sys/class/hwmon/hwmon1/temp1_alarm | 1 + .../sys/class/hwmon/hwmon1/temp1_crit | 1 + .../sys/class/hwmon/hwmon1/temp1_input | 1 + .../sys/class/hwmon/hwmon1/temp1_label | 1 + .../sys/class/hwmon/hwmon1/temp1_max | 1 + .../sys/class/hwmon/hwmon1/temp1_min | 1 + .../sys/class/hwmon/hwmon1/temp2_input | 1 + .../sys/class/hwmon/hwmon1/temp2_label | 1 + .../sys/class/hwmon/hwmon1/temp2_max | 1 + .../sys/class/hwmon/hwmon1/temp2_min | 1 + .../sys/class/hwmon/hwmon1/temp3_input | 1 + .../sys/class/hwmon/hwmon1/temp3_label | 1 + .../sys/class/hwmon/hwmon1/temp3_max | 1 + .../sys/class/hwmon/hwmon1/temp3_min | 1 + .../sys/class/hwmon/hwmon1/uevent | 0 .../sys/class/hwmon/hwmon2/device | 1 + .../sys/class/hwmon/hwmon2/name | 1 + .../sys/class/hwmon/hwmon2/temp1_input | 1 + .../sys/class/hwmon/hwmon2/temp1_label | 1 + .../sys/class/hwmon/hwmon2/temp3_input | 1 + .../sys/class/hwmon/hwmon2/temp3_label | 1 + .../sys/class/hwmon/hwmon2/uevent | 0 .../testcases/with_device_tag/telegraf.conf | 3 + .../temp/testcases/with_name/expected_v1.out | 24 + .../temp/testcases/with_name/expected_v2.out | 8 + .../with_name/sys/class/hwmon/hwmon0/device | 1 + .../with_name/sys/class/hwmon/hwmon0/name | 1 + .../sys/class/hwmon/hwmon0/temp1_alarm | 1 + .../sys/class/hwmon/hwmon0/temp1_crit | 1 + .../sys/class/hwmon/hwmon0/temp1_input | 1 + .../sys/class/hwmon/hwmon0/temp1_label | 1 + .../sys/class/hwmon/hwmon0/temp1_max | 1 + .../sys/class/hwmon/hwmon0/temp1_min | 1 + .../sys/class/hwmon/hwmon0/temp2_input | 1 + .../sys/class/hwmon/hwmon0/temp2_label | 1 + .../sys/class/hwmon/hwmon0/temp2_max | 1 + .../sys/class/hwmon/hwmon0/temp2_min | 1 + .../sys/class/hwmon/hwmon0/temp3_input | 1 + .../sys/class/hwmon/hwmon0/temp3_label | 1 + .../sys/class/hwmon/hwmon0/temp3_max | 1 + .../sys/class/hwmon/hwmon0/temp3_min | 1 + .../with_name/sys/class/hwmon/hwmon0/uevent | 0 .../with_name/sys/class/hwmon/hwmon1/device | 1 + .../with_name/sys/class/hwmon/hwmon1/name | 1 + .../sys/class/hwmon/hwmon1/temp1_alarm | 1 + .../sys/class/hwmon/hwmon1/temp1_crit | 1 + .../sys/class/hwmon/hwmon1/temp1_input | 1 + .../sys/class/hwmon/hwmon1/temp1_label | 1 + .../sys/class/hwmon/hwmon1/temp1_max | 1 + .../sys/class/hwmon/hwmon1/temp1_min | 1 + .../sys/class/hwmon/hwmon1/temp2_input | 1 + .../sys/class/hwmon/hwmon1/temp2_label | 1 + .../sys/class/hwmon/hwmon1/temp2_max | 1 + .../sys/class/hwmon/hwmon1/temp2_min | 1 + .../sys/class/hwmon/hwmon1/temp3_input | 1 + .../sys/class/hwmon/hwmon1/temp3_label | 1 + .../sys/class/hwmon/hwmon1/temp3_max | 1 + .../sys/class/hwmon/hwmon1/temp3_min | 1 + .../with_name/sys/class/hwmon/hwmon1/uevent | 0 .../with_name/sys/class/hwmon/hwmon2/device | 1 + .../with_name/sys/class/hwmon/hwmon2/name | 1 + .../sys/class/hwmon/hwmon2/temp1_input | 1 + .../sys/class/hwmon/hwmon2/temp1_label | 1 + .../sys/class/hwmon/hwmon2/temp3_input | 1 + .../sys/class/hwmon/hwmon2/temp3_label | 1 + .../with_name/sys/class/hwmon/hwmon2/uevent | 0 .../temp/testcases/with_name/telegraf.conf | 2 + plugins/inputs/tengine/README.md | 81 + plugins/inputs/tengine/sample.conf | 14 + plugins/inputs/tengine/tengine.go | 325 + plugins/inputs/tengine/tengine_test.go | 99 + plugins/inputs/tomcat/README.md | 89 + plugins/inputs/tomcat/sample.conf | 18 + plugins/inputs/tomcat/tomcat.go | 206 + plugins/inputs/tomcat/tomcat_test.go | 174 + plugins/inputs/trig/README.md | 36 + plugins/inputs/trig/sample.conf | 4 + plugins/inputs/trig/trig.go | 42 + plugins/inputs/trig/trig_test.go | 31 + plugins/inputs/twemproxy/README.md | 28 + plugins/inputs/twemproxy/sample.conf | 6 + plugins/inputs/twemproxy/twemproxy.go | 128 + plugins/inputs/twemproxy/twemproxy_test.go | 176 + plugins/inputs/unbound/README.md | 171 + plugins/inputs/unbound/sample.conf | 24 + plugins/inputs/unbound/unbound.go | 189 + plugins/inputs/unbound/unbound_test.go | 292 + plugins/inputs/upsd/README.md | 111 + plugins/inputs/upsd/sample.conf | 26 + .../expected.out | 1 + .../telegraf.conf | 1 + .../CyberPowerSystems_CP900EPFCLCD/types.dev | 49 + .../variables.dev | 49 + .../expected.out | 1 + .../telegraf.conf | 2 + .../types.dev | 49 + .../variables.dev | 49 + .../expected.out | 1 + .../telegraf.conf | 2 + .../types.dev | 49 + .../variables.dev | 49 + .../inputs/upsd/testcases/fake/expected.out | 1 + .../inputs/upsd/testcases/fake/telegraf.conf | 1 + plugins/inputs/upsd/testcases/fake/types.dev | 15 + .../inputs/upsd/testcases/fake/variables.dev | 15 + .../testcases/fake_force_float/expected.out | 1 + .../testcases/fake_force_float/telegraf.conf | 2 + .../upsd/testcases/fake_force_float/types.dev | 15 + .../testcases/fake_force_float/variables.dev | 15 + .../fake_force_float_with_string/expected.out | 1 + .../telegraf.conf | 3 + .../fake_force_float_with_string/types.dev | 16 + .../variables.dev | 16 + plugins/inputs/upsd/upsd.go | 284 + plugins/inputs/upsd/upsd_test.go | 295 + plugins/inputs/uwsgi/README.md | 100 + plugins/inputs/uwsgi/sample.conf | 11 + plugins/inputs/uwsgi/uwsgi.go | 282 + plugins/inputs/uwsgi/uwsgi_test.go | 197 + plugins/inputs/varnish/README.md | 654 + plugins/inputs/varnish/sample.conf | 39 + .../inputs/varnish/test_data/varnish4_4.json | 1478 ++ .../test_data/varnish6.2.1_reload.json | 2173 +++ .../inputs/varnish/test_data/varnish6.6.json | 2154 +++ .../varnish/test_data/varnish_types.json | 24 + .../varnish/test_data/varnish_v1_reload.txt | 474 + .../varnish/test_data/varnishadm-200.json | 10 + .../varnish/test_data/varnishadm-reload.json | 51 + plugins/inputs/varnish/varnish.go | 412 + plugins/inputs/varnish/varnish_test.go | 634 + plugins/inputs/varnish/varnish_windows.go | 30 + plugins/inputs/vault/README.md | 50 + plugins/inputs/vault/sample.conf | 19 + .../vault/testdata/response_key_metrics.json | 40 + plugins/inputs/vault/vault.go | 198 + plugins/inputs/vault/vault_metrics.go | 40 + plugins/inputs/vault/vault_test.go | 228 + plugins/inputs/vsphere/METRICS.md | 355 + plugins/inputs/vsphere/README.md | 1028 ++ plugins/inputs/vsphere/client.go | 361 + plugins/inputs/vsphere/endpoint.go | 1462 ++ plugins/inputs/vsphere/finder.go | 276 + plugins/inputs/vsphere/sample.conf | 215 + plugins/inputs/vsphere/selfhealth.go | 42 + plugins/inputs/vsphere/throttled_exec.go | 44 + plugins/inputs/vsphere/tscache.go | 61 + plugins/inputs/vsphere/vsan.go | 543 + plugins/inputs/vsphere/vsphere.go | 181 + plugins/inputs/vsphere/vsphere_test.go | 615 + plugins/inputs/webhooks/README.md | 118 + plugins/inputs/webhooks/artifactory/README.md | 528 + .../artifactory/artifactory_webhook.go | 122 + .../artifactory_webhook_mock_json_test.go | 439 + .../artifactory/artifactory_webhook_models.go | 255 + .../artifactory/artifactory_webhook_test.go | 163 + plugins/inputs/webhooks/filestack/README.md | 22 + .../webhooks/filestack/filestack_webhooks.go | 55 + .../filestack/filestack_webhooks_events.go | 21 + .../filestack/filestack_webhooks_test.go | 86 + .../filestack/testdata/dialog_open.json | 39 + .../webhooks/filestack/testdata/upload.json | 12 + .../filestack/testdata/video_conversion.json | 51 + plugins/inputs/webhooks/github/README.md | 456 + .../inputs/webhooks/github/github_webhooks.go | 150 + .../github/github_webhooks_mock_json_test.go | 3572 +++++ .../webhooks/github/github_webhooks_models.go | 739 + .../webhooks/github/github_webhooks_test.go | 147 + plugins/inputs/webhooks/mandrill/README.md | 22 + .../webhooks/mandrill/mandrill_webhooks.go | 67 + .../mandrill/mandrill_webhooks_events.go | 19 + .../mandrill/mandrill_webhooks_test.go | 97 + .../mandrill/testdata/hard_bounce_event.json | 23 + .../mandrill/testdata/send_event.json | 26 + plugins/inputs/webhooks/papertrail/README.md | 49 + .../webhooks/papertrail/papertrail_test.go | 207 + .../papertrail/papertrail_webhooks.go | 97 + .../papertrail/papertrail_webhooks_models.go | 41 + plugins/inputs/webhooks/particle/README.md | 45 + .../webhooks/particle/particle_webhooks.go | 83 + .../particle/particle_webhooks_test.go | 144 + plugins/inputs/webhooks/rollbar/README.md | 64 + .../webhooks/rollbar/rollbar_webhooks.go | 82 + .../rollbar/rollbar_webhooks_events.go | 115 + .../rollbar_webhooks_events_json_test.go | 160 + .../webhooks/rollbar/rollbar_webhooks_test.go | 98 + plugins/inputs/webhooks/sample.conf | 55 + plugins/inputs/webhooks/webhooks.go | 136 + plugins/inputs/webhooks/webhooks_test.go | 64 + plugins/inputs/win_eventlog/README.md | 300 + plugins/inputs/win_eventlog/event.go | 82 + plugins/inputs/win_eventlog/sample.conf | 102 + .../inputs/win_eventlog/syscall_windows.go | 36 + plugins/inputs/win_eventlog/util.go | 148 + plugins/inputs/win_eventlog/util_test.go | 198 + plugins/inputs/win_eventlog/win_eventlog.go | 604 + .../win_eventlog/win_eventlog_notwindows.go | 33 + .../inputs/win_eventlog/win_eventlog_test.go | 133 + .../inputs/win_eventlog/zsyscall_windows.go | 250 + plugins/inputs/win_perf_counters/README.md | 726 + plugins/inputs/win_perf_counters/kernel32.go | 56 + plugins/inputs/win_perf_counters/pdh.go | 636 + plugins/inputs/win_perf_counters/pdh_386.go | 126 + plugins/inputs/win_perf_counters/pdh_amd64.go | 115 + plugins/inputs/win_perf_counters/pdh_arm64.go | 115 + .../win_perf_counters/performance_query.go | 333 + plugins/inputs/win_perf_counters/sample.conf | 170 + .../win_perf_counters/win_perf_counters.go | 633 + .../win_perf_counters_integration_test.go | 563 + .../win_perf_counters_notwindows.go | 33 + .../win_perf_counters_test.go | 2100 +++ plugins/inputs/win_services/README.md | 91 + plugins/inputs/win_services/sample.conf | 13 + plugins/inputs/win_services/win_services.go | 248 + .../win_services_integration_test.go | 78 + .../win_services/win_services_notwindows.go | 33 + .../inputs/win_services/win_services_test.go | 240 + plugins/inputs/win_wmi/README.md | 383 + plugins/inputs/win_wmi/method.go | 228 + plugins/inputs/win_wmi/query.go | 191 + plugins/inputs/win_wmi/sample.conf | 36 + plugins/inputs/win_wmi/win_wmi.go | 78 + plugins/inputs/win_wmi/win_wmi_notwindows.go | 31 + plugins/inputs/win_wmi/win_wmi_test.go | 119 + plugins/inputs/wireguard/README.md | 85 + plugins/inputs/wireguard/sample.conf | 5 + plugins/inputs/wireguard/wireguard.go | 142 + plugins/inputs/wireguard/wireguard_test.go | 147 + plugins/inputs/wireless/README.md | 51 + plugins/inputs/wireless/sample.conf | 6 + plugins/inputs/wireless/wireless.go | 27 + plugins/inputs/wireless/wireless_linux.go | 120 + plugins/inputs/wireless/wireless_notlinux.go | 23 + plugins/inputs/wireless/wireless_test.go | 56 + plugins/inputs/x509_cert/README.md | 102 + plugins/inputs/x509_cert/java_key_store.go | 101 + .../inputs/x509_cert/java_key_store_test.go | 201 + plugins/inputs/x509_cert/sample.conf | 38 + plugins/inputs/x509_cert/x509_cert.go | 546 + plugins/inputs/x509_cert/x509_cert_test.go | 682 + plugins/inputs/xtremio/README.md | 128 + plugins/inputs/xtremio/sample.conf | 18 + .../xtremio/testdata/sample_bbu_response.json | 20 + .../testdata/sample_get_bbu_response.json | 15 + plugins/inputs/xtremio/xtremio.go | 382 + plugins/inputs/xtremio/xtremio_test.go | 225 + plugins/inputs/xtremio/xtremio_types.go | 98 + plugins/inputs/zfs/README.md | 418 + plugins/inputs/zfs/sample.conf | 20 + .../zfs/testcases/freebsd/cache/expected.out | 1 + .../zfs/testcases/freebsd/cache/sysctl.json | 12 + .../zfs/testcases/freebsd/cache/telegraf.conf | 2 + .../zfs/testcases/freebsd/cache/zdataset.txt | 0 .../zfs/testcases/freebsd/cache/zpool.txt | 4 + .../freebsd/cache_poolmetrics/expected.out | 5 + .../freebsd/cache_poolmetrics/sysctl.json | 12 + .../freebsd/cache_poolmetrics/telegraf.conf | 3 + .../freebsd/cache_poolmetrics/zdataset.txt | 0 .../freebsd/cache_poolmetrics/zpool.txt | 4 + .../testcases/freebsd/dataset/expected.out | 1 + .../zfs/testcases/freebsd/dataset/sysctl.json | 12 + .../testcases/freebsd/dataset/telegraf.conf | 2 + .../testcases/freebsd/dataset/zdataset.txt | 4 + .../zfs/testcases/freebsd/dataset/zpool.txt | 0 .../dataset_datasetmetrics/expected.out | 5 + .../dataset_datasetmetrics/sysctl.json | 12 + .../dataset_datasetmetrics/telegraf.conf | 3 + .../dataset_datasetmetrics/zdataset.txt | 4 + .../freebsd/dataset_datasetmetrics/zpool.txt | 0 .../testcases/freebsd/freebsd14/expected.out | 16 + .../testcases/freebsd/freebsd14/sysctl.json | 159 + .../testcases/freebsd/freebsd14/telegraf.conf | 4 + .../zfs/testcases/freebsd/freebsd14/uname.txt | 1 + .../testcases/freebsd/freebsd14/zdataset.txt | 14 + .../zfs/testcases/freebsd/freebsd14/zpool.txt | 1 + .../testcases/freebsd/freenas/expected.out | 1 + .../zfs/testcases/freebsd/freenas/sysctl.json | 12 + .../testcases/freebsd/freenas/telegraf.conf | 2 + .../testcases/freebsd/freenas/zdataset.txt | 0 .../zfs/testcases/freebsd/freenas/zpool.txt | 4 + .../freebsd/freenas_zfetchstats/expected.out | 1 + .../freebsd/freenas_zfetchstats/sysctl.json | 12 + .../freebsd/freenas_zfetchstats/telegraf.conf | 2 + .../freebsd/freenas_zfetchstats/zdataset.txt | 0 .../freebsd/freenas_zfetchstats/zpool.txt | 4 + .../freebsd/unavailable/expected.out | 1 + .../testcases/freebsd/unavailable/sysctl.json | 12 + .../freebsd/unavailable/telegraf.conf | 2 + .../freebsd/unavailable/zdataset.txt | 0 .../testcases/freebsd/unavailable/zpool.txt | 1 + .../unavailable_poolmetrics/expected.out | 2 + .../unavailable_poolmetrics/sysctl.json | 12 + .../unavailable_poolmetrics/telegraf.conf | 3 + .../unavailable_poolmetrics/zdataset.txt | 0 .../freebsd/unavailable_poolmetrics/zpool.txt | 1 + plugins/inputs/zfs/zfs.go | 25 + plugins/inputs/zfs/zfs_freebsd.go | 274 + plugins/inputs/zfs/zfs_freebsd_test.go | 104 + plugins/inputs/zfs/zfs_linux.go | 245 + plugins/inputs/zfs/zfs_linux_test.go | 609 + plugins/inputs/zfs/zfs_other.go | 25 + plugins/inputs/zipkin/README.md | 215 + .../stress_test_write/stress_test_write.go | 81 + .../cmd/thrift_serialize/thrift_serialize.go | 148 + plugins/inputs/zipkin/codec/codec.go | 227 + plugins/inputs/zipkin/codec/codec_test.go | 613 + plugins/inputs/zipkin/codec/jsonV1/jsonV1.go | 271 + .../inputs/zipkin/codec/jsonV1/jsonV1_test.go | 894 ++ .../gen-go/zipkincore/GoUnusedProtection__.go | 5 + .../gen-go/zipkincore/zipkinCore-consts.go | 48 + .../thrift/gen-go/zipkincore/zipkinCore.go | 1564 ++ plugins/inputs/zipkin/codec/thrift/thrift.go | 220 + .../inputs/zipkin/codec/thrift/thrift_test.go | 206 + plugins/inputs/zipkin/convert.go | 79 + plugins/inputs/zipkin/convert_test.go | 348 + plugins/inputs/zipkin/handler.go | 141 + plugins/inputs/zipkin/handler_test.go | 133 + plugins/inputs/zipkin/sample.conf | 12 + .../zipkin/testdata/cli_microservice.dat | Bin 0 -> 3937 bytes .../testdata/distributed_trace_sample.dat | Bin 0 -> 191 bytes .../testdata/json/brave-tracer-example.json | 188 + .../testdata/json/cli_microservice.json | 407 + .../json/distributed_trace_sample.json | 30 + .../zipkin/testdata/json/threespans.json | 92 + plugins/inputs/zipkin/testdata/threespans.dat | Bin 0 -> 616 bytes plugins/inputs/zipkin/trace/trace.go | 41 + plugins/inputs/zipkin/zipkin.go | 150 + plugins/inputs/zipkin/zipkin_test.go | 662 + plugins/inputs/zookeeper/README.md | 107 + .../inputs/zookeeper/dev/docker-compose.yml | 17 + plugins/inputs/zookeeper/dev/telegraf.conf | 9 + plugins/inputs/zookeeper/sample.conf | 25 + plugins/inputs/zookeeper/zookeeper.go | 173 + plugins/inputs/zookeeper/zookeeper_test.go | 87 + plugins/outputs/all/all.go | 1 + plugins/outputs/all/amon.go | 5 + plugins/outputs/all/amqp.go | 5 + plugins/outputs/all/application_insights.go | 5 + plugins/outputs/all/azure_data_explorer.go | 5 + plugins/outputs/all/azure_monitor.go | 5 + plugins/outputs/all/bigquery.go | 5 + plugins/outputs/all/clarify.go | 5 + plugins/outputs/all/cloud_pubsub.go | 5 + plugins/outputs/all/cloudwatch.go | 5 + plugins/outputs/all/cloudwatch_logs.go | 5 + plugins/outputs/all/cratedb.go | 5 + plugins/outputs/all/datadog.go | 5 + plugins/outputs/all/discard.go | 5 + plugins/outputs/all/dynatrace.go | 5 + plugins/outputs/all/elasticsearch.go | 5 + plugins/outputs/all/event_hubs.go | 5 + plugins/outputs/all/exec.go | 5 + plugins/outputs/all/execd.go | 5 + plugins/outputs/all/file.go | 5 + plugins/outputs/all/graphite.go | 5 + plugins/outputs/all/graylog.go | 5 + plugins/outputs/all/groundwork.go | 5 + plugins/outputs/all/health.go | 5 + plugins/outputs/all/http.go | 5 + plugins/outputs/all/influxdb.go | 5 + plugins/outputs/all/influxdb_v2.go | 5 + plugins/outputs/all/instrumental.go | 5 + plugins/outputs/all/iotdb.go | 5 + plugins/outputs/all/kafka.go | 5 + plugins/outputs/all/kinesis.go | 5 + plugins/outputs/all/librato.go | 5 + plugins/outputs/all/logzio.go | 5 + plugins/outputs/all/loki.go | 5 + plugins/outputs/all/mongodb.go | 5 + plugins/outputs/all/mqtt.go | 5 + plugins/outputs/all/nats.go | 5 + .../outputs/all/nebius_cloud_monitoring.go | 5 + plugins/outputs/all/newrelic.go | 5 + plugins/outputs/all/nsq.go | 5 + plugins/outputs/all/opensearch.go | 5 + plugins/outputs/all/opentelemetry.go | 5 + plugins/outputs/all/opentsdb.go | 5 + plugins/outputs/all/parquet.go | 5 + plugins/outputs/all/postgresql.go | 5 + plugins/outputs/all/prometheus_client.go | 5 + plugins/outputs/all/quix.go | 5 + plugins/outputs/all/redistimeseries.go | 5 + plugins/outputs/all/remotefile.go | 5 + plugins/outputs/all/riemann.go | 5 + plugins/outputs/all/sensu.go | 5 + plugins/outputs/all/signalfx.go | 5 + plugins/outputs/all/socket_writer.go | 5 + plugins/outputs/all/sql.go | 5 + plugins/outputs/all/stackdriver.go | 5 + plugins/outputs/all/stomp.go | 5 + plugins/outputs/all/sumologic.go | 5 + plugins/outputs/all/syslog.go | 5 + plugins/outputs/all/timestream.go | 5 + plugins/outputs/all/warp10.go | 5 + plugins/outputs/all/wavefront.go | 5 + plugins/outputs/all/websocket.go | 5 + .../outputs/all/yandex_cloud_monitoring.go | 5 + plugins/outputs/all/zabbix.go | 5 + plugins/outputs/amon/README.md | 44 + plugins/outputs/amon/amon.go | 151 + plugins/outputs/amon/amon_test.go | 89 + plugins/outputs/amon/sample.conf | 10 + plugins/outputs/amqp/README.md | 146 + plugins/outputs/amqp/amqp.go | 334 + plugins/outputs/amqp/amqp_test.go | 160 + plugins/outputs/amqp/client.go | 146 + plugins/outputs/amqp/sample.conf | 87 + .../outputs/application_insights/README.md | 69 + .../application_insights.go | 321 + .../application_insights_test.go | 462 + .../diagnostic_message_subscriber.go | 12 + .../mocks/diagnostics_message_listener.go | 12 + .../mocks/diagnostics_message_subscriber.go | 28 + .../application_insights/mocks/transmitter.go | 33 + .../outputs/application_insights/sample.conf | 25 + .../application_insights/transmitter.go | 27 + plugins/outputs/azure_data_explorer/README.md | 300 + .../azure_data_explorer.go | 118 + .../azure_data_explorer_test.go | 30 + .../outputs/azure_data_explorer/sample.conf | 31 + plugins/outputs/azure_monitor/README.md | 206 + .../outputs/azure_monitor/azure_monitor.go | 597 + .../azure_monitor/azure_monitor_test.go | 619 + plugins/outputs/azure_monitor/sample.conf | 37 + plugins/outputs/azure_monitor/types.go | 60 + plugins/outputs/bigquery/README.md | 126 + plugins/outputs/bigquery/bigquery.go | 323 + plugins/outputs/bigquery/bigquery_test.go | 304 + plugins/outputs/bigquery/sample.conf | 19 + plugins/outputs/clarify/README.md | 90 + plugins/outputs/clarify/clarify.go | 191 + plugins/outputs/clarify/clarify_test.go | 318 + plugins/outputs/clarify/sample.conf | 15 + plugins/outputs/cloud_pubsub/README.md | 82 + plugins/outputs/cloud_pubsub/cloud_pubsub.go | 288 + .../outputs/cloud_pubsub/cloud_pubsub_test.go | 240 + plugins/outputs/cloud_pubsub/sample.conf | 57 + plugins/outputs/cloud_pubsub/topic_gcp.go | 45 + plugins/outputs/cloud_pubsub/topic_stubbed.go | 238 + plugins/outputs/cloudwatch/README.md | 135 + plugins/outputs/cloudwatch/cloudwatch.go | 425 + plugins/outputs/cloudwatch/cloudwatch_test.go | 158 + plugins/outputs/cloudwatch/sample.conf | 49 + plugins/outputs/cloudwatch_logs/README.md | 114 + .../cloudwatch_logs/cloudwatch_logs.go | 405 + .../cloudwatch_logs/cloudwatch_logs_test.go | 584 + plugins/outputs/cloudwatch_logs/sample.conf | 60 + plugins/outputs/cratedb/README.md | 79 + plugins/outputs/cratedb/cratedb.go | 262 + plugins/outputs/cratedb/cratedb_test.go | 312 + plugins/outputs/cratedb/sample.conf | 18 + plugins/outputs/datadog/README.md | 70 + plugins/outputs/datadog/datadog.go | 284 + plugins/outputs/datadog/datadog_test.go | 901 ++ plugins/outputs/datadog/sample.conf | 27 + plugins/outputs/deprecations.go | 12 + plugins/outputs/discard/README.md | 25 + plugins/outputs/discard/discard.go | 28 + plugins/outputs/discard/sample.conf | 3 + plugins/outputs/dynatrace/README.md | 256 + plugins/outputs/dynatrace/dynatrace.go | 281 + plugins/outputs/dynatrace/dynatrace_test.go | 901 ++ plugins/outputs/dynatrace/sample.conf | 44 + plugins/outputs/elasticsearch/README.md | 442 + .../outputs/elasticsearch/elasticsearch.go | 546 + .../elasticsearch/elasticsearch_test.go | 850 + plugins/outputs/elasticsearch/sample.conf | 98 + plugins/outputs/event_hubs/README.md | 58 + plugins/outputs/event_hubs/event_hubs.go | 165 + plugins/outputs/event_hubs/event_hubs_test.go | 249 + plugins/outputs/event_hubs/sample.conf | 27 + .../outputs/event_hubs/testdata/Config.json | 24 + plugins/outputs/exec/README.md | 54 + plugins/outputs/exec/exec.go | 190 + plugins/outputs/exec/exec_test.go | 185 + plugins/outputs/exec/sample.conf | 23 + plugins/outputs/execd/README.md | 65 + plugins/outputs/execd/examples/file/file.sh | 5 + .../outputs/execd/examples/file/telegraf.conf | 9 + .../execd/examples/redis/redis_influx.rb | 19 + .../execd/examples/redis/redis_json.rb | 21 + .../execd/examples/redis/telegraf.conf | 15 + plugins/outputs/execd/execd.go | 134 + plugins/outputs/execd/execd_test.go | 264 + plugins/outputs/execd/sample.conf | 30 + plugins/outputs/file/README.md | 64 + plugins/outputs/file/file.go | 142 + plugins/outputs/file/file_test.go | 346 + plugins/outputs/file/sample.conf | 40 + plugins/outputs/graphite/README.md | 82 + plugins/outputs/graphite/graphite.go | 306 + plugins/outputs/graphite/graphite_test.go | 770 + plugins/outputs/graphite/sample.conf | 56 + plugins/outputs/graylog/README.md | 79 + plugins/outputs/graylog/graylog.go | 538 + plugins/outputs/graylog/graylog_test.go | 51 + plugins/outputs/graylog/graylog_test_linux.go | 462 + plugins/outputs/graylog/sample.conf | 33 + plugins/outputs/groundwork/README.md | 92 + plugins/outputs/groundwork/groundwork.go | 384 + plugins/outputs/groundwork/groundwork_test.go | 401 + plugins/outputs/groundwork/log_adapter.go | 87 + plugins/outputs/groundwork/sample.conf | 26 + plugins/outputs/health/README.md | 92 + plugins/outputs/health/compares.go | 76 + plugins/outputs/health/compares_test.go | 269 + plugins/outputs/health/contains.go | 19 + plugins/outputs/health/contains_test.go | 69 + plugins/outputs/health/health.go | 233 + plugins/outputs/health/health_test.go | 216 + plugins/outputs/health/sample.conf | 42 + plugins/outputs/http/README.md | 167 + plugins/outputs/http/http.go | 285 + plugins/outputs/http/http_test.go | 819 + plugins/outputs/http/sample.conf | 112 + plugins/outputs/influxdb/README.md | 129 + plugins/outputs/influxdb/http.go | 594 + plugins/outputs/influxdb/http_test.go | 1258 ++ plugins/outputs/influxdb/influxdb.go | 296 + plugins/outputs/influxdb/influxdb_test.go | 555 + plugins/outputs/influxdb/sample.conf | 87 + plugins/outputs/influxdb/udp.go | 145 + plugins/outputs/influxdb/udp_test.go | 270 + plugins/outputs/influxdb_v2/README.md | 116 + plugins/outputs/influxdb_v2/http.go | 434 + plugins/outputs/influxdb_v2/http_test.go | 269 + plugins/outputs/influxdb_v2/influxdb_v2.go | 221 + .../outputs/influxdb_v2/influxdb_v2_test.go | 1172 ++ plugins/outputs/influxdb_v2/sample.conf | 79 + plugins/outputs/instrumental/README.md | 51 + plugins/outputs/instrumental/instrumental.go | 212 + .../outputs/instrumental/instrumental_test.go | 243 + plugins/outputs/instrumental/sample.conf | 13 + plugins/outputs/iotdb/README.md | 151 + plugins/outputs/iotdb/iotdb.go | 346 + plugins/outputs/iotdb/iotdb_test.go | 641 + plugins/outputs/iotdb/sample.conf | 59 + plugins/outputs/kafka/README.md | 257 + plugins/outputs/kafka/kafka.go | 273 + plugins/outputs/kafka/kafka_test.go | 312 + plugins/outputs/kafka/sample.conf | 196 + plugins/outputs/kinesis/README.md | 195 + plugins/outputs/kinesis/kinesis.go | 196 + plugins/outputs/kinesis/kinesis_test.go | 596 + plugins/outputs/kinesis/sample.conf | 66 + plugins/outputs/librato/README.md | 59 + plugins/outputs/librato/librato.go | 254 + plugins/outputs/librato/librato_test.go | 273 + plugins/outputs/librato/sample.conf | 16 + plugins/outputs/logzio/README.md | 62 + plugins/outputs/logzio/logzio.go | 172 + plugins/outputs/logzio/logzio_test.go | 135 + plugins/outputs/logzio/sample.conf | 15 + plugins/outputs/loki/README.md | 72 + plugins/outputs/loki/loki.go | 226 + plugins/outputs/loki/loki_test.go | 630 + plugins/outputs/loki/sample.conf | 36 + plugins/outputs/loki/stream.go | 70 + plugins/outputs/loki/stream_test.go | 157 + plugins/outputs/mongodb/README.md | 70 + plugins/outputs/mongodb/mongodb.go | 233 + plugins/outputs/mongodb/mongodb_test.go | 437 + plugins/outputs/mongodb/sample.conf | 34 + .../mongodb/testdata/auth_scram/setup.js | 3 + .../mongodb/testdata/auth_x509/setup.js | 5 + plugins/outputs/mqtt/README.md | 349 + plugins/outputs/mqtt/homie.go | 110 + plugins/outputs/mqtt/mqtt.go | 312 + plugins/outputs/mqtt/mqtt_test.go | 938 ++ plugins/outputs/mqtt/sample.conf | 117 + plugins/outputs/mqtt/testdata/mosquitto.conf | 3 + plugins/outputs/mqtt/topic_name_generator.go | 88 + plugins/outputs/nats/README.md | 95 + plugins/outputs/nats/nats.go | 283 + plugins/outputs/nats/nats_test.go | 184 + plugins/outputs/nats/sample.conf | 61 + plugins/outputs/nats/testcases/js-config.conf | 16 + .../outputs/nats/testcases/js-default.conf | 8 + .../outputs/nats/testcases/js-no-stream.conf | 7 + .../outputs/nats/testcases/js-subjects.conf | 9 + plugins/outputs/nats/testcases/no-js.conf | 6 + .../outputs/nebius_cloud_monitoring/README.md | 93 + .../nebius_cloud_monitoring.go | 260 + .../nebius_cloud_monitoring_test.go | 205 + .../nebius_cloud_monitoring/sample.conf | 7 + plugins/outputs/newrelic/README.md | 49 + plugins/outputs/newrelic/newrelic.go | 179 + plugins/outputs/newrelic/newrelic_test.go | 193 + plugins/outputs/newrelic/sample.conf | 22 + plugins/outputs/nsq/README.md | 37 + plugins/outputs/nsq/nsq.go | 75 + plugins/outputs/nsq/nsq_test.go | 47 + plugins/outputs/nsq/sample.conf | 12 + plugins/outputs/opensearch/README.md | 368 + plugins/outputs/opensearch/opensearch.go | 450 + plugins/outputs/opensearch/opensearch_test.go | 361 + .../outputs/opensearch/opensearch_v1_test.go | 343 + .../outputs/opensearch/opensearch_v2_test.go | 343 + plugins/outputs/opensearch/sample.conf | 101 + plugins/outputs/opensearch/template.json | 55 + plugins/outputs/opentelemetry/README.md | 116 + plugins/outputs/opentelemetry/logger.go | 16 + .../outputs/opentelemetry/opentelemetry.go | 215 + .../opentelemetry/opentelemetry_test.go | 146 + plugins/outputs/opentelemetry/sample.conf | 48 + plugins/outputs/opentsdb/README.md | 123 + plugins/outputs/opentsdb/opentsdb.go | 259 + plugins/outputs/opentsdb/opentsdb_http.go | 187 + plugins/outputs/opentsdb/opentsdb_test.go | 203 + plugins/outputs/opentsdb/sample.conf | 26 + plugins/outputs/parquet/README.md | 122 + plugins/outputs/parquet/parquet.go | 337 + plugins/outputs/parquet/parquet_test.go | 247 + plugins/outputs/parquet/sample.conf | 14 + plugins/outputs/postgresql/Dockerfile | 26 + plugins/outputs/postgresql/README.md | 332 + plugins/outputs/postgresql/columns.go | 10 + plugins/outputs/postgresql/datatype_uint8.go | 342 + plugins/outputs/postgresql/datatypes.go | 60 + plugins/outputs/postgresql/postgresql.go | 507 + .../postgresql/postgresql_bench_test.go | 112 + plugins/outputs/postgresql/postgresql_test.go | 1214 ++ plugins/outputs/postgresql/sample.conf | 97 + .../postgresql/sqltemplate/template.go | 405 + plugins/outputs/postgresql/table_manager.go | 448 + .../outputs/postgresql/table_manager_test.go | 515 + plugins/outputs/postgresql/table_source.go | 436 + .../outputs/postgresql/table_source_test.go | 326 + plugins/outputs/postgresql/utils/column.go | 53 + plugins/outputs/postgresql/utils/utils.go | 117 + plugins/outputs/prometheus_client/README.md | 99 + .../prometheus_client/prometheus_client.go | 312 + .../prometheus_client_test.go | 123 + .../prometheus_client_v1_test.go | 497 + .../prometheus_client_v2_test.go | 528 + plugins/outputs/prometheus_client/sample.conf | 59 + .../outputs/prometheus_client/v1/collector.go | 424 + .../outputs/prometheus_client/v2/collector.go | 98 + plugins/outputs/quix/README.md | 58 + plugins/outputs/quix/config.go | 81 + plugins/outputs/quix/quix.go | 172 + plugins/outputs/quix/quix_test.go | 178 + plugins/outputs/quix/sample.conf | 14 + plugins/outputs/redistimeseries/README.md | 55 + .../redistimeseries/redistimeseries.go | 123 + .../redistimeseries/redistimeseries_test.go | 170 + plugins/outputs/redistimeseries/sample.conf | 23 + .../testcases/normal/expected.out | 6 + .../testcases/normal/input.influx | 2 + .../testcases/normal/telegraf.conf | 2 + .../normal_varying_labels/expected.out | 6 + .../normal_varying_labels/input.influx | 2 + .../normal_varying_labels/telegraf.conf | 2 + .../testcases/string_convert/expected.out | 3 + .../testcases/string_convert/input.influx | 1 + .../testcases/string_convert/telegraf.conf | 2 + .../testcases/string_drop/expected.out | 2 + .../testcases/string_drop/input.influx | 1 + .../testcases/string_drop/telegraf.conf | 3 + plugins/outputs/registry.go | 13 + plugins/outputs/remotefile/README.md | 91 + plugins/outputs/remotefile/backends.go | 8 + plugins/outputs/remotefile/remotefile.go | 273 + plugins/outputs/remotefile/remotefile_test.go | 513 + plugins/outputs/remotefile/sample.conf | 49 + plugins/outputs/riemann/README.md | 112 + plugins/outputs/riemann/riemann.go | 192 + plugins/outputs/riemann/riemann_test.go | 169 + plugins/outputs/riemann/sample.conf | 32 + plugins/outputs/sensu/README.md | 116 + plugins/outputs/sensu/sample.conf | 93 + plugins/outputs/sensu/sensu.go | 419 + plugins/outputs/sensu/sensu_test.go | 262 + plugins/outputs/signalfx/README.md | 48 + plugins/outputs/signalfx/sample.conf | 17 + plugins/outputs/signalfx/signalfx.go | 241 + plugins/outputs/signalfx/signalfx_test.go | 652 + plugins/outputs/socket_writer/README.md | 62 + plugins/outputs/socket_writer/sample.conf | 38 + .../outputs/socket_writer/socket_writer.go | 185 + .../socket_writer/socket_writer_test.go | 211 + plugins/outputs/sql/README.md | 232 + plugins/outputs/sql/sample.conf | 74 + plugins/outputs/sql/sql.go | 373 + plugins/outputs/sql/sql_test.go | 523 + plugins/outputs/sql/sqlite.go | 10 + plugins/outputs/sql/sqlite_test.go | 135 + .../testdata/clickhouse/enable_stdout_log.xml | 5 + .../sql/testdata/clickhouse/expected.txt | 36 + .../sql/testdata/clickhouse/initdb/init.sql | 1 + .../testdata/mariadb/expected_metric_one.sql | 14 + .../mariadb/expected_metric_three.sql | 8 + .../testdata/mariadb/expected_metric_two.sql | 8 + .../sql/testdata/mariadb/initdb/script.sql | 4 + .../expected_metric_one.sql | 13 + .../expected_metric_three.sql | 7 + .../expected_metric_two.sql | 7 + .../mariadb_no_timestamp/initdb/script.sql | 4 + .../sql/testdata/postgres/expected.sql | 34 + .../sql/testdata/postgres/initdb/init.sql | 2 + plugins/outputs/stackdriver/README.md | 115 + plugins/outputs/stackdriver/counter_cache.go | 99 + .../outputs/stackdriver/counter_cache_test.go | 166 + plugins/outputs/stackdriver/sample.conf | 52 + plugins/outputs/stackdriver/stackdriver.go | 694 + .../outputs/stackdriver/stackdriver_test.go | 1156 ++ plugins/outputs/stomp/README.md | 55 + plugins/outputs/stomp/sample.conf | 18 + plugins/outputs/stomp/stomp.go | 119 + plugins/outputs/stomp/stomp_test.go | 50 + plugins/outputs/sumologic/README.md | 79 + plugins/outputs/sumologic/sample.conf | 51 + plugins/outputs/sumologic/sumologic.go | 275 + plugins/outputs/sumologic/sumologic_test.go | 709 + plugins/outputs/syslog/README.md | 149 + plugins/outputs/syslog/sample.conf | 76 + plugins/outputs/syslog/syslog.go | 192 + plugins/outputs/syslog/syslog_mapper.go | 202 + plugins/outputs/syslog/syslog_mapper_test.go | 219 + plugins/outputs/syslog/syslog_test.go | 584 + .../syslog/testcases/issue_16012/expected.out | 1 + .../syslog/testcases/issue_16012/input.influx | 1 + .../testcases/issue_16012/telegraf.conf | 4 + plugins/outputs/timestream/README.md | 294 + plugins/outputs/timestream/sample.conf | 92 + plugins/outputs/timestream/timestream.go | 631 + .../timestream/timestream_internal_test.go | 101 + plugins/outputs/timestream/timestream_test.go | 1414 ++ plugins/outputs/warp10/README.md | 73 + plugins/outputs/warp10/sample.conf | 26 + plugins/outputs/warp10/warp10.go | 299 + plugins/outputs/warp10/warp10_test.go | 150 + plugins/outputs/wavefront/README.md | 182 + plugins/outputs/wavefront/sample.conf | 108 + plugins/outputs/wavefront/wavefront.go | 407 + plugins/outputs/wavefront/wavefront_test.go | 464 + plugins/outputs/websocket/README.md | 75 + plugins/outputs/websocket/sample.conf | 43 + plugins/outputs/websocket/websocket.go | 208 + plugins/outputs/websocket/websocket_test.go | 223 + .../outputs/yandex_cloud_monitoring/README.md | 42 + .../yandex_cloud_monitoring/sample.conf | 10 + .../yandex_cloud_monitoring.go | 255 + .../yandex_cloud_monitoring_test.go | 145 + plugins/outputs/zabbix/README.md | 408 + plugins/outputs/zabbix/autoregister.go | 38 + plugins/outputs/zabbix/autoregister_test.go | 118 + plugins/outputs/zabbix/lld.go | 235 + plugins/outputs/zabbix/lld_test.go | 1129 ++ plugins/outputs/zabbix/sample.conf | 34 + .../zabbix/testcases/receive/expected.out | 172 + .../zabbix/testcases/receive/input.influx | 3 + .../zabbix/testcases/receive/telegraf.conf | 7 + plugins/outputs/zabbix/zabbix.go | 240 + plugins/outputs/zabbix/zabbix_test.go | 1272 ++ plugins/parsers/EXAMPLE_README.md | 47 + plugins/parsers/all/all.go | 1 + plugins/parsers/all/avro.go | 5 + plugins/parsers/all/binary.go | 5 + plugins/parsers/all/collectd.go | 5 + plugins/parsers/all/csv.go | 5 + plugins/parsers/all/dropwizard.go | 5 + plugins/parsers/all/form_urlencoded.go | 5 + plugins/parsers/all/graphite.go | 5 + plugins/parsers/all/grok.go | 5 + plugins/parsers/all/influx.go | 8 + plugins/parsers/all/json.go | 5 + plugins/parsers/all/json_v2.go | 5 + plugins/parsers/all/logfmt.go | 5 + plugins/parsers/all/nagios.go | 5 + plugins/parsers/all/openmetrics.go | 5 + plugins/parsers/all/opentsdb.go | 5 + plugins/parsers/all/parquet.go | 5 + plugins/parsers/all/prometheus.go | 5 + plugins/parsers/all/prometheusremotewrite.go | 5 + plugins/parsers/all/value.go | 5 + plugins/parsers/all/wavefront.go | 5 + plugins/parsers/all/xpath.go | 5 + plugins/parsers/avro/README.md | 148 + plugins/parsers/avro/parser.go | 340 + plugins/parsers/avro/parser_test.go | 183 + plugins/parsers/avro/schema_registry.go | 134 + .../bad-timestamp-format/expected.err | 1 + .../bad-timestamp-format/expected.out | 0 .../bad-timestamp-format/message.avro | 0 .../bad-timestamp-format/telegraf.conf | 29 + .../avro/testcases/benchmark/expected.out | 1 + .../avro/testcases/benchmark/message.json | 7 + .../avro/testcases/benchmark/telegraf.conf | 25 + .../avro/testcases/config-both/expected.err | 4 + .../avro/testcases/config-both/expected.out | 0 .../avro/testcases/config-both/message.avro | 0 .../avro/testcases/config-both/telegraf.conf | 28 + .../testcases/config-neither/expected.err | 2 + .../testcases/config-neither/expected.out | 0 .../testcases/config-neither/message.avro | 0 .../testcases/config-neither/telegraf.conf | 5 + .../parsers/avro/testcases/enum/expected.out | 1 + .../parsers/avro/testcases/enum/message.json | 7 + .../parsers/avro/testcases/enum/telegraf.conf | 41 + .../avro/testcases/json-array/expected.out | 1 + .../avro/testcases/json-array/message.json | 5 + .../avro/testcases/json-array/telegraf.conf | 24 + .../avro/testcases/json-format/expected.out | 1 + .../avro/testcases/json-format/message.json | 7 + .../avro/testcases/json-format/telegraf.conf | 25 + .../expected.out | 1 + .../message.avro | 1 + .../telegraf.conf | 30 + .../no-timestamp-format/expected.out | 1 + .../no-timestamp-format/message.avro | 1 + .../no-timestamp-format/telegraf.conf | 28 + .../testcases/supplied_timestamp/expected.out | 1 + .../testcases/supplied_timestamp/message.avro | 1 + .../supplied_timestamp/telegraf.conf | 28 + .../expected.out | 1 + .../message.avro | 1 + .../telegraf.conf | 29 + .../expected.out | 1 + .../message.avro | 1 + .../telegraf.conf | 23 + .../avro/testcases/union-any/expected.out | 1 + .../avro/testcases/union-any/message.json | 11 + .../avro/testcases/union-any/telegraf.conf | 26 + .../avro/testcases/union-array/expected.out | 1 + .../avro/testcases/union-array/message.json | 5 + .../avro/testcases/union-array/telegraf.conf | 25 + .../testcases/union-nullable-tag/expected.out | 1 + .../testcases/union-nullable-tag/message.json | 14 + .../union-nullable-tag/telegraf.conf | 27 + .../testcases/union-nullable/expected.out | 1 + .../testcases/union-nullable/message.json | 11 + .../testcases/union-nullable/telegraf.conf | 26 + .../parsers/avro/testcases/union/expected.out | 1 + .../parsers/avro/testcases/union/message.json | 11 + .../avro/testcases/union/telegraf.conf | 26 + plugins/parsers/binary/README.md | 350 + plugins/parsers/binary/config.go | 183 + plugins/parsers/binary/entry.go | 310 + plugins/parsers/binary/entry_test.go | 44 + plugins/parsers/binary/parser.go | 213 + plugins/parsers/binary/parser_test.go | 1614 ++ .../testcases/base64_encoding/expected.out | 3 + .../testcases/base64_encoding/messageA.bin | 1 + .../testcases/base64_encoding/messageB.bin | 1 + .../testcases/base64_encoding/messageC.bin | 1 + .../testcases/base64_encoding/telegraf.conf | 8 + .../testcases/hex_encoding/expected.out | 3 + .../testcases/hex_encoding/messageA.bin | 1 + .../testcases/hex_encoding/messageB.bin | 1 + .../testcases/hex_encoding/messageC.bin | 1 + .../testcases/hex_encoding/telegraf.conf | 8 + .../testcases/multiple_messages/expected.out | 3 + .../testcases/multiple_messages/messageA.bin | Bin 0 -> 28 bytes .../testcases/multiple_messages/messageB.bin | Bin 0 -> 16 bytes .../testcases/multiple_messages/messageC.bin | Bin 0 -> 20 bytes .../testcases/multiple_messages/telegraf.conf | 46 + plugins/parsers/collectd/README.md | 58 + plugins/parsers/collectd/parser.go | 208 + plugins/parsers/collectd/parser_test.go | 410 + plugins/parsers/collectd/testdata/authfile | 1 + plugins/parsers/csv/README.md | 229 + plugins/parsers/csv/parser.go | 506 + plugins/parsers/csv/parser_test.go | 1578 ++ plugins/parsers/deprecations.go | 6 + plugins/parsers/dropwizard/README.md | 177 + plugins/parsers/dropwizard/parser.go | 259 + plugins/parsers/dropwizard/parser_test.go | 652 + plugins/parsers/errors.go | 9 + plugins/parsers/form_urlencoded/README.md | 59 + plugins/parsers/form_urlencoded/parser.go | 107 + .../parsers/form_urlencoded/parser_test.go | 217 + plugins/parsers/graphite/README.md | 48 + plugins/parsers/graphite/config.go | 130 + plugins/parsers/graphite/parser.go | 198 + plugins/parsers/graphite/parser_test.go | 893 ++ plugins/parsers/grok/README.md | 272 + plugins/parsers/grok/influx_patterns.go | 43 + plugins/parsers/grok/parser.go | 603 + plugins/parsers/grok/parser_test.go | 1243 ++ plugins/parsers/grok/testdata/test-patterns | 14 + plugins/parsers/grok/testdata/test_a.log | 1 + plugins/parsers/grok/testdata/test_b.log | 1 + .../parsers/grok/testdata/test_multiline.log | 3 + plugins/parsers/influx/README.md | 29 + plugins/parsers/influx/escape.go | 83 + plugins/parsers/influx/handler.go | 134 + .../parsers/influx/influx_upstream/README.md | 4 + .../parsers/influx/influx_upstream/parser.go | 318 + .../influx/influx_upstream/parser_test.go | 1073 ++ plugins/parsers/influx/machine.go | 3810 +++++ plugins/parsers/influx/machine.go.rl | 562 + plugins/parsers/influx/machine_test.go | 2227 +++ plugins/parsers/influx/parser.go | 257 + plugins/parsers/influx/parser_test.go | 1040 ++ plugins/parsers/json/README.md | 262 + plugins/parsers/json/json_flattener.go | 70 + plugins/parsers/json/parser.go | 248 + plugins/parsers/json/parser_test.go | 1493 ++ plugins/parsers/json_v2/README.md | 276 + plugins/parsers/json_v2/parser.go | 747 + plugins/parsers/json_v2/parser_test.go | 168 + .../json_v2/testdata/10670/expected.out | 1 + .../parsers/json_v2/testdata/10670/input.json | 10 + .../json_v2/testdata/10670/telegraf.conf | 25 + .../testdata/array_of_objects/expected.out | 2 + .../testdata/array_of_objects/input.json | 14 + .../testdata/array_of_objects/telegraf.conf | 9 + .../json_v2/testdata/benchmark/benchmark.json | 34 + .../json_v2/testdata/benchmark/expected.out | 2 + .../json_v2/testdata/benchmark/input.json | 34 + .../json_v2/testdata/benchmark/telegraf.conf | 9 + .../testdata/complex_nesting/expected.out | 3 + .../testdata/complex_nesting/input.json | 31 + .../testdata/complex_nesting/telegraf.conf | 9 + .../testdata/fields_and_tags/expected.out | 2 + .../testdata/fields_and_tags/input.json | 46 + .../testdata/fields_and_tags/telegraf.conf | 14 + .../fields_and_tags_complex/expected.out | 5 + .../fields_and_tags_complex/input.json | 87 + .../fields_and_tags_complex/telegraf.conf | 10 + .../testdata/large_numbers/expected.out | 3 + .../json_v2/testdata/large_numbers/input.json | 17 + .../testdata/large_numbers/telegraf.conf | 22 + .../measurement_name_int/expected.out | 1 + .../testdata/measurement_name_int/input.json | 19 + .../measurement_name_int/telegraf.conf | 9 + .../mix_field_and_object/expected.out | 1 + .../testdata/mix_field_and_object/input.json | 44 + .../mix_field_and_object/telegraf.conf | 15 + .../multiple_arrays_in_object/expected.out | 8 + .../multiple_arrays_in_object/input.json | 24 + .../multiple_arrays_in_object/telegraf.conf | 11 + .../testdata/multiple_json_input/expected.out | 2 + .../testdata/multiple_json_input/input_1.json | 87 + .../testdata/multiple_json_input/input_2.json | 134 + .../multiple_json_input/telegraf.conf | 18 + .../testdata/multiple_timestamps/expected.out | 2 + .../testdata/multiple_timestamps/input.json | 12 + .../multiple_timestamps/telegraf.conf | 10 + .../nested_and_nonnested_tags/expected.out | 12 + .../nested_and_nonnested_tags/input.json | 174 + .../nested_and_nonnested_tags/telegraf.conf | 16 + .../nested_array_of_objects/expected.out | 2 + .../nested_array_of_objects/input.json | 36 + .../nested_array_of_objects/telegraf.conf | 15 + .../nested_objects_optional/expected.out | 5 + .../nested_objects_nest.json | 25 + .../nested_objects_single.json | 6 + .../nested_objects_optional/telegraf.conf | 58 + .../json_v2/testdata/nested_tags/expected.out | 2 + .../json_v2/testdata/nested_tags/input.json | 16 + .../testdata/nested_tags/telegraf.conf | 12 + .../testdata/nested_tags_complex/expected.out | 3 + .../testdata/nested_tags_complex/input.json | 35 + .../nested_tags_complex/telegraf.conf | 14 + .../json_v2/testdata/null/expected.out | 1 + .../parsers/json_v2/testdata/null/input.json | 40 + .../json_v2/testdata/null/telegraf.conf | 8 + .../json_v2/testdata/object/expected.out | 5 + .../json_v2/testdata/object/input.json | 87 + .../json_v2/testdata/object/telegraf.conf | 12 + .../testdata/object_multiple/expected.out | 5 + .../testdata/object_multiple/input.json | 21 + .../testdata/object_multiple/telegraf.conf | 23 + .../testdata/object_timestamp/expected.out | 3 + .../testdata/object_timestamp/input.json | 19 + .../testdata/object_timestamp/telegraf.conf | 12 + .../json_v2/testdata/optional/expected.out | 0 .../json_v2/testdata/optional/input.json | 3 + .../json_v2/testdata/optional/telegraf.conf | 15 + .../testdata/optional_objects/expected.out | 3 + .../testdata/optional_objects/input_1.json | 1 + .../testdata/optional_objects/input_2.json | 1 + .../testdata/optional_objects/telegraf.conf | 21 + .../subfieldtag_in_object/expected.out | 1 + .../testdata/subfieldtag_in_object/input.json | 97 + .../subfieldtag_in_object/telegraf.conf | 17 + .../subfieldtag_in_object_2/expected.out | 4 + .../subfieldtag_in_object_2/input.json | 10 + .../subfieldtag_in_object_2/telegraf.conf | 16 + .../json_v2/testdata/timestamp/expected.out | 4 + .../json_v2/testdata/timestamp/input.json | 25 + .../json_v2/testdata/timestamp/telegraf.conf | 11 + .../testdata/timestamp_ns/expected.out | 2 + .../json_v2/testdata/timestamp_ns/input.json | 7 + .../testdata/timestamp_ns/telegraf.conf | 11 + .../testdata/timestamp_rfc3339/expected.out | 1 + .../testdata/timestamp_rfc3339/input.json | 4 + .../testdata/timestamp_rfc3339/telegraf.conf | 8 + .../json_v2/testdata/types/expected.out | 4 + .../parsers/json_v2/testdata/types/input.json | 22 + .../json_v2/testdata/types/telegraf.conf | 105 + .../json_v2/testdata/wrong_path/expected.err | 6 + .../json_v2/testdata/wrong_path/expected.out | 0 .../json_v2/testdata/wrong_path/input.json | 3 + .../json_v2/testdata/wrong_path/telegraf.conf | 46 + plugins/parsers/logfmt/README.md | 33 + plugins/parsers/logfmt/parser.go | 126 + plugins/parsers/logfmt/parser_test.go | 334 + plugins/parsers/nagios/README.md | 17 + plugins/parsers/nagios/parser.go | 323 + plugins/parsers/nagios/parser_test.go | 577 + plugins/parsers/openmetrics/README.md | 154 + plugins/parsers/openmetrics/metric_v1.go | 163 + plugins/parsers/openmetrics/metric_v2.go | 189 + .../openmetrics/openmetrics_data_model.pb.go | 1834 +++ .../openmetrics/openmetrics_data_model.proto | 214 + plugins/parsers/openmetrics/parser.go | 143 + plugins/parsers/openmetrics/parser_test.go | 178 + .../testcases/dovecot/expected_v1.out | 46 + .../testcases/dovecot/expected_v2.out | 82 + .../openmetrics/testcases/dovecot/input.txt | 107 + .../testcases/dovecot/telegraf.conf | 4 + .../testcases/multiple/expected_v1.out | 4 + .../testcases/multiple/expected_v2.out | 10 + .../openmetrics/testcases/multiple/input.txt | 23 + .../testcases/multiple/telegraf.conf | 4 + .../testcases/protobuf/expected_v1.out | 46 + .../testcases/protobuf/expected_v2.out | 82 + .../openmetrics/testcases/protobuf/input.bin | Bin 0 -> 3071 bytes .../testcases/protobuf/telegraf.conf | 6 + .../protobuf_infolabels/expected_v1.out | 1 + .../protobuf_infolabels/expected_v2.out | 1 + .../testcases/protobuf_infolabels/input.bin | 14 + .../protobuf_infolabels/telegraf.conf | 6 + .../testcases/valid_counter/expected_v1.out | 1 + .../testcases/valid_counter/expected_v2.out | 1 + .../testcases/valid_counter/input.txt | 4 + .../testcases/valid_counter/telegraf.conf | 4 + .../testcases/valid_gauge/expected_v1.out | 3 + .../testcases/valid_gauge/expected_v2.out | 3 + .../testcases/valid_gauge/input.txt | 10 + .../testcases/valid_gauge/telegraf.conf | 3 + .../valid_gaugehistogram/expected_v1.out | 1 + .../valid_gaugehistogram/expected_v2.out | 9 + .../testcases/valid_gaugehistogram/input.txt | 14 + .../valid_gaugehistogram/telegraf.conf | 4 + .../testcases/valid_histogram/expected_v1.out | 1 + .../testcases/valid_histogram/expected_v2.out | 9 + .../testcases/valid_histogram/input.txt | 14 + .../testcases/valid_histogram/telegraf.conf | 4 + .../testcases/valid_info/expected_v1.out | 1 + .../testcases/valid_info/expected_v2.out | 1 + .../testcases/valid_info/input.txt | 4 + .../testcases/valid_info/telegraf.conf | 3 + .../testcases/valid_stateset/expected_v1.out | 2 + .../testcases/valid_stateset/expected_v2.out | 6 + .../testcases/valid_stateset/input.txt | 8 + .../testcases/valid_stateset/telegraf.conf | 3 + .../testcases/valid_summary/expected_v1.out | 1 + .../testcases/valid_summary/expected_v2.out | 4 + .../testcases/valid_summary/input.txt | 10 + .../testcases/valid_summary/telegraf.conf | 3 + .../testcases/valid_unknown/expected_v1.out | 2 + .../testcases/valid_unknown/expected_v2.out | 2 + .../testcases/valid_unknown/input.txt | 5 + .../testcases/valid_unknown/telegraf.conf | 4 + plugins/parsers/openmetrics/textparse.go | 394 + plugins/parsers/opentsdb/README.md | 29 + plugins/parsers/opentsdb/parser.go | 121 + plugins/parsers/opentsdb/parser_test.go | 358 + plugins/parsers/parquet/README.md | 51 + plugins/parsers/parquet/columns.go | 126 + plugins/parsers/parquet/parser.go | 149 + plugins/parsers/parquet/parser_test.go | 76 + .../parquet/testcases/benchmark/expected.out | 1 + .../parquet/testcases/benchmark/generate.py | 11 + .../parquet/testcases/benchmark/input.parquet | Bin 0 -> 2366 bytes .../parquet/testcases/benchmark/telegraf.conf | 6 + .../parquet/testcases/datatypes/expected.out | 2 + .../parquet/testcases/datatypes/generate.py | 33 + .../parquet/testcases/datatypes/input.parquet | Bin 0 -> 6560 bytes .../parquet/testcases/datatypes/telegraf.conf | 9 + .../parquet/testcases/dense/expected.out | 7 + .../parquet/testcases/dense/generate.py | 16 + .../parquet/testcases/dense/input.parquet | Bin 0 -> 3540 bytes .../parquet/testcases/dense/telegraf.conf | 8 + .../parquet/testcases/empty/expected.out | 0 .../parquet/testcases/empty/generate.py | 6 + .../parquet/testcases/empty/input.parquet | Bin 0 -> 976 bytes .../parquet/testcases/empty/telegraf.conf | 3 + .../parquet/testcases/multitable/expected.out | 21 + .../parquet/testcases/multitable/generate.py | 39 + .../testcases/multitable/input.parquet | Bin 0 -> 4711 bytes .../testcases/multitable/telegraf.conf | 8 + .../parquet/testcases/sparse/expected.out | 6 + .../parquet/testcases/sparse/generate.py | 20 + .../parquet/testcases/sparse/input.parquet | Bin 0 -> 5499 bytes .../parquet/testcases/sparse/telegraf.conf | 7 + .../parquet/testcases/timestamp/expected.out | 3 + .../parquet/testcases/timestamp/generate.py | 14 + .../parquet/testcases/timestamp/input.parquet | Bin 0 -> 2444 bytes .../parquet/testcases/timestamp/telegraf.conf | 7 + plugins/parsers/prometheus/README.md | 22 + plugins/parsers/prometheus/common.go | 37 + plugins/parsers/prometheus/metric_v1.go | 85 + plugins/parsers/prometheus/metric_v2.go | 107 + plugins/parsers/prometheus/parser.go | 99 + plugins/parsers/prometheus/parser_test.go | 178 + .../testcases/benchmark/expected_v1.out | 2 + .../testcases/benchmark/expected_v2.out | 2 + .../prometheus/testcases/benchmark/input.txt | 7 + .../testcases/benchmark/telegraf.conf | 4 + .../testcases/default_tags/expected_v1.out | 1 + .../testcases/default_tags/expected_v2.out | 1 + .../testcases/default_tags/input.txt | 3 + .../testcases/default_tags/telegraf.conf | 7 + .../histogram_inf_bucket/expected_v1.out | 1 + .../histogram_inf_bucket/expected_v2.out | 9 + .../testcases/histogram_inf_bucket/input.bin | Bin 0 -> 267 bytes .../histogram_inf_bucket/telegraf.conf | 6 + .../ignore_timestamp/expected_v1.out | 1 + .../ignore_timestamp/expected_v2.out | 1 + .../testcases/ignore_timestamp/input.txt | 2 + .../testcases/ignore_timestamp/telegraf.conf | 4 + .../metric_with_timestamp/expected_v1.out | 1 + .../metric_with_timestamp/expected_v2.out | 1 + .../testcases/metric_with_timestamp/input.txt | 2 + .../metric_with_timestamp/telegraf.conf | 4 + .../testcases/protobuf/expected_v1.out | 6 + .../testcases/protobuf/expected_v2.out | 6 + .../prometheus/testcases/protobuf/input.bin | Bin 0 -> 414 bytes .../testcases/protobuf/telegraf.conf | 6 + .../testcases/valid_counter/expected_v1.out | 1 + .../testcases/valid_counter/expected_v2.out | 1 + .../testcases/valid_counter/input.txt | 3 + .../testcases/valid_counter/telegraf.conf | 4 + .../testcases/valid_gauge/expected_v1.out | 1 + .../testcases/valid_gauge/expected_v2.out | 1 + .../testcases/valid_gauge/input.txt | 3 + .../testcases/valid_gauge/telegraf.conf | 4 + .../testcases/valid_histogram/expected_v1.out | 1 + .../testcases/valid_histogram/expected_v2.out | 9 + .../testcases/valid_histogram/input.txt | 12 + .../testcases/valid_histogram/telegraf.conf | 4 + .../testcases/valid_summary/expected_v1.out | 1 + .../testcases/valid_summary/expected_v2.out | 4 + .../testcases/valid_summary/input.txt | 7 + .../testcases/valid_summary/telegraf.conf | 4 + .../parsers/prometheusremotewrite/README.md | 60 + .../prometheusremotewrite/metric_v1.go | 106 + .../prometheusremotewrite/metric_v2.go | 91 + .../parsers/prometheusremotewrite/parser.go | 72 + .../prometheusremotewrite/parser_test.go | 449 + .../testcases/benchmark/expected_v1.out | 2 + .../testcases/benchmark/expected_v2.out | 2 + .../testcases/benchmark/input.json | 22 + .../testcases/benchmark/telegraf.conf | 3 + .../testcases/default_tags/expected_v1.out | 1 + .../testcases/default_tags/expected_v2.out | 1 + .../testcases/default_tags/input.json | 11 + .../testcases/default_tags/telegraf.conf | 4 + .../testcases/float_histogram/expected_v1.out | 1 + .../testcases/float_histogram/expected_v2.out | 9 + .../testcases/float_histogram/input.json | 23 + .../testcases/float_histogram/telegraf.conf | 3 + .../testcases/int_histogram/expected_v1.out | 1 + .../testcases/int_histogram/expected_v2.out | 9 + .../testcases/int_histogram/input.json | 23 + .../testcases/int_histogram/telegraf.conf | 3 + .../testcases/simple/expected_v1.out | 2 + .../testcases/simple/expected_v2.out | 2 + .../testcases/simple/input.json | 21 + .../testcases/simple/telegraf.conf | 3 + plugins/parsers/registry.go | 16 + plugins/parsers/value/README.md | 59 + plugins/parsers/value/parser.go | 125 + plugins/parsers/value/parser_test.go | 346 + plugins/parsers/wavefront/README.md | 21 + plugins/parsers/wavefront/element.go | 225 + plugins/parsers/wavefront/parser.go | 223 + plugins/parsers/wavefront/parser_test.go | 342 + plugins/parsers/wavefront/scanner.go | 65 + plugins/parsers/wavefront/token.go | 46 + plugins/parsers/xpath/README.md | 639 + plugins/parsers/xpath/cbor_document.go | 103 + plugins/parsers/xpath/json_document.go | 103 + plugins/parsers/xpath/msgpack_document.go | 41 + plugins/parsers/xpath/parser.go | 703 + plugins/parsers/xpath/parser_test.go | 1820 +++ .../parsers/xpath/protocolbuffer_document.go | 214 + .../parsers/xpath/testcases/addressbook.conf | 28 + .../parsers/xpath/testcases/addressbook.dat | 17 + .../xpath/testcases/cbor/addressbook.bin | 1 + .../parsers/xpath/testcases/cbor/expected.out | 5 + .../xpath/testcases/cbor/telegraf.conf | 9 + .../testcases/cbor_base64_encoding/data.bin | Bin 0 -> 83 bytes .../cbor_base64_encoding/expected.out | 1 + .../cbor_base64_encoding/telegraf.conf | 28 + .../testcases/cbor_benchmark/expected.out | 2 + .../testcases/cbor_benchmark/message.bin | Bin 0 -> 185 bytes .../testcases/cbor_benchmark/telegraf.conf | 20 + .../testcases/cbor_hex_encoding/data.bin | Bin 0 -> 83 bytes .../testcases/cbor_hex_encoding/expected.out | 1 + .../testcases/cbor_hex_encoding/telegraf.conf | 24 + .../cbor_hex_encoding_explicit/data.bin | Bin 0 -> 83 bytes .../cbor_hex_encoding_explicit/expected.out | 1 + .../cbor_hex_encoding_explicit/telegraf.conf | 29 + .../testcases/cbor_numeric_keys/data.bin | Bin 0 -> 76 bytes .../testcases/cbor_numeric_keys/expected.out | 1 + .../testcases/cbor_numeric_keys/telegraf.conf | 26 + .../parsers/xpath/testcases/earthquakes.conf | 44 + .../xpath/testcases/earthquakes.quakeml | 20 + .../xpath/testcases/field_tag_batch.conf | 14 + .../xpath/testcases/field_tag_batch.json | 12 + .../testcases/json_array_expand/expected.out | 1 + .../testcases/json_array_expand/telegraf.conf | 12 + .../testcases/json_array_expand/test.json | 43 + .../expected.out | 1 + .../telegraf.conf | 12 + .../json_array_expand_simple_types/test.json | 20 + .../json_array_simple_types/expected.out | 1 + .../json_array_simple_types/telegraf.conf | 11 + .../json_array_simple_types/test.json | 20 + .../json_explicit_precedence/expected.out | 1 + .../json_explicit_precedence/telegraf.conf | 15 + .../json_explicit_precedence/test.json | 13 + .../json_native_nonnested/expected.out | 1 + .../json_native_nonnested/telegraf.conf | 11 + .../testcases/json_native_nonnested/test.json | 13 + .../json_string_representation/expected.out | 1 + .../json_string_representation/telegraf.conf | 9 + .../json_string_representation/test.json | 13 + .../parsers/xpath/testcases/multisensor.xml | 31 + .../testcases/multisensor_explicit_basic.conf | 17 + .../testcases/multisensor_explicit_batch.conf | 28 + .../multisensor_selection_batch.conf | 23 + .../testcases/name_expansion/expected.out | 3 + .../testcases/name_expansion/telegraf.conf | 10 + .../xpath/testcases/name_expansion/test.json | 48 + .../native_types_cbor/addressbook.bin | 1 + .../testcases/native_types_cbor/expected.out | 5 + .../testcases/native_types_cbor/telegraf.conf | 11 + .../testcases/native_types_json/expected.out | 1 + .../testcases/native_types_json/telegraf.conf | 13 + .../testcases/native_types_json/test.json | 6 + .../native_types_msgpack/expected.out | 1 + .../native_types_json/expected.out | 1 + .../native_types_json/telegraf.conf | 12 + .../native_types_json/test.json | 5 + .../native_types_msgpack/telegraf.conf | 13 + .../testcases/native_types_msgpack/test.msg | Bin 0 -> 37 bytes .../native_types_protobuf/expected.out | 1 + .../native_types_protobuf/message.proto | 10 + .../native_types_protobuf/telegraf.conf | 17 + .../testcases/native_types_protobuf/test.dat | 2 + .../xpath/testcases/openweathermap_5d.json | 127 + .../xpath/testcases/openweathermap_5d.xml | 38 + .../xpath/testcases/openweathermap_json.conf | 28 + .../xpath/testcases/openweathermap_xml.conf | 28 + .../protobuf_benchmark/benchmark.proto | 15 + .../testcases/protobuf_benchmark/expected.out | 2 + .../testcases/protobuf_benchmark/message.bin | Bin 0 -> 90 bytes .../protobuf_benchmark/telegraf.conf | 24 + .../protobuf_issue_13715/expected.out | 1 + .../protobuf_issue_13715/issue.proto | 38 + .../protobuf_issue_13715/message.bin | 6 + .../protobuf_issue_13715/telegraf.conf | 19 + .../testcases/protobuf_issue_15571/data.json | 3194 ++++ .../protobuf_issue_15571/expected.out | 1 + .../protobuf_issue_15571/message.bin | Bin 0 -> 7807 bytes .../testcases/protobuf_issue_15571/port.proto | 226 + .../protobuf_issue_15571/telegraf.conf | 16 + .../protobuf_issue_15571/telemetry_top.proto | 99 + .../protobuf_noskip_bytes_grpc/expected.err | 1 + .../protobuf_noskip_bytes_grpc/message.proto | 10 + .../protobuf_noskip_bytes_grpc/telegraf.conf | 18 + .../protobuf_noskip_bytes_grpc/test.dat | Bin 0 -> 28 bytes .../protobuf_powerdns_hex/expected.out | 1 + .../powerdns_message.bin | Bin 0 -> 103 bytes .../powerdns_message.proto | 184 + .../protobuf_powerdns_hex/telegraf.conf | 14 + .../protobuf_skip_bytes_grpc/expected.out | 1 + .../protobuf_skip_bytes_grpc/message.proto | 10 + .../protobuf_skip_bytes_grpc/telegraf.conf | 18 + .../protobuf_skip_bytes_grpc/test.dat | Bin 0 -> 28 bytes .../xpath/testcases/protos/addressbook.proto | 28 + .../xpath/testcases/protos/person.proto | 13 + .../xpath/testcases/protos/phonenumber.proto | 15 + .../xpath/testcases/string_join/expected.out | 1 + .../xpath/testcases/string_join/telegraf.conf | 13 + .../xpath/testcases/string_join/test.json | 20 + .../time_float_exponential/expected.out | 1 + .../time_float_exponential/telegraf.conf | 12 + .../time_float_exponential/test.json | 5 + .../time_timezone_Berlin/expected.out | 1 + .../time_timezone_Berlin/telegraf.conf | 13 + .../testcases/time_timezone_Berlin/test.json | 5 + .../testcases/time_timezone_CEST/expected.out | 1 + .../time_timezone_CEST/telegraf.conf | 13 + .../testcases/time_timezone_CEST/test.json | 5 + .../testcases/time_timezone_MST/expected.out | 1 + .../testcases/time_timezone_MST/telegraf.conf | 13 + .../testcases/time_timezone_MST/test.json | 5 + .../testcases/time_timezone_utc/expected.out | 1 + .../testcases/time_timezone_utc/telegraf.conf | 12 + .../testcases/time_timezone_utc/test.json | 5 + .../time_timezone_with_offset/expected.out | 1 + .../time_timezone_with_offset/telegraf.conf | 13 + .../time_timezone_with_offset/test.json | 5 + plugins/parsers/xpath/testcases/tracker.msg | 1 + .../xpath/testcases/tracker_msgpack.conf | 24 + plugins/parsers/xpath/xml_document.go | 73 + plugins/processors/all/all.go | 1 + plugins/processors/all/aws_ec2.go | 5 + plugins/processors/all/batch.go | 5 + plugins/processors/all/clone.go | 5 + plugins/processors/all/converter.go | 5 + plugins/processors/all/date.go | 5 + plugins/processors/all/dedup.go | 5 + plugins/processors/all/defaults.go | 5 + plugins/processors/all/enum.go | 5 + plugins/processors/all/execd.go | 5 + plugins/processors/all/filepath.go | 5 + plugins/processors/all/filter.go | 5 + plugins/processors/all/ifname.go | 5 + plugins/processors/all/lookup.go | 5 + plugins/processors/all/noise.go | 5 + plugins/processors/all/override.go | 5 + plugins/processors/all/parser.go | 5 + plugins/processors/all/pivot.go | 5 + plugins/processors/all/port_name.go | 5 + plugins/processors/all/printer.go | 5 + plugins/processors/all/processors.go | 5 + plugins/processors/all/regex.go | 5 + plugins/processors/all/rename.go | 5 + plugins/processors/all/reverse_dns.go | 5 + plugins/processors/all/s2geo.go | 5 + plugins/processors/all/scale.go | 5 + plugins/processors/all/snmp_lookup.go | 5 + plugins/processors/all/split.go | 5 + plugins/processors/all/starlark.go | 5 + plugins/processors/all/strings.go | 5 + plugins/processors/all/tag_limit.go | 5 + plugins/processors/all/template.go | 5 + plugins/processors/all/topk.go | 5 + plugins/processors/all/unpivot.go | 5 + plugins/processors/aws_ec2/README.md | 126 + plugins/processors/aws_ec2/ec2.go | 401 + plugins/processors/aws_ec2/ec2_test.go | 184 + plugins/processors/aws_ec2/sample.conf | 78 + plugins/processors/batch/README.md | 60 + plugins/processors/batch/batch.go | 49 + plugins/processors/batch/batch_test.go | 112 + plugins/processors/batch/sample.conf | 11 + plugins/processors/clone/README.md | 48 + plugins/processors/clone/clone.go | 52 + plugins/processors/clone/clone_test.go | 242 + plugins/processors/clone/sample.conf | 10 + plugins/processors/converter/README.md | 139 + plugins/processors/converter/converter.go | 396 + .../processors/converter/converter_test.go | 869 + plugins/processors/converter/sample.conf | 49 + plugins/processors/date/README.md | 68 + plugins/processors/date/date.go | 77 + plugins/processors/date/date_test.go | 294 + plugins/processors/date/sample.conf | 24 + plugins/processors/dedup/README.md | 36 + plugins/processors/dedup/dedup.go | 161 + plugins/processors/dedup/dedup_test.go | 532 + plugins/processors/dedup/sample.conf | 4 + plugins/processors/defaults/README.md | 65 + plugins/processors/defaults/defaults.go | 56 + plugins/processors/defaults/defaults_test.go | 200 + plugins/processors/defaults/sample.conf | 15 + plugins/processors/deprecations.go | 6 + plugins/processors/enum/README.md | 61 + plugins/processors/enum/enum.go | 165 + plugins/processors/enum/enum_test.go | 219 + plugins/processors/enum/sample.conf | 23 + plugins/processors/execd/README.md | 139 + .../multiplier_line_protocol/multiplier.conf | 14 + .../multiplier_line_protocol.rb | 27 + plugins/processors/execd/execd.go | 184 + plugins/processors/execd/execd_test.go | 492 + plugins/processors/execd/sample.conf | 20 + .../testcases/dataformat-influx/expected.out | 5 + .../testcases/dataformat-influx/input.influx | 5 + .../testcases/dataformat-influx/telegraf.conf | 3 + .../testcases/dataformat-json/expected.out | 5 + .../testcases/dataformat-json/input.influx | 5 + .../testcases/dataformat-json/telegraf.conf | 6 + .../execd/testcases/defaults/expected.out | 5 + .../execd/testcases/defaults/input.influx | 5 + .../execd/testcases/defaults/telegraf.conf | 2 + .../execd/testcases/pass-through.go | 18 + plugins/processors/filepath/README.md | 227 + plugins/processors/filepath/filepath.go | 125 + plugins/processors/filepath/filepath_test.go | 134 + .../filepath/filepath_test_helpers.go | 100 + .../filepath/filepath_windows_test.go | 43 + plugins/processors/filepath/sample.conf | 30 + plugins/processors/filter/README.md | 83 + plugins/processors/filter/filter.go | 75 + plugins/processors/filter/filter_test.go | 738 + plugins/processors/filter/rule.go | 87 + plugins/processors/filter/sample.conf | 28 + plugins/processors/ifname/README.md | 102 + plugins/processors/ifname/cache.go | 83 + plugins/processors/ifname/cache_test.go | 23 + plugins/processors/ifname/ifname.go | 330 + plugins/processors/ifname/ifname_test.go | 232 + plugins/processors/ifname/sample.conf | 59 + plugins/processors/ifname/ttl_cache.go | 62 + plugins/processors/ifname/ttl_cache_test.go | 43 + plugins/processors/lookup/README.md | 159 + plugins/processors/lookup/lookup.go | 215 + plugins/processors/lookup/lookup_test.go | 178 + plugins/processors/lookup/sample.conf | 18 + .../multiple_files_json/expected.out | 5 + .../multiple_files_json/input.influx | 5 + .../multiple_files_json/lut_hugin.json | 9 + .../multiple_files_json/lut_munin.json | 6 + .../multiple_files_json/lut_thor.json | 7 + .../multiple_files_json/telegraf.conf | 7 + .../testcases/non_existing_tag/expected.out | 3 + .../testcases/non_existing_tag/input.influx | 3 + .../testcases/non_existing_tag/lut.json | 8 + .../testcases/non_existing_tag/telegraf.conf | 3 + .../expected.out | 5 + .../input.influx | 5 + .../normal_lookup_csv_key_name_value/lut.csv | 5 + .../telegraf.conf | 4 + .../normal_lookup_csv_key_values/expected.out | 5 + .../normal_lookup_csv_key_values/input.influx | 5 + .../normal_lookup_csv_key_values/lut.csv | 7 + .../telegraf.conf | 4 + .../testcases/normal_lookup_json/expected.out | 5 + .../testcases/normal_lookup_json/input.influx | 5 + .../testcases/normal_lookup_json/lut.json | 18 + .../normal_lookup_json/telegraf.conf | 3 + plugins/processors/noise/README.md | 97 + plugins/processors/noise/noise.go | 136 + plugins/processors/noise/noise_test.go | 467 + plugins/processors/noise/sample.conf | 21 + plugins/processors/override/README.md | 45 + plugins/processors/override/override.go | 47 + plugins/processors/override/override_test.go | 164 + plugins/processors/override/sample.conf | 10 + plugins/processors/parser/README.md | 70 + plugins/processors/parser/parser.go | 201 + plugins/processors/parser/parser_test.go | 1080 ++ plugins/processors/parser/sample.conf | 31 + plugins/processors/pivot/README.md | 40 + plugins/processors/pivot/pivot.go | 46 + plugins/processors/pivot/pivot_test.go | 198 + plugins/processors/pivot/sample.conf | 6 + plugins/processors/port_name/README.md | 53 + plugins/processors/port_name/port_name.go | 214 + .../processors/port_name/port_name_test.go | 457 + plugins/processors/port_name/sample.conf | 18 + plugins/processors/port_name/services_path.go | 12 + .../port_name/services_path_notwindows.go | 24 + plugins/processors/printer/README.md | 42 + plugins/processors/printer/printer.go | 39 + plugins/processors/printer/printer_test.go | 94 + plugins/processors/printer/sample.conf | 21 + plugins/processors/regex/README.md | 243 + plugins/processors/regex/converter.go | 269 + plugins/processors/regex/regex.go | 105 + plugins/processors/regex/regex_test.go | 1094 ++ plugins/processors/regex/sample.conf | 66 + plugins/processors/registry.go | 32 + plugins/processors/rename/README.md | 46 + plugins/processors/rename/rename.go | 68 + plugins/processors/rename/rename_test.go | 129 + plugins/processors/rename/sample.conf | 18 + plugins/processors/reverse_dns/README.md | 82 + plugins/processors/reverse_dns/rdnscache.go | 309 + .../processors/reverse_dns/rdnscache_test.go | 142 + plugins/processors/reverse_dns/reverse_dns.go | 109 + .../reverse_dns/reverse_dns_test.go | 133 + plugins/processors/reverse_dns/sample.conf | 46 + plugins/processors/s2geo/README.md | 41 + plugins/processors/s2geo/s2geo.go | 67 + plugins/processors/s2geo/s2geo_test.go | 124 + plugins/processors/s2geo/sample.conf | 12 + plugins/processors/scale/README.md | 83 + plugins/processors/scale/sample.conf | 27 + plugins/processors/scale/scale.go | 147 + plugins/processors/scale/scale_test.go | 552 + plugins/processors/snmp_lookup/README.md | 138 + plugins/processors/snmp_lookup/backlog.go | 105 + plugins/processors/snmp_lookup/lookup.go | 186 + plugins/processors/snmp_lookup/lookup_test.go | 632 + plugins/processors/snmp_lookup/sample.conf | 77 + plugins/processors/snmp_lookup/store.go | 124 + plugins/processors/snmp_lookup/store_test.go | 99 + plugins/processors/split/README.md | 72 + plugins/processors/split/sample.conf | 17 + plugins/processors/split/split.go | 111 + plugins/processors/split/split_test.go | 155 + .../split/testcases/drop_original/config.toml | 8 + .../testcases/drop_original/expected.out | 2 + .../testcases/drop_original/input.influx | 1 + .../split/testcases/globs/config.toml | 9 + .../split/testcases/globs/expected.out | 3 + .../split/testcases/globs/input.influx | 1 + .../split/testcases/nomatches/config.toml | 7 + .../split/testcases/nomatches/expected.out | 1 + .../split/testcases/nomatches/input.influx | 1 + .../split/testcases/singlemetric/config.toml | 7 + .../split/testcases/singlemetric/expected.out | 3 + .../split/testcases/singlemetric/input.influx | 1 + .../split/testcases/tags/config.toml | 9 + .../split/testcases/tags/expected.out | 3 + .../split/testcases/tags/input.influx | 1 + plugins/processors/starlark/README.md | 291 + plugins/processors/starlark/sample.conf | 21 + plugins/processors/starlark/starlark.go | 142 + plugins/processors/starlark/starlark_test.go | 3824 +++++ .../starlark/testdata/compare_metrics.star | 26 + .../drop_fields_with_unexpected_type.star | 30 + .../starlark/testdata/drop_string_fields.star | 14 + .../processors/starlark/testdata/fail.star | 13 + .../processors/starlark/testdata/iops.star | 55 + .../processors/starlark/testdata/json.star | 18 + .../starlark/testdata/json_nested.star | 46 + .../processors/starlark/testdata/logging.star | 19 + .../processors/starlark/testdata/math.star | 14 + .../starlark/testdata/multiple_metrics.star | 26 + .../testdata/multiple_metrics_with_json.star | 27 + .../starlark/testdata/number_logic.star | 17 + .../processors/starlark/testdata/pivot.star | 17 + .../processors/starlark/testdata/ratio.star | 15 + .../processors/starlark/testdata/rename.star | 23 + .../rename_prometheus_remote_write.star | 16 + .../processors/starlark/testdata/scale.star | 13 + .../starlark/testdata/schema_sizing.star | 96 + .../starlark/testdata/sparkplug.star | 320 + .../starlark/testdata/time_date.star | 19 + .../starlark/testdata/time_duration.star | 17 + .../starlark/testdata/time_set_timestamp.star | 15 + .../starlark/testdata/time_timestamp.star | 22 + .../testdata/time_timestamp_nanos.star | 22 + .../starlark/testdata/value_filter.star | 18 + plugins/processors/streamingprocessor.go | 61 + plugins/processors/strings/README.md | 186 + plugins/processors/strings/sample.conf | 59 + plugins/processors/strings/strings.go | 289 + plugins/processors/strings/strings_test.go | 1201 ++ plugins/processors/tag_limit/README.md | 37 + plugins/processors/tag_limit/sample.conf | 7 + plugins/processors/tag_limit/tag_limit.go | 78 + .../processors/tag_limit/tag_limit_test.go | 153 + plugins/processors/template/README.md | 134 + plugins/processors/template/sample.conf | 11 + plugins/processors/template/template.go | 85 + .../processors/template/template_metric.go | 74 + plugins/processors/template/template_test.go | 344 + plugins/processors/timestamp/README.md | 98 + plugins/processors/timestamp/sample.conf | 36 + plugins/processors/timestamp/timestamp.go | 107 + .../processors/timestamp/timestamp_test.go | 165 + plugins/processors/topk/README.md | 133 + plugins/processors/topk/sample.conf | 55 + plugins/processors/topk/test_sets.go | 164 + plugins/processors/topk/topk.go | 379 + plugins/processors/topk/topk_test.go | 581 + plugins/processors/unpivot/README.md | 56 + plugins/processors/unpivot/sample.conf | 15 + plugins/processors/unpivot/unpivot.go | 82 + plugins/processors/unpivot/unpivot_test.go | 334 + plugins/secretstores/README.md | 11 + plugins/secretstores/all/all.go | 1 + plugins/secretstores/all/docker.go | 5 + plugins/secretstores/all/http.go | 5 + plugins/secretstores/all/jose.go | 5 + plugins/secretstores/all/oauth2.go | 5 + plugins/secretstores/all/os.go | 5 + plugins/secretstores/all/systemd.go | 5 + plugins/secretstores/deprecations.go | 6 + plugins/secretstores/docker/README.md | 93 + plugins/secretstores/docker/docker.go | 92 + plugins/secretstores/docker/docker_test.go | 144 + plugins/secretstores/docker/sample.conf | 16 + .../docker/testdata/secret-file-1 | 1 + .../secretstores/docker/testdata/secretFile | 1 + .../docker/testdata/secret_file_2 | 1 + plugins/secretstores/http/README.md | 175 + plugins/secretstores/http/aes.go | 172 + plugins/secretstores/http/aes_test.go | 319 + plugins/secretstores/http/decryption.go | 47 + plugins/secretstores/http/decryption_test.go | 22 + plugins/secretstores/http/http.go | 241 + plugins/secretstores/http/http_test.go | 433 + plugins/secretstores/http/key_derivation.go | 53 + .../secretstores/http/key_derivation_test.go | 91 + plugins/secretstores/http/sample.conf | 85 + .../http/testcases/aes-cbc-kdf/expected.json | 6 + .../http/testcases/aes-cbc-kdf/secrets.json | 6 + .../http/testcases/aes-cbc-kdf/telegraf.conf | 12 + .../http/testcases/aes-cbc-key/expected.json | 6 + .../http/testcases/aes-cbc-key/secrets.json | 6 + .../http/testcases/aes-cbc-key/telegraf.conf | 9 + .../http/testcases/mixed/expected.json | 10 + .../http/testcases/mixed/secrets.json | 30 + .../http/testcases/mixed/telegraf.conf | 15 + .../plain-list-complex/expected.json | 10 + .../testcases/plain-list-complex/secrets.json | 30 + .../plain-list-complex/telegraf.conf | 4 + .../testcases/plain-list-simple/expected.json | 6 + .../testcases/plain-list-simple/secrets.json | 18 + .../testcases/plain-list-simple/telegraf.conf | 4 + .../plain-no-transform/expected.json | 6 + .../testcases/plain-no-transform/secrets.json | 6 + .../plain-no-transform/telegraf.conf | 3 + plugins/secretstores/jose/README.md | 53 + plugins/secretstores/jose/jose.go | 115 + plugins/secretstores/jose/jose_test.go | 203 + plugins/secretstores/jose/sample.conf | 13 + plugins/secretstores/oauth2/README.md | 136 + plugins/secretstores/oauth2/oauth2.go | 200 + plugins/secretstores/oauth2/oauth2_test.go | 364 + plugins/secretstores/oauth2/sample.conf | 42 + plugins/secretstores/os/README.md | 125 + plugins/secretstores/os/os.go | 101 + plugins/secretstores/os/os_darwin.go | 29 + plugins/secretstores/os/os_linux.go | 19 + plugins/secretstores/os/os_test.go | 89 + plugins/secretstores/os/os_unsupported.go | 1 + plugins/secretstores/os/os_windows.go | 15 + plugins/secretstores/os/sample.conf | 24 + plugins/secretstores/registry.go | 16 + plugins/secretstores/systemd/README.md | 246 + plugins/secretstores/systemd/sample.conf | 15 + plugins/secretstores/systemd/systemd.go | 139 + .../secretstores/systemd/systemd_nonlinux.go | 1 + plugins/secretstores/systemd/systemd_test.go | 175 + .../systemd/testdata/secret-file-1 | 1 + .../secretstores/systemd/testdata/secretFile | 1 + .../systemd/testdata/secret_file_2 | 1 + plugins/serializers/EXAMPLE_README.md | 47 + plugins/serializers/all/all.go | 1 + plugins/serializers/all/binary.go | 7 + plugins/serializers/all/carbon2.go | 7 + plugins/serializers/all/cloudevents.go | 7 + plugins/serializers/all/csv.go | 7 + plugins/serializers/all/graphite.go | 7 + plugins/serializers/all/influx.go | 7 + plugins/serializers/all/json.go | 7 + plugins/serializers/all/msgpack.go | 7 + plugins/serializers/all/nowmetric.go | 7 + plugins/serializers/all/prometheus.go | 7 + .../serializers/all/prometheusremotewrite.go | 7 + plugins/serializers/all/splunkmetric.go | 7 + plugins/serializers/all/template.go | 7 + plugins/serializers/all/wavefront.go | 7 + plugins/serializers/binary/README.md | 134 + plugins/serializers/binary/binary.go | 108 + plugins/serializers/binary/binary_test.go | 121 + plugins/serializers/binary/entry.go | 133 + plugins/serializers/binary/entry_test.go | 305 + .../serializers/binary/type_conversions.go | 110 + plugins/serializers/carbon2/README.md | 98 + plugins/serializers/carbon2/carbon2.go | 119 + plugins/serializers/carbon2/carbon2_test.go | 442 + plugins/serializers/cloudevents/README.md | 64 + .../serializers/cloudevents/cloudevents.go | 199 + .../cloudevents/cloudevents_test.go | 271 + .../testcases/batch-events/expected.json | 478 + .../testcases/batch-events/input.influx | 17 + .../testcases/batch-events/telegraf.conf | 3 + .../testcases/batch-metrics/expected.json | 112 + .../testcases/batch-metrics/input.influx | 5 + .../testcases/batch-metrics/telegraf.conf | 5 + .../testcases/cloudevents-v0.3-schema.json | 79 + .../testcases/cloudevents-v1.0-schema.json | 128 + .../testcases/single-multiple/expected.json | 478 + .../testcases/single-multiple/input.influx | 17 + .../testcases/single-multiple/telegraf.conf | 2 + .../single-source-overwrite/expected.json | 30 + .../single-source-overwrite/input.influx | 1 + .../single-source-overwrite/telegraf.conf | 3 + .../single-sourcetag-overwrite/expected.json | 142 + .../single-sourcetag-overwrite/input.influx | 5 + .../single-sourcetag-overwrite/telegraf.conf | 3 + .../testcases/single/expected.json | 30 + .../cloudevents/testcases/single/input.influx | 1 + .../testcases/single/telegraf.conf | 2 + plugins/serializers/csv/README.md | 69 + plugins/serializers/csv/csv.go | 245 + plugins/serializers/csv/csv_test.go | 261 + plugins/serializers/csv/testcases/basic.conf | 8 + plugins/serializers/csv/testcases/basic.csv | 2 + plugins/serializers/csv/testcases/header.conf | 10 + plugins/serializers/csv/testcases/header.csv | 3 + .../csv/testcases/nanoseconds.conf | 10 + .../serializers/csv/testcases/nanoseconds.csv | 2 + .../serializers/csv/testcases/ordered.conf | 11 + plugins/serializers/csv/testcases/ordered.csv | 2 + .../csv/testcases/ordered_not_exist.conf | 12 + .../csv/testcases/ordered_not_exist.csv | 3 + .../csv/testcases/ordered_with_header.conf | 12 + .../csv/testcases/ordered_with_header.csv | 3 + .../testcases/ordered_with_header_prefix.conf | 13 + .../testcases/ordered_with_header_prefix.csv | 3 + plugins/serializers/csv/testcases/prefix.conf | 11 + plugins/serializers/csv/testcases/prefix.csv | 3 + .../serializers/csv/testcases/rfc3339.conf | 11 + plugins/serializers/csv/testcases/rfc3339.csv | 3 + .../serializers/csv/testcases/semicolon.conf | 11 + .../serializers/csv/testcases/semicolon.csv | 3 + plugins/serializers/deprecations.go | 6 + plugins/serializers/graphite/README.md | 90 + plugins/serializers/graphite/graphite.go | 362 + plugins/serializers/graphite/graphite_test.go | 1246 ++ plugins/serializers/influx/README.md | 51 + plugins/serializers/influx/escape.go | 59 + plugins/serializers/influx/influx.go | 335 + plugins/serializers/influx/influx_test.go | 575 + plugins/serializers/influx/reader.go | 70 + plugins/serializers/influx/reader_test.go | 262 + plugins/serializers/json/README.md | 309 + plugins/serializers/json/json.go | 169 + plugins/serializers/json/json_test.go | 514 + .../json/testcases/nested_fields_exclude.conf | 6 + .../json/testcases/nested_fields_include.conf | 6 + .../json/testcases/nested_fields_out.json | 23 + .../json/testcases/transformation_batch.conf | 24 + .../testcases/transformation_batch_out.json | 32 + .../json/testcases/transformation_single.conf | 24 + .../testcases/transformation_single_out.json | 32 + plugins/serializers/msgpack/README.md | 43 + plugins/serializers/msgpack/metric.go | 104 + plugins/serializers/msgpack/metric_gen.go | 417 + .../serializers/msgpack/metric_gen_test.go | 236 + plugins/serializers/msgpack/metric_test.go | 162 + plugins/serializers/msgpack/msgpack.go | 47 + plugins/serializers/msgpack/msgpack_test.go | 154 + plugins/serializers/nowmetric/README.md | 135 + plugins/serializers/nowmetric/nowmetric.go | 137 + .../serializers/nowmetric/nowmetric_test.go | 270 + plugins/serializers/prometheus/README.md | 96 + plugins/serializers/prometheus/collection.go | 488 + .../serializers/prometheus/collection_test.go | 845 + plugins/serializers/prometheus/convert.go | 197 + plugins/serializers/prometheus/prometheus.go | 95 + .../serializers/prometheus/prometheus_test.go | 786 + .../prometheusremotewrite/README.md | 45 + .../prometheusremotewrite.go | 357 + .../prometheusremotewrite_test.go | 829 + plugins/serializers/registry.go | 14 + plugins/serializers/splunkmetric/README.md | 197 + .../serializers/splunkmetric/splunkmetric.go | 217 + .../splunkmetric/splunkmetric_test.go | 290 + plugins/serializers/template/README.md | 45 + plugins/serializers/template/template.go | 102 + plugins/serializers/template/template_test.go | 205 + plugins/serializers/test_benchmark.go | 31 + plugins/serializers/wavefront/README.md | 51 + plugins/serializers/wavefront/replacers.go | 31 + plugins/serializers/wavefront/wavefront.go | 196 + .../serializers/wavefront/wavefront_test.go | 311 + processor.go | 41 + scripts/check-deps.sh | 94 + scripts/check-file-changes.sh | 12 + scripts/check-plugin-doc-embedding.sh | 71 + scripts/ci.docker | 23 + scripts/deb/post-install.sh | 79 + scripts/deb/post-remove.sh | 33 + scripts/deb/pre-install.sh | 24 + scripts/deb/pre-remove.sh | 10 + scripts/init.sh | 220 + scripts/install_gotestsum.sh | 53 + scripts/install_incus.sh | 47 + scripts/installgo_linux.sh | 37 + scripts/installgo_mac.sh | 53 + scripts/installgo_windows.sh | 25 + scripts/local_circleci.sh | 6 + scripts/mac-signing.sh | 139 + scripts/make_docs.sh | 10 + scripts/rpm/post-install.sh | 50 + scripts/rpm/post-remove.sh | 19 + scripts/rpm/pre-install.sh | 24 + scripts/sign-windows.sh | 44 + scripts/telegraf.service | 22 + scripts/telegraf_entry_mac | 13 + scripts/windows-gen-syso.sh | 19 + secretstore.go | 25 + selfstat/selfstat.go | 197 + selfstat/selfstat_test.go | 213 + selfstat/stat.go | 42 + selfstat/timingStat.go | 58 + serializer.go | 38 + testutil/accumulator.go | 767 + testutil/capturelog.go | 149 + testutil/container.go | 217 + testutil/container_test.go | 72 + testutil/file.go | 139 + testutil/log.go | 75 + testutil/metric.go | 399 + testutil/metric_test.go | 260 + testutil/pki/cacert.pem | 18 + testutil/pki/cakey.pem | 28 + testutil/pki/client.pem | 45 + testutil/pki/clientcert.pem | 18 + testutil/pki/clientenc.pem | 48 + testutil/pki/clientenckey.pem | 30 + testutil/pki/clientenckey.pkcs8.pem | 30 + testutil/pki/clientkey.pem | 27 + testutil/pki/clientkey.pkcs8.pem | 28 + testutil/pki/server.pem | 45 + testutil/pki/servercert.pem | 18 + testutil/pki/serverkey.pem | 27 + testutil/pki/tls-certs.sh | 90 + testutil/plugin_input/plugin.go | 177 + testutil/plugin_input/sample.conf | 15 + testutil/socket.go | 32 + testutil/testutil.go | 137 + testutil/testutil_test.go | 39 + testutil/tls.go | 159 + tools/config_includer/generator.go | 142 + tools/custom_builder/README.md | 102 + tools/custom_builder/config.go | 232 + tools/custom_builder/main.go | 178 + tools/custom_builder/main_test.go | 56 + tools/custom_builder/packages.go | 345 + .../testcases/issue_13592/expected.tags | 5 + .../testcases/issue_13592/telegraf.conf | 65 + .../testcases/issue_15627/expected.tags | 4 + .../testcases/issue_15627/telegraf.conf | 39 + tools/license_checker/README.md | 93 + tools/license_checker/data/spdx_mapping.json | 15 + tools/license_checker/data/whitelist | 2 + tools/license_checker/main.go | 245 + tools/license_checker/package.go | 102 + tools/license_checker/whitelist.go | 119 + tools/package_incus_test/README.md | 24 + tools/package_incus_test/container.go | 361 + tools/package_incus_test/incus.go | 195 + tools/package_incus_test/main.go | 116 + tools/readme_config_includer/generator.go | 250 + tools/readme_linter/README.md | 29 + tools/readme_linter/assert.go | 158 + tools/readme_linter/main.go | 149 + tools/readme_linter/plugin.go | 36 + tools/readme_linter/rules.go | 456 + tools/readme_linter/set.go | 32 + tools/update_goversion/README.md | 12 + tools/update_goversion/main.go | 216 + tools/update_goversion/main_test.go | 46 + .../testdata/godev_minor.html | 192 + .../testdata/godev_patch.html | 192 + 4963 files changed, 677545 insertions(+) create mode 100644 .circleci/config.yml create mode 100644 .gitattributes create mode 100644 .github/ISSUE_TEMPLATE/BUG_REPORT.yml create mode 100644 .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml create mode 100644 .github/ISSUE_TEMPLATE/SUPPORT.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/linter.yml create mode 100644 .github/workflows/milestones.yml create mode 100644 .github/workflows/pr-target-branch.yml create mode 100644 .github/workflows/readme-linter.yml create mode 100644 .github/workflows/semantic.yml create mode 100644 .gitignore create mode 100644 .golangci.yml create mode 100644 .markdownlint.yml create mode 100644 .markdownlintignore create mode 100644 CHANGELOG-1.13.md create mode 100644 CHANGELOG.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 EXTERNAL_PLUGINS.md create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 SECURITY.md create mode 100644 accumulator.go create mode 100644 agent/README.md create mode 100644 agent/accumulator.go create mode 100644 agent/accumulator_test.go create mode 100644 agent/agent.go create mode 100644 agent/agent_posix.go create mode 100644 agent/agent_test.go create mode 100644 agent/agent_windows.go create mode 100644 agent/testcases/aggregators-rerun-processors/expected.out create mode 100644 agent/testcases/aggregators-rerun-processors/input.influx create mode 100644 agent/testcases/aggregators-rerun-processors/telegraf.conf create mode 100644 agent/testcases/aggregators-skip-processors/expected.out create mode 100644 agent/testcases/aggregators-skip-processors/input.influx create mode 100644 agent/testcases/aggregators-skip-processors/telegraf.conf create mode 100644 agent/testcases/processor-order-appearance/expected.out create mode 100644 agent/testcases/processor-order-appearance/input.influx create mode 100644 agent/testcases/processor-order-appearance/telegraf.conf create mode 100644 agent/testcases/processor-order-explicit/expected.out create mode 100644 agent/testcases/processor-order-explicit/input.influx create mode 100644 agent/testcases/processor-order-explicit/telegraf.conf create mode 100644 agent/testcases/processor-order-mixed/expected.out create mode 100644 agent/testcases/processor-order-mixed/input.influx create mode 100644 agent/testcases/processor-order-mixed/telegraf.conf create mode 100644 agent/testcases/processor-order-no-starlark/expected.out create mode 100644 agent/testcases/processor-order-no-starlark/input.influx create mode 100644 agent/testcases/processor-order-no-starlark/telegraf.conf create mode 100644 agent/tick.go create mode 100644 agent/tick_test.go create mode 100644 aggregator.go create mode 100644 assets/GopherAndTiger.png create mode 100644 assets/TelegrafTiger.png create mode 100644 assets/TelegrafTigerSmall.png create mode 100644 assets/windows/icon.icns create mode 100644 assets/windows/tiger.ico create mode 100644 build_version.txt create mode 120000 cmd/telegraf/README.md create mode 100644 cmd/telegraf/agent.conf create mode 100644 cmd/telegraf/cmd_config.go create mode 100644 cmd/telegraf/cmd_plugins.go create mode 100644 cmd/telegraf/cmd_secretstore.go create mode 100644 cmd/telegraf/cmd_win_service.go create mode 100644 cmd/telegraf/cmd_win_service_notwindows.go create mode 100644 cmd/telegraf/main.go create mode 100644 cmd/telegraf/main_test.go create mode 100644 cmd/telegraf/main_win_test.go create mode 100644 cmd/telegraf/pprof.go create mode 100644 cmd/telegraf/printer.go create mode 100644 cmd/telegraf/telegraf.go create mode 100644 cmd/telegraf/telegraf_posix.go create mode 100644 cmd/telegraf/telegraf_windows.go create mode 120000 config/README.md create mode 100644 config/config.go create mode 100644 config/config_test.go create mode 100644 config/deprecation.go create mode 100644 config/deprecation_test.go create mode 100644 config/envvar.go create mode 100644 config/internal_test.go create mode 100644 config/migration.go create mode 100644 config/plugin_id.go create mode 100644 config/plugin_printer.go create mode 100644 config/secret.go create mode 100644 config/secret_protected.go create mode 100644 config/secret_test.go create mode 100644 config/secret_unprotected.go create mode 100644 config/testdata/addressbook.proto create mode 100644 config/testdata/azure_monitor.toml create mode 100644 config/testdata/default_parser.toml create mode 100644 config/testdata/default_parser_exec.toml create mode 100644 config/testdata/deprecated_field_filter.toml create mode 100644 config/testdata/envvar_comments.toml create mode 100644 config/testdata/envvar_comments_expected.toml create mode 100644 config/testdata/filter_metricpass.toml create mode 100644 config/testdata/inline_table.toml create mode 100644 config/testdata/invalid_field.toml create mode 100644 config/testdata/invalid_field_in_parser_table.toml create mode 100644 config/testdata/invalid_field_in_parserfunc_table.toml create mode 100644 config/testdata/invalid_field_processor.toml create mode 100644 config/testdata/invalid_field_processor_in_parser.toml create mode 100644 config/testdata/invalid_field_processor_in_parser_table.toml create mode 100644 config/testdata/invalid_field_processor_in_parserfunc.toml create mode 100644 config/testdata/invalid_field_processor_in_parserfunc_table.toml create mode 100644 config/testdata/invalid_field_processor_with_parser.toml create mode 100644 config/testdata/invalid_field_processor_with_parserfunc.toml create mode 100644 config/testdata/invalid_field_with_parser.toml create mode 100644 config/testdata/invalid_field_with_parserfunc.toml create mode 100644 config/testdata/non_slice_slice.toml create mode 100644 config/testdata/parsers_new.toml create mode 100644 config/testdata/processor_order/multiple_processors.toml create mode 100644 config/testdata/processor_order/multiple_processors_messy_order.toml create mode 100644 config/testdata/processor_order/multiple_processors_simple_order.toml create mode 100644 config/testdata/processors_with_parsers.toml create mode 100644 config/testdata/serializers_new.toml create mode 100644 config/testdata/serializers_old.toml create mode 100644 config/testdata/single_plugin.toml create mode 100644 config/testdata/single_plugin_env_vars.toml create mode 100644 config/testdata/single_plugin_with_comment_in_array.toml create mode 100644 config/testdata/single_plugin_with_separators.toml create mode 100644 config/testdata/slice_comment.toml create mode 100644 config/testdata/special_types.key create mode 100644 config/testdata/special_types.pem create mode 100644 config/testdata/special_types.toml create mode 100644 config/testdata/state_persistence_input_all_different.toml create mode 100644 config/testdata/state_persistence_input_all_same.toml create mode 100644 config/testdata/state_persistence_input_store_load.toml create mode 100644 config/testdata/state_persistence_processors.toml create mode 100644 config/testdata/subconfig/exec.conf create mode 100644 config/testdata/subconfig/memcached.conf create mode 100644 config/testdata/subconfig/procstat.conf create mode 100644 config/testdata/telegraf-agent.toml create mode 100644 config/testdata/wrong_cert_path.toml create mode 100644 config/testdata/wrong_field_type.toml create mode 100644 config/testdata/wrong_field_type2.toml create mode 100644 config/types.go create mode 100644 config/types_test.go create mode 100644 docs/AGGREGATORS.md create mode 100644 docs/AGGREGATORS_AND_PROCESSORS.md create mode 100644 docs/APPARMOR.md create mode 100644 docs/COMMANDS_AND_FLAGS.md create mode 100644 docs/CONFIGURATION.md create mode 100644 docs/CUSTOMIZATION.md create mode 100644 docs/DATA_FORMATS_INPUT.md create mode 100644 docs/DATA_FORMATS_OUTPUT.md create mode 100644 docs/DOCKER.md create mode 100644 docs/EXTERNAL_PLUGINS.md create mode 100644 docs/FAQ.md create mode 100644 docs/INPUTS.md create mode 100644 docs/INSTALL_GUIDE.md create mode 100644 docs/INTEGRATION_TESTS.md create mode 100644 docs/LICENSE_OF_DEPENDENCIES.md create mode 100644 docs/METRICS.md create mode 100644 docs/NIGHTLIES.md create mode 100644 docs/OUTPUTS.md create mode 100644 docs/PARSING_DATA.md create mode 100644 docs/PROCESSORS.md create mode 100644 docs/PROFILING.md create mode 100644 docs/QUICK_START.md create mode 100644 docs/README.md create mode 100644 docs/RELEASES.md create mode 100644 docs/SECRETSTORES.md create mode 100644 docs/SQL_DRIVERS_INPUT.md create mode 100644 docs/SUPPORTED_PLATFORMS.md create mode 100644 docs/TEMPLATE_PATTERN.md create mode 100644 docs/TLS.md create mode 100644 docs/TOML.md create mode 100644 docs/WINDOWS_SERVICE.md create mode 100644 docs/developers/CODE_STYLE.md create mode 100644 docs/developers/DEBUG.md create mode 100644 docs/developers/DEPRECATION.md create mode 100644 docs/developers/LOGGING.md create mode 100644 docs/developers/METRIC_FORMAT_CHANGES.md create mode 100644 docs/developers/PACKAGING.md create mode 100644 docs/developers/PROFILING.md create mode 120000 docs/developers/README.md create mode 100644 docs/developers/REVIEWS.md create mode 100644 docs/developers/SAMPLE_CONFIG.md create mode 100644 docs/developers/STATE_PERSISTENCE.md create mode 100644 docs/includes/plugin_config.md create mode 100644 docs/includes/secret_usage.md create mode 100644 docs/includes/service_input.md create mode 100644 docs/includes/startup_error_behavior.md create mode 100644 docs/specs/README.md create mode 100644 docs/specs/template.md create mode 100644 docs/specs/tsd-001-deprecation.md create mode 100644 docs/specs/tsd-002-custom-builder.md create mode 100644 docs/specs/tsd-003-state-persistence.md create mode 100644 docs/specs/tsd-004-configuration-migration.md create mode 100644 docs/specs/tsd-005-output-buffer-strategy.md create mode 100644 docs/specs/tsd-006-startup-error-behavior.md create mode 100644 docs/specs/tsd-007-url-config-behavior.md create mode 100644 docs/specs/tsd-008-partial-write-error-handling.md create mode 100644 docs/specs/tsd-009-probe-on-startup.md create mode 100644 etc/logrotate.d/telegraf create mode 100644 filter/filter.go create mode 100644 filter/filter_test.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 info.plist create mode 100644 input.go create mode 100644 internal/choice/choice.go create mode 100644 internal/content_coding.go create mode 100644 internal/content_coding_test.go create mode 100644 internal/customized_no.go create mode 100644 internal/customized_yes.go create mode 100644 internal/docker/docker.go create mode 100644 internal/docker/docker_test.go create mode 100644 internal/env.go create mode 100644 internal/errors.go create mode 100644 internal/exec.go create mode 100644 internal/exec_unix.go create mode 100644 internal/exec_windows.go create mode 100644 internal/fuzz/json.go create mode 100644 internal/globpath/globpath.go create mode 100644 internal/globpath/globpath_test.go create mode 100644 internal/globpath/testdata/log1.log create mode 100644 internal/globpath/testdata/log2.log create mode 100644 internal/globpath/testdata/log[!.log create mode 100644 internal/globpath/testdata/nested1/nested2/nested.txt create mode 100644 internal/globpath/testdata/test.conf create mode 100644 internal/goplugin/noplugin.go create mode 100644 internal/goplugin/plugin.go create mode 100644 internal/host_endianness_be.go create mode 100644 internal/host_endianness_le.go create mode 100644 internal/http.go create mode 100644 internal/internal.go create mode 100644 internal/internal_test.go create mode 100644 internal/limiter/limiter.go create mode 100644 internal/process/process.go create mode 100644 internal/process/process_posix.go create mode 100644 internal/process/process_test.go create mode 100644 internal/process/process_windows.go create mode 100644 internal/rotate/file_writer.go create mode 100644 internal/rotate/file_writer_test.go create mode 100644 internal/snmp/config.go create mode 100644 internal/snmp/field.go create mode 100644 internal/snmp/field_test.go create mode 100644 internal/snmp/mib_loader.go create mode 100644 internal/snmp/mib_loader_test.go create mode 100644 internal/snmp/table.go create mode 100644 internal/snmp/table_test.go create mode 100644 internal/snmp/testdata/gosmi/bridgeMib create mode 100644 internal/snmp/testdata/gosmi/bridgeMibImports create mode 100644 internal/snmp/testdata/gosmi/foo create mode 100644 internal/snmp/testdata/gosmi/fooImports create mode 100644 internal/snmp/testdata/gosmi/ifPhysAddress create mode 100644 internal/snmp/testdata/gosmi/ifPhysAddressImports create mode 100644 internal/snmp/testdata/gosmi/server create mode 100644 internal/snmp/testdata/gosmi/serverImports create mode 100644 internal/snmp/testdata/gosmi/tableBuild create mode 100644 internal/snmp/testdata/gosmi/tableMib create mode 100644 internal/snmp/testdata/gosmi/tableMibImports create mode 100644 internal/snmp/testdata/gosmi/tcpMib create mode 100644 internal/snmp/testdata/gosmi/tcpMibImports create mode 100644 internal/snmp/testdata/loadMibsFromPath/linkTarget/emptyFile create mode 100644 internal/snmp/testdata/loadMibsFromPath/root/dirOne/dirTwo/empty create mode 120000 internal/snmp/testdata/loadMibsFromPath/root/symlink create mode 100644 internal/snmp/testdata/mibs/testmib create mode 100644 internal/snmp/translator.go create mode 100644 internal/snmp/translator_gosmi.go create mode 100644 internal/snmp/translator_gosmi_test.go create mode 100644 internal/snmp/translator_netsnmp.go create mode 100644 internal/snmp/translator_netsnmp_mocks_generate.go create mode 100644 internal/snmp/translator_netsnmp_mocks_test.go create mode 100644 internal/snmp/translator_netsnmp_test.go create mode 100644 internal/snmp/wrapper.go create mode 100644 internal/snmp/wrapper_test.go create mode 100644 internal/templating/engine.go create mode 100644 internal/templating/engine_test.go create mode 100644 internal/templating/matcher.go create mode 100644 internal/templating/node.go create mode 100644 internal/templating/template.go create mode 100644 internal/templating/template_test.go create mode 100644 internal/type_conversions.go create mode 100644 logger.go create mode 100644 logger/event_logger.go create mode 100644 logger/event_logger_test.go create mode 100644 logger/handler.go create mode 100644 logger/logger.go create mode 100644 logger/logger_test.go create mode 100644 logger/registry.go create mode 100644 logger/stdlog_redirector.go create mode 100644 logger/structured_logger.go create mode 100644 logger/structured_logger_test.go create mode 100644 logger/text_logger.go create mode 100644 logger/text_logger_test.go create mode 100644 metric.go create mode 100644 metric/deserialize.go create mode 100644 metric/init.go create mode 100644 metric/metric.go create mode 100644 metric/metric_test.go create mode 100644 metric/series_grouper.go create mode 100644 metric/series_grouper_test.go create mode 100644 metric/tracking.go create mode 100644 metric/tracking_test.go create mode 100644 migrations/all/all.go create mode 100644 migrations/all/general_metricfilter.go create mode 100644 migrations/all/global_agent.go create mode 100644 migrations/all/inputs.nats_consumer.go create mode 100644 migrations/all/inputs_cassandra.go create mode 100644 migrations/all/inputs_disk.go create mode 100644 migrations/all/inputs_gnmi.go create mode 100644 migrations/all/inputs_httpjson.go create mode 100644 migrations/all/inputs_io.go create mode 100644 migrations/all/inputs_jolokia.go create mode 100644 migrations/all/inputs_kafka_consumer_legacy.go create mode 100644 migrations/all/inputs_mqtt_consumer.go create mode 100644 migrations/all/inputs_procstat.go create mode 100644 migrations/all/inputs_sflow.go create mode 100644 migrations/all/inputs_snmp_legacy.go create mode 100644 migrations/all/inputs_tcp_listener.go create mode 100644 migrations/all/inputs_udp_listener.go create mode 100644 migrations/all/outputs_influxdb.go create mode 100644 migrations/all/outputs_riemann_legacy.go create mode 100644 migrations/common/filter_options.go create mode 100644 migrations/common/input_options.go create mode 100644 migrations/common/output_options.go create mode 100644 migrations/general_metricfilter/migration.go create mode 100644 migrations/general_metricfilter/migration_test.go create mode 100644 migrations/general_metricfilter/testcases/deprecated_drop/expected.conf create mode 100644 migrations/general_metricfilter/testcases/deprecated_drop/telegraf.conf create mode 100644 migrations/general_metricfilter/testcases/deprecated_fielddrop/expected.conf create mode 100644 migrations/general_metricfilter/testcases/deprecated_fielddrop/telegraf.conf create mode 100644 migrations/general_metricfilter/testcases/deprecated_fieldpass/expected.conf create mode 100644 migrations/general_metricfilter/testcases/deprecated_fieldpass/telegraf.conf create mode 100644 migrations/general_metricfilter/testcases/deprecated_pass/expected.conf create mode 100644 migrations/general_metricfilter/testcases/deprecated_pass/telegraf.conf create mode 100644 migrations/general_metricfilter/testcases/merge_all_overlap/expected.conf create mode 100644 migrations/general_metricfilter/testcases/merge_all_overlap/telegraf.conf create mode 100644 migrations/general_metricfilter/testcases/merge_fieldexclude/expected.conf create mode 100644 migrations/general_metricfilter/testcases/merge_fieldexclude/telegraf.conf create mode 100644 migrations/general_metricfilter/testcases/merge_fieldexclude_overlap/expected.conf create mode 100644 migrations/general_metricfilter/testcases/merge_fieldexclude_overlap/telegraf.conf create mode 100644 migrations/general_metricfilter/testcases/merge_fieldinclude/expected.conf create mode 100644 migrations/general_metricfilter/testcases/merge_fieldinclude/telegraf.conf create mode 100644 migrations/general_metricfilter/testcases/merge_fieldinclude_overlap/expected.conf create mode 100644 migrations/general_metricfilter/testcases/merge_fieldinclude_overlap/telegraf.conf create mode 100644 migrations/global_agent/migration.go create mode 100644 migrations/global_agent/migration_test.go create mode 100644 migrations/global_agent/testcases/default.conf create mode 100644 migrations/global_agent/testcases/logtarget_eventlog/expected.conf create mode 100644 migrations/global_agent/testcases/logtarget_eventlog/telegraf.conf create mode 100644 migrations/global_agent/testcases/logtarget_eventlog_collision.conf create mode 100644 migrations/global_agent/testcases/logtarget_eventlog_with_logfile/expected.conf create mode 100644 migrations/global_agent/testcases/logtarget_eventlog_with_logfile/telegraf.conf create mode 100644 migrations/global_agent/testcases/logtarget_file/expected.conf create mode 100644 migrations/global_agent/testcases/logtarget_file/telegraf.conf create mode 100644 migrations/global_agent/testcases/logtarget_file_no_logfile/expected.conf create mode 100644 migrations/global_agent/testcases/logtarget_file_no_logfile/telegraf.conf create mode 100644 migrations/global_agent/testcases/logtarget_stderr/expected.conf create mode 100644 migrations/global_agent/testcases/logtarget_stderr/telegraf.conf create mode 100644 migrations/global_agent/testcases/logtarget_stderr_with_logfile/expected.conf create mode 100644 migrations/global_agent/testcases/logtarget_stderr_with_logfile/telegraf.conf create mode 100644 migrations/inputs_cassandra/migration.go create mode 100644 migrations/inputs_cassandra/migration_test.go create mode 100644 migrations/inputs_cassandra/testcases/filter_options/expected.conf create mode 100644 migrations/inputs_cassandra/testcases/filter_options/telegraf.conf create mode 100644 migrations/inputs_cassandra/testcases/general_options/expected.conf create mode 100644 migrations/inputs_cassandra/testcases/general_options/telegraf.conf create mode 100644 migrations/inputs_cassandra/testcases/simple/expected.conf create mode 100644 migrations/inputs_cassandra/testcases/simple/telegraf.conf create mode 100644 migrations/inputs_disk/migration.go create mode 100644 migrations/inputs_disk/migration_test.go create mode 100644 migrations/inputs_disk/testcases/deprecated_mountpoints/expected.conf create mode 100644 migrations/inputs_disk/testcases/deprecated_mountpoints/telegraf.conf create mode 100644 migrations/inputs_disk/testcases/deprecated_mountpoints_existing/expected.conf create mode 100644 migrations/inputs_disk/testcases/deprecated_mountpoints_existing/telegraf.conf create mode 100644 migrations/inputs_gnmi/migration.go create mode 100644 migrations/inputs_gnmi/migration_test.go create mode 100644 migrations/inputs_gnmi/testcases/deprecated_guess_path/expected.conf create mode 100644 migrations/inputs_gnmi/testcases/deprecated_guess_path/telegraf.conf create mode 100644 migrations/inputs_gnmi/testcases/deprecated_guess_path_false/expected.conf create mode 100644 migrations/inputs_gnmi/testcases/deprecated_guess_path_false/telegraf.conf create mode 100644 migrations/inputs_httpjson/migration.go create mode 100644 migrations/inputs_httpjson/migration_test.go create mode 100644 migrations/inputs_httpjson/testcases/array/expected.conf create mode 100644 migrations/inputs_httpjson/testcases/array/input.json create mode 100644 migrations/inputs_httpjson/testcases/array/output.influx create mode 100644 migrations/inputs_httpjson/testcases/array/telegraf.conf create mode 100644 migrations/inputs_httpjson/testcases/filters/expected.conf create mode 100644 migrations/inputs_httpjson/testcases/filters/telegraf.conf create mode 100644 migrations/inputs_httpjson/testcases/headers/expected.conf create mode 100644 migrations/inputs_httpjson/testcases/headers/telegraf.conf create mode 100644 migrations/inputs_httpjson/testcases/params/expected.conf create mode 100644 migrations/inputs_httpjson/testcases/params/telegraf.conf create mode 100644 migrations/inputs_httpjson/testcases/single/expected.conf create mode 100644 migrations/inputs_httpjson/testcases/single/input.json create mode 100644 migrations/inputs_httpjson/testcases/single/output.influx create mode 100644 migrations/inputs_httpjson/testcases/single/telegraf.conf create mode 100644 migrations/inputs_io/migration.go create mode 100644 migrations/inputs_io/migration_test.go create mode 100644 migrations/inputs_io/testcases/empty/expected.conf create mode 100644 migrations/inputs_io/testcases/empty/telegraf.conf create mode 100644 migrations/inputs_io/testcases/full/expected.conf create mode 100644 migrations/inputs_io/testcases/full/telegraf.conf create mode 100644 migrations/inputs_jolokia/README.md create mode 100644 migrations/inputs_jolokia/migration.go create mode 100644 migrations/inputs_jolokia/migration_test.go create mode 100644 migrations/inputs_jolokia/testcases/agent_default/expected.conf create mode 100644 migrations/inputs_jolokia/testcases/agent_default/telegraf.conf create mode 100644 migrations/inputs_jolokia/testcases/agent_more_complex/expected.conf create mode 100644 migrations/inputs_jolokia/testcases/agent_more_complex/telegraf.conf create mode 100644 migrations/inputs_jolokia/testcases/agent_response_timeout/expected.conf create mode 100644 migrations/inputs_jolokia/testcases/agent_response_timeout/telegraf.conf create mode 100644 migrations/inputs_jolokia/testcases/proxy_default/expected.conf create mode 100644 migrations/inputs_jolokia/testcases/proxy_default/telegraf.conf create mode 100644 migrations/inputs_kafka_consumer_legacy/README.md create mode 100644 migrations/inputs_kafka_consumer_legacy/migration.go create mode 100644 migrations/inputs_kafka_consumer_legacy/migration_test.go create mode 100644 migrations/inputs_mqtt_consumer/migration.go create mode 100644 migrations/inputs_mqtt_consumer/migration_test.go create mode 100644 migrations/inputs_mqtt_consumer/testcases/deprecated_metric_buffer/expected.conf create mode 100644 migrations/inputs_mqtt_consumer/testcases/deprecated_metric_buffer/telegraf.conf create mode 100644 migrations/inputs_mqtt_consumer/testcases/deprecated_metric_buffer_parser/expected.conf create mode 100644 migrations/inputs_mqtt_consumer/testcases/deprecated_metric_buffer_parser/telegraf.conf create mode 100644 migrations/inputs_nats_consumer/migration.go create mode 100644 migrations/inputs_nats_consumer/migration_test.go create mode 100644 migrations/inputs_nats_consumer/testcases/deprecated_metric_buffer/expected.conf create mode 100644 migrations/inputs_nats_consumer/testcases/deprecated_metric_buffer/telegraf.conf create mode 100644 migrations/inputs_nats_consumer/testcases/deprecated_metric_buffer_parser/expected.conf create mode 100644 migrations/inputs_nats_consumer/testcases/deprecated_metric_buffer_parser/telegraf.conf create mode 100644 migrations/inputs_procstat/migration.go create mode 100644 migrations/inputs_procstat/migration_test.go create mode 100644 migrations/inputs_procstat/testcases/deprecated_supervisor_unit merge/expected.conf create mode 100644 migrations/inputs_procstat/testcases/deprecated_supervisor_unit merge/telegraf.conf create mode 100644 migrations/inputs_procstat/testcases/deprecated_supervisor_unit/expected.conf create mode 100644 migrations/inputs_procstat/testcases/deprecated_supervisor_unit/telegraf.conf create mode 100644 migrations/inputs_procstat/testcases/deprecated_tagging_false/expected.conf create mode 100644 migrations/inputs_procstat/testcases/deprecated_tagging_false/telegraf.conf create mode 100644 migrations/inputs_procstat/testcases/deprecated_tagging_true/expected.conf create mode 100644 migrations/inputs_procstat/testcases/deprecated_tagging_true/telegraf.conf create mode 100644 migrations/inputs_procstat/testcases/deprecated_tagging_true_merge/expected.conf create mode 100644 migrations/inputs_procstat/testcases/deprecated_tagging_true_merge/telegraf.conf create mode 100644 migrations/inputs_procstat/testcases/deprecated_tagging_true_merge_overlap/expected.conf create mode 100644 migrations/inputs_procstat/testcases/deprecated_tagging_true_merge_overlap/telegraf.conf create mode 100644 migrations/inputs_sflow/migration.go create mode 100644 migrations/inputs_sflow/migration_test.go create mode 100644 migrations/inputs_sflow/testcases/filters/expected.conf create mode 100644 migrations/inputs_sflow/testcases/filters/telegraf.conf create mode 100644 migrations/inputs_sflow/testcases/minimal/expected.conf create mode 100644 migrations/inputs_sflow/testcases/minimal/telegraf.conf create mode 100644 migrations/inputs_sflow/testcases/read_buffer_size/expected.conf create mode 100644 migrations/inputs_sflow/testcases/read_buffer_size/telegraf.conf create mode 100644 migrations/inputs_snmp_legacy/migration.go create mode 100644 migrations/inputs_snmp_legacy/migration_test.go create mode 100644 migrations/inputs_tcp_listener/README.md create mode 100644 migrations/inputs_tcp_listener/migration.go create mode 100644 migrations/inputs_tcp_listener/migration_test.go create mode 100644 migrations/inputs_tcp_listener/testcases/allow_pending_messages/expected.conf create mode 100644 migrations/inputs_tcp_listener/testcases/allow_pending_messages/telegraf.conf create mode 100644 migrations/inputs_tcp_listener/testcases/parser/expected.conf create mode 100644 migrations/inputs_tcp_listener/testcases/parser/telegraf.conf create mode 100644 migrations/inputs_tcp_listener/testcases/simple/expected.conf create mode 100644 migrations/inputs_tcp_listener/testcases/simple/telegraf.conf create mode 100644 migrations/inputs_udp_listener/README.md create mode 100644 migrations/inputs_udp_listener/migration.go create mode 100644 migrations/inputs_udp_listener/migration_test.go create mode 100644 migrations/inputs_udp_listener/testcases/all_deprecated_messages/expected.conf create mode 100644 migrations/inputs_udp_listener/testcases/all_deprecated_messages/telegraf.conf create mode 100644 migrations/inputs_udp_listener/testcases/allow_pending_messages/expected.conf create mode 100644 migrations/inputs_udp_listener/testcases/allow_pending_messages/telegraf.conf create mode 100644 migrations/inputs_udp_listener/testcases/parser/expected.conf create mode 100644 migrations/inputs_udp_listener/testcases/parser/telegraf.conf create mode 100644 migrations/inputs_udp_listener/testcases/simple/expected.conf create mode 100644 migrations/inputs_udp_listener/testcases/simple/telegraf.conf create mode 100644 migrations/outputs_influxdb/migration.go create mode 100644 migrations/outputs_influxdb/migration_test.go create mode 100644 migrations/outputs_influxdb/testcases/convert_url/expected.conf create mode 100644 migrations/outputs_influxdb/testcases/convert_url/telegraf.conf create mode 100644 migrations/outputs_influxdb/testcases/merge_url/expected.conf create mode 100644 migrations/outputs_influxdb/testcases/merge_url/telegraf.conf create mode 100644 migrations/outputs_influxdb/testcases/merge_url_overlap/expected.conf create mode 100644 migrations/outputs_influxdb/testcases/merge_url_overlap/telegraf.conf create mode 100644 migrations/outputs_riemann_legacy/README.md create mode 100644 migrations/outputs_riemann_legacy/migration.go create mode 100644 migrations/outputs_riemann_legacy/migration_test.go create mode 100644 migrations/outputs_riemann_legacy/testcases/general_options/expected.conf create mode 100644 migrations/outputs_riemann_legacy/testcases/general_options/telegraf.conf create mode 100644 migrations/outputs_riemann_legacy/testcases/simple/expected.conf create mode 100644 migrations/outputs_riemann_legacy/testcases/simple/telegraf.conf create mode 100644 migrations/registry.go create mode 100644 migrations/utils.go create mode 100644 models/buffer.go create mode 100644 models/buffer_disk.go create mode 100644 models/buffer_disk_test.go create mode 100644 models/buffer_mem.go create mode 100644 models/buffer_mem_test.go create mode 100644 models/buffer_suite_test.go create mode 100644 models/common.go create mode 100644 models/filter.go create mode 100644 models/filter_test.go create mode 100644 models/makemetric.go create mode 100644 models/running_aggregator.go create mode 100644 models/running_aggregator_test.go create mode 100644 models/running_input.go create mode 100644 models/running_input_test.go create mode 100644 models/running_output.go create mode 100644 models/running_output_test.go create mode 100644 models/running_parsers.go create mode 100644 models/running_processor.go create mode 100644 models/running_processor_test.go create mode 100644 models/running_serializer.go create mode 100644 output.go create mode 100644 parser.go create mode 100644 persister/persister.go create mode 100644 plugin.go create mode 100644 plugins/aggregators/all/all.go create mode 100644 plugins/aggregators/all/basicstats.go create mode 100644 plugins/aggregators/all/derivative.go create mode 100644 plugins/aggregators/all/final.go create mode 100644 plugins/aggregators/all/histogram.go create mode 100644 plugins/aggregators/all/merge.go create mode 100644 plugins/aggregators/all/minmax.go create mode 100644 plugins/aggregators/all/quantile.go create mode 100644 plugins/aggregators/all/starlark.go create mode 100644 plugins/aggregators/all/valuecounter.go create mode 100644 plugins/aggregators/basicstats/README.md create mode 100644 plugins/aggregators/basicstats/basicstats.go create mode 100644 plugins/aggregators/basicstats/basicstats_test.go create mode 100644 plugins/aggregators/basicstats/sample.conf create mode 100644 plugins/aggregators/deprecations.go create mode 100644 plugins/aggregators/derivative/README.md create mode 100644 plugins/aggregators/derivative/derivative.go create mode 100644 plugins/aggregators/derivative/derivative_test.go create mode 100644 plugins/aggregators/derivative/sample.conf create mode 100644 plugins/aggregators/final/README.md create mode 100644 plugins/aggregators/final/final.go create mode 100644 plugins/aggregators/final/final_test.go create mode 100644 plugins/aggregators/final/sample.conf create mode 100644 plugins/aggregators/histogram/README.md create mode 100644 plugins/aggregators/histogram/histogram.go create mode 100644 plugins/aggregators/histogram/histogram_test.go create mode 100644 plugins/aggregators/histogram/sample.conf create mode 100644 plugins/aggregators/merge/README.md create mode 100644 plugins/aggregators/merge/merge.go create mode 100644 plugins/aggregators/merge/merge_test.go create mode 100644 plugins/aggregators/merge/sample.conf create mode 100644 plugins/aggregators/minmax/README.md create mode 100644 plugins/aggregators/minmax/minmax.go create mode 100644 plugins/aggregators/minmax/minmax_test.go create mode 100644 plugins/aggregators/minmax/sample.conf create mode 100644 plugins/aggregators/quantile/README.md create mode 100644 plugins/aggregators/quantile/algorithms.go create mode 100644 plugins/aggregators/quantile/quantile.go create mode 100644 plugins/aggregators/quantile/quantile_test.go create mode 100644 plugins/aggregators/quantile/sample.conf create mode 100644 plugins/aggregators/registry.go create mode 100644 plugins/aggregators/starlark/README.md create mode 100644 plugins/aggregators/starlark/sample.conf create mode 100644 plugins/aggregators/starlark/starlark.go create mode 100644 plugins/aggregators/starlark/starlark_test.go create mode 100644 plugins/aggregators/starlark/testdata/merge.star create mode 100644 plugins/aggregators/starlark/testdata/min_max.star create mode 100644 plugins/aggregators/valuecounter/README.md create mode 100644 plugins/aggregators/valuecounter/sample.conf create mode 100644 plugins/aggregators/valuecounter/valuecounter.go create mode 100644 plugins/aggregators/valuecounter/valuecounter_test.go create mode 100644 plugins/all_test.go create mode 100644 plugins/common/adx/adx.go create mode 100644 plugins/common/adx/adx_test.go create mode 100644 plugins/common/auth/basic_auth.go create mode 100644 plugins/common/auth/basic_auth_test.go create mode 100644 plugins/common/aws/credentials.go create mode 100644 plugins/common/cookie/cookie.go create mode 100644 plugins/common/cookie/cookie_test.go create mode 100644 plugins/common/docker/stats_helpers.go create mode 100644 plugins/common/encoding/decoder.go create mode 100644 plugins/common/encoding/decoder_reader.go create mode 100644 plugins/common/encoding/decoder_test.go create mode 100644 plugins/common/http/config.go create mode 100644 plugins/common/jolokia2/client.go create mode 100644 plugins/common/jolokia2/gatherer.go create mode 100644 plugins/common/jolokia2/gatherer_test.go create mode 100644 plugins/common/jolokia2/metric.go create mode 100644 plugins/common/jolokia2/point_builder.go create mode 100644 plugins/common/kafka/config.go create mode 100644 plugins/common/kafka/config_test.go create mode 100644 plugins/common/kafka/logger.go create mode 100644 plugins/common/kafka/sasl.go create mode 100644 plugins/common/kafka/scram_client.go create mode 100644 plugins/common/logrus/hook.go create mode 100644 plugins/common/mqtt/mqtt.go create mode 100644 plugins/common/mqtt/mqtt_logger.go create mode 100644 plugins/common/mqtt/mqtt_test.go create mode 100644 plugins/common/mqtt/mqtt_v3.go create mode 100644 plugins/common/mqtt/mqtt_v5.go create mode 100644 plugins/common/oauth/config.go create mode 100644 plugins/common/opcua/client.go create mode 100644 plugins/common/opcua/client_test.go create mode 100644 plugins/common/opcua/input/input_client.go create mode 100644 plugins/common/opcua/input/input_client_test.go create mode 100644 plugins/common/opcua/logger.go create mode 100644 plugins/common/opcua/opcua_util.go create mode 100644 plugins/common/parallel/ordered.go create mode 100644 plugins/common/parallel/parallel.go create mode 100644 plugins/common/parallel/parallel_test.go create mode 100644 plugins/common/parallel/unordered.go create mode 100644 plugins/common/postgresql/config.go create mode 100644 plugins/common/postgresql/config_test.go create mode 100644 plugins/common/postgresql/service.go create mode 100644 plugins/common/proxy/connect.go create mode 100644 plugins/common/proxy/dialer.go create mode 100644 plugins/common/proxy/proxy.go create mode 100644 plugins/common/proxy/socks5.go create mode 100644 plugins/common/proxy/socks5_test.go create mode 100644 plugins/common/psutil/mock_ps.go create mode 100644 plugins/common/psutil/ps.go create mode 100644 plugins/common/ratelimiter/config.go create mode 100644 plugins/common/ratelimiter/limiters.go create mode 100644 plugins/common/ratelimiter/limiters_test.go create mode 100644 plugins/common/ratelimiter/serializers.go create mode 100644 plugins/common/ratelimiter/serializers_test.go create mode 100644 plugins/common/shim/README.md create mode 100644 plugins/common/shim/config.go create mode 100644 plugins/common/shim/config_test.go create mode 100644 plugins/common/shim/example/cmd/main.go create mode 100644 plugins/common/shim/example/cmd/plugin.conf create mode 100644 plugins/common/shim/goshim.go create mode 100644 plugins/common/shim/goshim_test.go create mode 100644 plugins/common/shim/input.go create mode 100644 plugins/common/shim/input_test.go create mode 100644 plugins/common/shim/output.go create mode 100644 plugins/common/shim/output_test.go create mode 100644 plugins/common/shim/processor.go create mode 100644 plugins/common/shim/processor_test.go create mode 100644 plugins/common/shim/testdata/plugin.conf create mode 100644 plugins/common/shim/testdata/processor.conf create mode 100644 plugins/common/shim/testdata/special.conf create mode 100644 plugins/common/socket/datagram.go create mode 100644 plugins/common/socket/socket.conf create mode 100644 plugins/common/socket/socket.go create mode 100644 plugins/common/socket/socket_test.go create mode 100644 plugins/common/socket/splitter.conf create mode 100644 plugins/common/socket/splitters.go create mode 100644 plugins/common/socket/stream.go create mode 100644 plugins/common/starlark/builtins.go create mode 100644 plugins/common/starlark/field_dict.go create mode 100644 plugins/common/starlark/logging.go create mode 100644 plugins/common/starlark/metric.go create mode 100644 plugins/common/starlark/starlark.go create mode 100644 plugins/common/starlark/tag_dict.go create mode 100644 plugins/common/tls/client.conf create mode 100644 plugins/common/tls/common.go create mode 100644 plugins/common/tls/config.go create mode 100644 plugins/common/tls/config_test.go create mode 100644 plugins/common/tls/utils.go create mode 100644 plugins/common/yangmodel/decoder.go create mode 100644 plugins/inputs/activemq/README.md create mode 100644 plugins/inputs/activemq/activemq.go create mode 100644 plugins/inputs/activemq/activemq_test.go create mode 100644 plugins/inputs/activemq/sample.conf create mode 100644 plugins/inputs/aerospike/README.md create mode 100644 plugins/inputs/aerospike/aerospike.go create mode 100644 plugins/inputs/aerospike/aerospike_test.go create mode 100644 plugins/inputs/aerospike/sample.conf create mode 100644 plugins/inputs/aliyuncms/README.md create mode 100644 plugins/inputs/aliyuncms/aliyuncms.go create mode 100644 plugins/inputs/aliyuncms/aliyuncms_test.go create mode 100644 plugins/inputs/aliyuncms/discovery.go create mode 100644 plugins/inputs/aliyuncms/sample.conf create mode 100644 plugins/inputs/all/activemq.go create mode 100644 plugins/inputs/all/aerospike.go create mode 100644 plugins/inputs/all/aliyuncms.go create mode 100644 plugins/inputs/all/all.go create mode 100644 plugins/inputs/all/amd_rocm_smi.go create mode 100644 plugins/inputs/all/amqp_consumer.go create mode 100644 plugins/inputs/all/apache.go create mode 100644 plugins/inputs/all/apcupsd.go create mode 100644 plugins/inputs/all/aurora.go create mode 100644 plugins/inputs/all/azure_monitor.go create mode 100644 plugins/inputs/all/azure_storage_queue.go create mode 100644 plugins/inputs/all/bcache.go create mode 100644 plugins/inputs/all/beanstalkd.go create mode 100644 plugins/inputs/all/beat.go create mode 100644 plugins/inputs/all/bind.go create mode 100644 plugins/inputs/all/bond.go create mode 100644 plugins/inputs/all/burrow.go create mode 100644 plugins/inputs/all/ceph.go create mode 100644 plugins/inputs/all/cgroup.go create mode 100644 plugins/inputs/all/chrony.go create mode 100644 plugins/inputs/all/cisco_telemetry_mdt.go create mode 100644 plugins/inputs/all/clickhouse.go create mode 100644 plugins/inputs/all/cloud_pubsub.go create mode 100644 plugins/inputs/all/cloud_pubsub_push.go create mode 100644 plugins/inputs/all/cloudwatch.go create mode 100644 plugins/inputs/all/cloudwatch_metric_streams.go create mode 100644 plugins/inputs/all/conntrack.go create mode 100644 plugins/inputs/all/consul.go create mode 100644 plugins/inputs/all/consul_agent.go create mode 100644 plugins/inputs/all/couchbase.go create mode 100644 plugins/inputs/all/couchdb.go create mode 100644 plugins/inputs/all/cpu.go create mode 100644 plugins/inputs/all/csgo.go create mode 100644 plugins/inputs/all/ctrlx_datalayer.go create mode 100644 plugins/inputs/all/dcos.go create mode 100644 plugins/inputs/all/directory_monitor.go create mode 100644 plugins/inputs/all/disk.go create mode 100644 plugins/inputs/all/diskio.go create mode 100644 plugins/inputs/all/disque.go create mode 100644 plugins/inputs/all/dmcache.go create mode 100644 plugins/inputs/all/dns_query.go create mode 100644 plugins/inputs/all/docker.go create mode 100644 plugins/inputs/all/docker_log.go create mode 100644 plugins/inputs/all/dovecot.go create mode 100644 plugins/inputs/all/dpdk.go create mode 100644 plugins/inputs/all/ecs.go create mode 100644 plugins/inputs/all/elasticsearch.go create mode 100644 plugins/inputs/all/elasticsearch_query.go create mode 100644 plugins/inputs/all/ethtool.go create mode 100644 plugins/inputs/all/eventhub_consumer.go create mode 100644 plugins/inputs/all/exec.go create mode 100644 plugins/inputs/all/execd.go create mode 100644 plugins/inputs/all/fail2ban.go create mode 100644 plugins/inputs/all/fibaro.go create mode 100644 plugins/inputs/all/file.go create mode 100644 plugins/inputs/all/filecount.go create mode 100644 plugins/inputs/all/filestat.go create mode 100644 plugins/inputs/all/fireboard.go create mode 100644 plugins/inputs/all/firehose.go create mode 100644 plugins/inputs/all/fluentd.go create mode 100644 plugins/inputs/all/github.go create mode 100644 plugins/inputs/all/gnmi.go create mode 100644 plugins/inputs/all/google_cloud_storage.go create mode 100644 plugins/inputs/all/graylog.go create mode 100644 plugins/inputs/all/haproxy.go create mode 100644 plugins/inputs/all/hddtemp.go create mode 100644 plugins/inputs/all/http.go create mode 100644 plugins/inputs/all/http_listener_v2.go create mode 100644 plugins/inputs/all/http_response.go create mode 100644 plugins/inputs/all/huebridge.go create mode 100644 plugins/inputs/all/hugepages.go create mode 100644 plugins/inputs/all/icinga2.go create mode 100644 plugins/inputs/all/infiniband.go create mode 100644 plugins/inputs/all/influxdb.go create mode 100644 plugins/inputs/all/influxdb_listener.go create mode 100644 plugins/inputs/all/influxdb_v2_listener.go create mode 100644 plugins/inputs/all/intel_baseband.go create mode 100644 plugins/inputs/all/intel_dlb.go create mode 100644 plugins/inputs/all/intel_pmt.go create mode 100644 plugins/inputs/all/intel_pmu.go create mode 100644 plugins/inputs/all/intel_powerstat.go create mode 100644 plugins/inputs/all/intel_rdt.go create mode 100644 plugins/inputs/all/internal.go create mode 100644 plugins/inputs/all/internet_speed.go create mode 100644 plugins/inputs/all/interrupts.go create mode 100644 plugins/inputs/all/ipmi_sensor.go create mode 100644 plugins/inputs/all/ipset.go create mode 100644 plugins/inputs/all/iptables.go create mode 100644 plugins/inputs/all/ipvs.go create mode 100644 plugins/inputs/all/jenkins.go create mode 100644 plugins/inputs/all/jolokia2_agent.go create mode 100644 plugins/inputs/all/jolokia2_proxy.go create mode 100644 plugins/inputs/all/jti_openconfig_telemetry.go create mode 100644 plugins/inputs/all/kafka_consumer.go create mode 100644 plugins/inputs/all/kapacitor.go create mode 100644 plugins/inputs/all/kernel.go create mode 100644 plugins/inputs/all/kernel_vmstat.go create mode 100644 plugins/inputs/all/kibana.go create mode 100644 plugins/inputs/all/kinesis_consumer.go create mode 100644 plugins/inputs/all/knx_listener.go create mode 100644 plugins/inputs/all/kube_inventory.go create mode 100644 plugins/inputs/all/kubernetes.go create mode 100644 plugins/inputs/all/lanz.go create mode 100644 plugins/inputs/all/ldap.go create mode 100644 plugins/inputs/all/leofs.go create mode 100644 plugins/inputs/all/libvirt.go create mode 100644 plugins/inputs/all/linux_cpu.go create mode 100644 plugins/inputs/all/linux_sysctl_fs.go create mode 100644 plugins/inputs/all/logparser.go create mode 100644 plugins/inputs/all/logstash.go create mode 100644 plugins/inputs/all/lustre2.go create mode 100644 plugins/inputs/all/lvm.go create mode 100644 plugins/inputs/all/mailchimp.go create mode 100644 plugins/inputs/all/marklogic.go create mode 100644 plugins/inputs/all/mcrouter.go create mode 100644 plugins/inputs/all/mdstat.go create mode 100644 plugins/inputs/all/mem.go create mode 100644 plugins/inputs/all/memcached.go create mode 100644 plugins/inputs/all/mesos.go create mode 100644 plugins/inputs/all/minecraft.go create mode 100644 plugins/inputs/all/mock.go create mode 100644 plugins/inputs/all/modbus.go create mode 100644 plugins/inputs/all/mongodb.go create mode 100644 plugins/inputs/all/monit.go create mode 100644 plugins/inputs/all/mqtt_consumer.go create mode 100644 plugins/inputs/all/multifile.go create mode 100644 plugins/inputs/all/mysql.go create mode 100644 plugins/inputs/all/nats.go create mode 100644 plugins/inputs/all/nats_consumer.go create mode 100644 plugins/inputs/all/neoom_beaam.go create mode 100644 plugins/inputs/all/neptune_apex.go create mode 100644 plugins/inputs/all/net.go create mode 100644 plugins/inputs/all/net_response.go create mode 100644 plugins/inputs/all/netflow.go create mode 100644 plugins/inputs/all/netstat.go create mode 100644 plugins/inputs/all/nfsclient.go create mode 100644 plugins/inputs/all/nginx.go create mode 100644 plugins/inputs/all/nginx_plus.go create mode 100644 plugins/inputs/all/nginx_plus_api.go create mode 100644 plugins/inputs/all/nginx_sts.go create mode 100644 plugins/inputs/all/nginx_upstream_check.go create mode 100644 plugins/inputs/all/nginx_vts.go create mode 100644 plugins/inputs/all/nomad.go create mode 100644 plugins/inputs/all/nsd.go create mode 100644 plugins/inputs/all/nsdp.go create mode 100644 plugins/inputs/all/nsq.go create mode 100644 plugins/inputs/all/nsq_consumer.go create mode 100644 plugins/inputs/all/nstat.go create mode 100644 plugins/inputs/all/ntpq.go create mode 100644 plugins/inputs/all/nvidia_smi.go create mode 100644 plugins/inputs/all/opcua.go create mode 100644 plugins/inputs/all/opcua_listener.go create mode 100644 plugins/inputs/all/openldap.go create mode 100644 plugins/inputs/all/openntpd.go create mode 100644 plugins/inputs/all/opensearch_query.go create mode 100644 plugins/inputs/all/opensmtpd.go create mode 100644 plugins/inputs/all/openstack.go create mode 100644 plugins/inputs/all/opentelemetry.go create mode 100644 plugins/inputs/all/openweathermap.go create mode 100644 plugins/inputs/all/p4runtime.go create mode 100644 plugins/inputs/all/passenger.go create mode 100644 plugins/inputs/all/pf.go create mode 100644 plugins/inputs/all/pgbouncer.go create mode 100644 plugins/inputs/all/phpfpm.go create mode 100644 plugins/inputs/all/ping.go create mode 100644 plugins/inputs/all/postfix.go create mode 100644 plugins/inputs/all/postgresql.go create mode 100644 plugins/inputs/all/postgresql_extensible.go create mode 100644 plugins/inputs/all/powerdns.go create mode 100644 plugins/inputs/all/powerdns_recursor.go create mode 100644 plugins/inputs/all/processes.go create mode 100644 plugins/inputs/all/procstat.go create mode 100644 plugins/inputs/all/prometheus.go create mode 100644 plugins/inputs/all/proxmox.go create mode 100644 plugins/inputs/all/puppetagent.go create mode 100644 plugins/inputs/all/rabbitmq.go create mode 100644 plugins/inputs/all/radius.go create mode 100644 plugins/inputs/all/raindrops.go create mode 100644 plugins/inputs/all/ras.go create mode 100644 plugins/inputs/all/ravendb.go create mode 100644 plugins/inputs/all/redfish.go create mode 100644 plugins/inputs/all/redis.go create mode 100644 plugins/inputs/all/redis_sentinel.go create mode 100644 plugins/inputs/all/rethinkdb.go create mode 100644 plugins/inputs/all/riak.go create mode 100644 plugins/inputs/all/riemann_listener.go create mode 100644 plugins/inputs/all/s7comm.go create mode 100644 plugins/inputs/all/salesforce.go create mode 100644 plugins/inputs/all/sensors.go create mode 100644 plugins/inputs/all/sflow.go create mode 100644 plugins/inputs/all/slab.go create mode 100644 plugins/inputs/all/slurm.go create mode 100644 plugins/inputs/all/smart.go create mode 100644 plugins/inputs/all/smartctl.go create mode 100644 plugins/inputs/all/snmp.go create mode 100644 plugins/inputs/all/snmp_trap.go create mode 100644 plugins/inputs/all/socket_listener.go create mode 100644 plugins/inputs/all/socketstat.go create mode 100644 plugins/inputs/all/solr.go create mode 100644 plugins/inputs/all/sql.go create mode 100644 plugins/inputs/all/sqlserver.go create mode 100644 plugins/inputs/all/stackdriver.go create mode 100644 plugins/inputs/all/statsd.go create mode 100644 plugins/inputs/all/supervisor.go create mode 100644 plugins/inputs/all/suricata.go create mode 100644 plugins/inputs/all/swap.go create mode 100644 plugins/inputs/all/synproxy.go create mode 100644 plugins/inputs/all/syslog.go create mode 100644 plugins/inputs/all/sysstat.go create mode 100644 plugins/inputs/all/system.go create mode 100644 plugins/inputs/all/systemd_units.go create mode 100644 plugins/inputs/all/tacacs.go create mode 100644 plugins/inputs/all/tail.go create mode 100644 plugins/inputs/all/teamspeak.go create mode 100644 plugins/inputs/all/temp.go create mode 100644 plugins/inputs/all/tengine.go create mode 100644 plugins/inputs/all/tomcat.go create mode 100644 plugins/inputs/all/trig.go create mode 100644 plugins/inputs/all/twemproxy.go create mode 100644 plugins/inputs/all/unbound.go create mode 100644 plugins/inputs/all/upsd.go create mode 100644 plugins/inputs/all/uwsgi.go create mode 100644 plugins/inputs/all/varnish.go create mode 100644 plugins/inputs/all/vault.go create mode 100644 plugins/inputs/all/vsphere.go create mode 100644 plugins/inputs/all/webhooks.go create mode 100644 plugins/inputs/all/win_eventlog.go create mode 100644 plugins/inputs/all/win_perf_counters.go create mode 100644 plugins/inputs/all/win_services.go create mode 100644 plugins/inputs/all/win_wmi.go create mode 100644 plugins/inputs/all/wireguard.go create mode 100644 plugins/inputs/all/wireless.go create mode 100644 plugins/inputs/all/x509_cert.go create mode 100644 plugins/inputs/all/xtremio.go create mode 100644 plugins/inputs/all/zfs.go create mode 100644 plugins/inputs/all/zipkin.go create mode 100644 plugins/inputs/all/zookeeper.go create mode 100644 plugins/inputs/amd_rocm_smi/README.md create mode 100644 plugins/inputs/amd_rocm_smi/amd_rocm_smi.go create mode 100644 plugins/inputs/amd_rocm_smi/amd_rocm_smi_test.go create mode 100644 plugins/inputs/amd_rocm_smi/sample.conf create mode 100644 plugins/inputs/amd_rocm_smi/testdata/mi100_rocm571.json create mode 100644 plugins/inputs/amd_rocm_smi/testdata/mi100_rocm602.json create mode 100644 plugins/inputs/amd_rocm_smi/testdata/rx6700xt_rocm430.json create mode 100644 plugins/inputs/amd_rocm_smi/testdata/rx6700xt_rocm571.json create mode 100644 plugins/inputs/amd_rocm_smi/testdata/rx6700xt_rocm602.json create mode 100644 plugins/inputs/amd_rocm_smi/testdata/rx6700xt_rocm612.json create mode 100644 plugins/inputs/amd_rocm_smi/testdata/vega-10-XT.json create mode 100644 plugins/inputs/amd_rocm_smi/testdata/vega-20-WKS-GL-XE.json create mode 100644 plugins/inputs/amqp_consumer/README.md create mode 100644 plugins/inputs/amqp_consumer/amqp_consumer.go create mode 100644 plugins/inputs/amqp_consumer/amqp_consumer_test.go create mode 100644 plugins/inputs/amqp_consumer/sample.conf create mode 100644 plugins/inputs/apache/README.md create mode 100644 plugins/inputs/apache/apache.go create mode 100644 plugins/inputs/apache/apache_test.go create mode 100644 plugins/inputs/apache/sample.conf create mode 100644 plugins/inputs/apcupsd/README.md create mode 100644 plugins/inputs/apcupsd/apcupsd.go create mode 100644 plugins/inputs/apcupsd/apcupsd_test.go create mode 100644 plugins/inputs/apcupsd/sample.conf create mode 100644 plugins/inputs/aurora/README.md create mode 100644 plugins/inputs/aurora/aurora.go create mode 100644 plugins/inputs/aurora/aurora_test.go create mode 100644 plugins/inputs/aurora/sample.conf create mode 100644 plugins/inputs/azure_monitor/README.md create mode 100644 plugins/inputs/azure_monitor/azure_monitor.go create mode 100644 plugins/inputs/azure_monitor/azure_monitor_test.go create mode 100644 plugins/inputs/azure_monitor/sample.conf create mode 100644 plugins/inputs/azure_monitor/testdata/json/azure_metric_definitions_responses.json create mode 100644 plugins/inputs/azure_monitor/testdata/json/azure_metrics_responses.json create mode 100644 plugins/inputs/azure_monitor/testdata/json/azure_resources_response.json create mode 100644 plugins/inputs/azure_monitor/testdata/toml/gather_success.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/gather_success_cloud_option_china.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/gather_success_cloud_option_government.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/gather_success_cloud_option_public.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_all_target_types.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_bad_credentials.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_no_client_id.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_no_client_secret.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_no_subscription_id.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_no_targets.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_no_tenant_id.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_no_resource_found.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_with_invalid_aggregation.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_with_invalid_metric.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_with_invalid_resource_group.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_with_invalid_resource_type.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_with_resource_without_resource_type.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_without_resource_group.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_resource_group_target_without_resources.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_resource_group_targets_only.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_resource_target_with_invalid_aggregation.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_resource_target_with_invalid_metric.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_resource_target_with_invalid_resource_id.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_resource_target_without_resource_id.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_resource_targets_only.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_subscription_target_no_resource_found.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_subscription_target_with_invalid_aggregation.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_subscription_target_with_invalid_metric.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_subscription_target_with_invalid_resource_type.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_subscription_target_without_resource_type.toml create mode 100644 plugins/inputs/azure_monitor/testdata/toml/init_subscription_targets_only.toml create mode 100644 plugins/inputs/azure_storage_queue/README.md create mode 100644 plugins/inputs/azure_storage_queue/azure_storage_queue.go create mode 100644 plugins/inputs/azure_storage_queue/azure_storage_queue_test.go create mode 100644 plugins/inputs/azure_storage_queue/sample.conf create mode 100644 plugins/inputs/bcache/README.md create mode 100644 plugins/inputs/bcache/bcache.go create mode 100644 plugins/inputs/bcache/bcache_notlinux.go create mode 100644 plugins/inputs/bcache/bcache_test.go create mode 100644 plugins/inputs/bcache/sample.conf create mode 100644 plugins/inputs/beanstalkd/README.md create mode 100644 plugins/inputs/beanstalkd/beanstalkd.go create mode 100644 plugins/inputs/beanstalkd/beanstalkd_test.go create mode 100644 plugins/inputs/beanstalkd/sample.conf create mode 100644 plugins/inputs/beat/README.md create mode 100644 plugins/inputs/beat/beat.go create mode 100644 plugins/inputs/beat/beat6_info.json create mode 100644 plugins/inputs/beat/beat6_stats.json create mode 100644 plugins/inputs/beat/beat_test.go create mode 100644 plugins/inputs/beat/sample.conf create mode 100644 plugins/inputs/bind/README.md create mode 100644 plugins/inputs/bind/bind.go create mode 100644 plugins/inputs/bind/bind_test.go create mode 100644 plugins/inputs/bind/json_stats.go create mode 100644 plugins/inputs/bind/sample.conf create mode 100644 plugins/inputs/bind/testdata/json/v1/mem create mode 100644 plugins/inputs/bind/testdata/json/v1/net create mode 100644 plugins/inputs/bind/testdata/json/v1/server create mode 100644 plugins/inputs/bind/testdata/xml/v2 create mode 100644 plugins/inputs/bind/testdata/xml/v3/mem create mode 100644 plugins/inputs/bind/testdata/xml/v3/net create mode 100644 plugins/inputs/bind/testdata/xml/v3/server create mode 100644 plugins/inputs/bind/xml_stats_v2.go create mode 100644 plugins/inputs/bind/xml_stats_v3.go create mode 100644 plugins/inputs/bond/README.md create mode 100644 plugins/inputs/bond/bond.go create mode 100644 plugins/inputs/bond/bond_test.go create mode 100644 plugins/inputs/bond/sample.conf create mode 100644 plugins/inputs/burrow/README.md create mode 100644 plugins/inputs/burrow/burrow.go create mode 100644 plugins/inputs/burrow/burrow_test.go create mode 100644 plugins/inputs/burrow/sample.conf create mode 100644 plugins/inputs/burrow/testdata/error.json create mode 100644 plugins/inputs/burrow/testdata/v3_kafka.json create mode 100644 plugins/inputs/burrow/testdata/v3_kafka_clustername1_consumer.json create mode 100644 plugins/inputs/burrow/testdata/v3_kafka_clustername1_consumer_group1_lag.json create mode 100644 plugins/inputs/burrow/testdata/v3_kafka_clustername1_topic.json create mode 100644 plugins/inputs/burrow/testdata/v3_kafka_clustername1_topic_topicA.json create mode 100644 plugins/inputs/ceph/README.md create mode 100644 plugins/inputs/ceph/ceph.go create mode 100644 plugins/inputs/ceph/ceph_test.go create mode 100644 plugins/inputs/ceph/sample.conf create mode 100644 plugins/inputs/cgroup/README.md create mode 100644 plugins/inputs/cgroup/cgroup.go create mode 100644 plugins/inputs/cgroup/cgroup_linux.go create mode 100644 plugins/inputs/cgroup/cgroup_notlinux.go create mode 100644 plugins/inputs/cgroup/cgroup_test.go create mode 100644 plugins/inputs/cgroup/cgroupv2_test.go create mode 100644 plugins/inputs/cgroup/sample.conf create mode 100644 plugins/inputs/cgroup/testdata/backslash/machine-qemu-1-ubuntu/cpu.stat create mode 100644 plugins/inputs/cgroup/testdata/blkio/blkio.io_serviced create mode 100644 plugins/inputs/cgroup/testdata/blkio/blkio.throttle.io_serviced create mode 100644 plugins/inputs/cgroup/testdata/broken/malformed.file create mode 100644 plugins/inputs/cgroup/testdata/broken/memory.limit_in_bytes create mode 100644 plugins/inputs/cgroup/testdata/cpu/cpu.cfs_quota_us create mode 100644 plugins/inputs/cgroup/testdata/cpu/cpu.stat create mode 100644 plugins/inputs/cgroup/testdata/cpu/cpuacct.usage_percpu create mode 100644 plugins/inputs/cgroup/testdata/memory/group_1/group_1_1/memory.limit_in_bytes create mode 100644 plugins/inputs/cgroup/testdata/memory/group_1/group_1_1/memory.stat create mode 100644 plugins/inputs/cgroup/testdata/memory/group_1/group_1_2/memory.limit_in_bytes create mode 100644 plugins/inputs/cgroup/testdata/memory/group_1/group_1_2/memory.stat create mode 100644 plugins/inputs/cgroup/testdata/memory/group_1/memory.kmem.limit_in_bytes create mode 100644 plugins/inputs/cgroup/testdata/memory/group_1/memory.kmem.max_usage_in_bytes create mode 100644 plugins/inputs/cgroup/testdata/memory/group_1/memory.limit_in_bytes create mode 100644 plugins/inputs/cgroup/testdata/memory/group_1/memory.stat create mode 100644 plugins/inputs/cgroup/testdata/memory/group_2/group_1_1/memory.limit_in_bytes create mode 100644 plugins/inputs/cgroup/testdata/memory/group_2/group_1_1/memory.stat create mode 100644 plugins/inputs/cgroup/testdata/memory/group_2/memory.limit_in_bytes create mode 100644 plugins/inputs/cgroup/testdata/memory/group_2/memory.stat create mode 100644 plugins/inputs/cgroup/testdata/memory/memory.empty create mode 100644 plugins/inputs/cgroup/testdata/memory/memory.kmem.limit_in_bytes create mode 100644 plugins/inputs/cgroup/testdata/memory/memory.limit_in_bytes create mode 100644 plugins/inputs/cgroup/testdata/memory/memory.max_usage_in_bytes create mode 100644 plugins/inputs/cgroup/testdata/memory/memory.numa_stat create mode 100644 plugins/inputs/cgroup/testdata/memory/memory.stat create mode 100644 plugins/inputs/cgroup/testdata/memory/memory.usage_in_bytes create mode 100644 plugins/inputs/cgroup/testdata/memory/memory.use_hierarchy create mode 100644 plugins/inputs/cgroup/testdata/memory/notify_on_release create mode 100644 plugins/inputs/cgroup/testdata/v2/cpu.idle create mode 100644 plugins/inputs/cgroup/testdata/v2/cpu.max create mode 100644 plugins/inputs/cgroup/testdata/v2/cpu.max.burst create mode 100644 plugins/inputs/cgroup/testdata/v2/cpu.pressure create mode 100644 plugins/inputs/cgroup/testdata/v2/cpu.stat create mode 100644 plugins/inputs/cgroup/testdata/v2/cpu.weight create mode 100644 plugins/inputs/cgroup/testdata/v2/cpu.weight.nice create mode 100644 plugins/inputs/cgroup/testdata/v2/cpuset.cpus create mode 100644 plugins/inputs/cgroup/testdata/v2/cpuset.cpus.effective create mode 100644 plugins/inputs/cgroup/testdata/v2/cpuset.cpus.partition create mode 100644 plugins/inputs/cgroup/testdata/v2/cpuset.mems create mode 100644 plugins/inputs/cgroup/testdata/v2/cpuset.mems.effective create mode 100644 plugins/inputs/cgroup/testdata/v2/hugetlb.1GB.current create mode 100644 plugins/inputs/cgroup/testdata/v2/hugetlb.1GB.events create mode 100644 plugins/inputs/cgroup/testdata/v2/hugetlb.1GB.events.local create mode 100644 plugins/inputs/cgroup/testdata/v2/hugetlb.1GB.max create mode 100644 plugins/inputs/cgroup/testdata/v2/hugetlb.1GB.numa_stat create mode 100644 plugins/inputs/cgroup/testdata/v2/hugetlb.1GB.rsvd.current create mode 100644 plugins/inputs/cgroup/testdata/v2/hugetlb.1GB.rsvd.max create mode 100644 plugins/inputs/cgroup/testdata/v2/hugetlb.2MB.current create mode 100644 plugins/inputs/cgroup/testdata/v2/hugetlb.2MB.events create mode 100644 plugins/inputs/cgroup/testdata/v2/hugetlb.2MB.events.local create mode 100644 plugins/inputs/cgroup/testdata/v2/hugetlb.2MB.max create mode 100644 plugins/inputs/cgroup/testdata/v2/hugetlb.2MB.numa_stat create mode 100644 plugins/inputs/cgroup/testdata/v2/hugetlb.2MB.rsvd.current create mode 100644 plugins/inputs/cgroup/testdata/v2/hugetlb.2MB.rsvd.max create mode 100644 plugins/inputs/cgroup/testdata/v2/io.bfq.weight create mode 100644 plugins/inputs/cgroup/testdata/v2/io.max create mode 100644 plugins/inputs/cgroup/testdata/v2/io.pressure create mode 100644 plugins/inputs/cgroup/testdata/v2/io.stat create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.current create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.events create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.events.local create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.high create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.low create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.max create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.min create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.numa_stat create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.oom.group create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.peak create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.pressure create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.reclaim create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.stat create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.swap.current create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.swap.events create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.swap.high create mode 100644 plugins/inputs/cgroup/testdata/v2/memory.swap.max create mode 100644 plugins/inputs/cgroup/testdata/v2/pids.current create mode 100644 plugins/inputs/cgroup/testdata/v2/pids.events create mode 100644 plugins/inputs/cgroup/testdata/v2/pids.max create mode 100644 plugins/inputs/cgroup/testdata/v2/pids.peak create mode 100644 plugins/inputs/chrony/README.md create mode 100644 plugins/inputs/chrony/chrony.go create mode 100644 plugins/inputs/chrony/chrony_test.go create mode 100644 plugins/inputs/chrony/sample.conf create mode 100644 plugins/inputs/chrony/testdata/chrony.conf create mode 100644 plugins/inputs/chrony/testdata/start.sh create mode 100644 plugins/inputs/cisco_telemetry_mdt/README.md create mode 100644 plugins/inputs/cisco_telemetry_mdt/cisco_telemetry_mdt.go create mode 100644 plugins/inputs/cisco_telemetry_mdt/cisco_telemetry_mdt_test.go create mode 100644 plugins/inputs/cisco_telemetry_mdt/cisco_telemetry_util.go create mode 100644 plugins/inputs/cisco_telemetry_mdt/sample.conf create mode 100644 plugins/inputs/cisco_telemetry_mdt/testdata/microburst create mode 100644 plugins/inputs/clickhouse/README.md create mode 100644 plugins/inputs/clickhouse/clickhouse.go create mode 100644 plugins/inputs/clickhouse/clickhouse_test.go create mode 100644 plugins/inputs/clickhouse/dev/dhparam.pem create mode 100644 plugins/inputs/clickhouse/dev/docker-compose.yml create mode 100644 plugins/inputs/clickhouse/dev/init_schema.sql create mode 100644 plugins/inputs/clickhouse/dev/mysql_port.xml create mode 100644 plugins/inputs/clickhouse/dev/part_log.xml create mode 100644 plugins/inputs/clickhouse/dev/telegraf.conf create mode 100644 plugins/inputs/clickhouse/dev/telegraf_ssl.conf create mode 100644 plugins/inputs/clickhouse/dev/test_dictionary.xml create mode 100644 plugins/inputs/clickhouse/dev/text_log.xml create mode 100644 plugins/inputs/clickhouse/dev/tls_settings.xml create mode 100644 plugins/inputs/clickhouse/dev/zookeeper.xml create mode 100644 plugins/inputs/clickhouse/sample.conf create mode 100644 plugins/inputs/cloud_pubsub/README.md create mode 100644 plugins/inputs/cloud_pubsub/cloud_pubsub.go create mode 100644 plugins/inputs/cloud_pubsub/cloud_pubsub_test.go create mode 100644 plugins/inputs/cloud_pubsub/sample.conf create mode 100644 plugins/inputs/cloud_pubsub/subscription_gcp.go create mode 100644 plugins/inputs/cloud_pubsub/subscription_stub_test.go create mode 100644 plugins/inputs/cloud_pubsub_push/README.md create mode 100644 plugins/inputs/cloud_pubsub_push/cloud_pubsub_push.go create mode 100644 plugins/inputs/cloud_pubsub_push/cloud_pubsub_push_test.go create mode 100644 plugins/inputs/cloud_pubsub_push/sample.conf create mode 100644 plugins/inputs/cloudwatch/README.md create mode 100644 plugins/inputs/cloudwatch/cloudwatch.go create mode 100644 plugins/inputs/cloudwatch/cloudwatch_test.go create mode 100644 plugins/inputs/cloudwatch/sample.conf create mode 100644 plugins/inputs/cloudwatch/utils.go create mode 100644 plugins/inputs/cloudwatch_metric_streams/README.md create mode 100644 plugins/inputs/cloudwatch_metric_streams/cloudwatch_metric_streams.go create mode 100644 plugins/inputs/cloudwatch_metric_streams/cloudwatch_metric_streams_test.go create mode 100644 plugins/inputs/cloudwatch_metric_streams/sample.conf create mode 100644 plugins/inputs/cloudwatch_metric_streams/testdata/record.json create mode 100644 plugins/inputs/cloudwatch_metric_streams/testdata/records.gz create mode 100644 plugins/inputs/cloudwatch_metric_streams/testdata/records.json create mode 100644 plugins/inputs/conntrack/README.md create mode 100644 plugins/inputs/conntrack/conntrack.go create mode 100644 plugins/inputs/conntrack/conntrack_notlinux.go create mode 100644 plugins/inputs/conntrack/conntrack_test.go create mode 100644 plugins/inputs/conntrack/sample.conf create mode 100644 plugins/inputs/consul/README.md create mode 100644 plugins/inputs/consul/consul.go create mode 100644 plugins/inputs/consul/consul_test.go create mode 100644 plugins/inputs/consul/sample.conf create mode 100644 plugins/inputs/consul_agent/README.md create mode 100644 plugins/inputs/consul_agent/consul_agent.go create mode 100644 plugins/inputs/consul_agent/consul_agent_test.go create mode 100644 plugins/inputs/consul_agent/consul_structs.go create mode 100644 plugins/inputs/consul_agent/sample.conf create mode 100644 plugins/inputs/consul_agent/testdata/response_key_metrics.json create mode 100644 plugins/inputs/couchbase/README.md create mode 100644 plugins/inputs/couchbase/couchbase.go create mode 100644 plugins/inputs/couchbase/couchbase_data.go create mode 100644 plugins/inputs/couchbase/couchbase_test.go create mode 100644 plugins/inputs/couchbase/sample.conf create mode 100644 plugins/inputs/couchbase/testdata/bucket_response.json create mode 100644 plugins/inputs/couchbase/testdata/bucket_stats_response.json create mode 100644 plugins/inputs/couchbase/testdata/bucket_stats_response_with_missing.json create mode 100644 plugins/inputs/couchbase/testdata/node_bucket_stats_response.json create mode 100644 plugins/inputs/couchbase/testdata/pools_default_response.json create mode 100644 plugins/inputs/couchbase/testdata/pools_response.json create mode 100644 plugins/inputs/couchbase/testdata/settings_autofailover.json create mode 100644 plugins/inputs/couchdb/README.md create mode 100644 plugins/inputs/couchdb/couchdb.go create mode 100644 plugins/inputs/couchdb/couchdb_test.go create mode 100644 plugins/inputs/couchdb/dev/telegraf.conf create mode 100644 plugins/inputs/couchdb/sample.conf create mode 100644 plugins/inputs/cpu/README.md create mode 100644 plugins/inputs/cpu/cpu.go create mode 100644 plugins/inputs/cpu/cpu_test.go create mode 100644 plugins/inputs/cpu/sample.conf create mode 100644 plugins/inputs/csgo/README.md create mode 100644 plugins/inputs/csgo/csgo.go create mode 100644 plugins/inputs/csgo/csgo_test.go create mode 100644 plugins/inputs/csgo/sample.conf create mode 100644 plugins/inputs/ctrlx_datalayer/README.md create mode 100644 plugins/inputs/ctrlx_datalayer/ctrlx_datalayer.go create mode 100644 plugins/inputs/ctrlx_datalayer/ctrlx_datalayer_payload_types.go create mode 100644 plugins/inputs/ctrlx_datalayer/ctrlx_datalayer_subscription.go create mode 100644 plugins/inputs/ctrlx_datalayer/ctrlx_datalayer_subscription_test.go create mode 100644 plugins/inputs/ctrlx_datalayer/ctrlx_datalayer_test.go create mode 100644 plugins/inputs/ctrlx_datalayer/sample.conf create mode 100644 plugins/inputs/dcos/README.md create mode 100644 plugins/inputs/dcos/client.go create mode 100644 plugins/inputs/dcos/client_test.go create mode 100644 plugins/inputs/dcos/creds.go create mode 100644 plugins/inputs/dcos/dcos.go create mode 100644 plugins/inputs/dcos/dcos_test.go create mode 100644 plugins/inputs/dcos/sample.conf create mode 100644 plugins/inputs/deprecations.go create mode 100644 plugins/inputs/directory_monitor/README.md create mode 100644 plugins/inputs/directory_monitor/directory_monitor.go create mode 100644 plugins/inputs/directory_monitor/directory_monitor_test.go create mode 100644 plugins/inputs/directory_monitor/sample.conf create mode 100644 plugins/inputs/disk/README.md create mode 100644 plugins/inputs/disk/disk.go create mode 100644 plugins/inputs/disk/disk_test.go create mode 100644 plugins/inputs/disk/sample.conf create mode 100644 plugins/inputs/disk/testdata/issue_10297/proc/1/mountinfo create mode 100644 plugins/inputs/disk/testdata/issue_10297/sys/block/sda1/dm/name create mode 100644 plugins/inputs/disk/testdata/issue_10297/sys/block/sdb/dm/name create mode 100644 plugins/inputs/disk/testdata/success/proc/1/mountinfo create mode 100644 plugins/inputs/diskio/README.md create mode 100644 plugins/inputs/diskio/diskio.go create mode 100644 plugins/inputs/diskio/diskio_linux.go create mode 100644 plugins/inputs/diskio/diskio_linux_test.go create mode 100644 plugins/inputs/diskio/diskio_other.go create mode 100644 plugins/inputs/diskio/diskio_test.go create mode 100644 plugins/inputs/diskio/sample.conf create mode 100644 plugins/inputs/diskio/testdata/udev.txt create mode 100644 plugins/inputs/diskio/testdata/uevent create mode 100644 plugins/inputs/disque/README.md create mode 100644 plugins/inputs/disque/disque.go create mode 100644 plugins/inputs/disque/disque_test.go create mode 100644 plugins/inputs/disque/sample.conf create mode 100644 plugins/inputs/dmcache/README.md create mode 100644 plugins/inputs/dmcache/dmcache.go create mode 100644 plugins/inputs/dmcache/dmcache_linux.go create mode 100644 plugins/inputs/dmcache/dmcache_linux_test.go create mode 100644 plugins/inputs/dmcache/dmcache_notlinux.go create mode 100644 plugins/inputs/dmcache/sample.conf create mode 100644 plugins/inputs/dns_query/README.md create mode 100644 plugins/inputs/dns_query/dns_query.go create mode 100644 plugins/inputs/dns_query/dns_query_test.go create mode 100644 plugins/inputs/dns_query/sample.conf create mode 100644 plugins/inputs/docker/README.md create mode 100644 plugins/inputs/docker/client.go create mode 100644 plugins/inputs/docker/docker.go create mode 100644 plugins/inputs/docker/docker_test.go create mode 100644 plugins/inputs/docker/docker_testdata.go create mode 100644 plugins/inputs/docker/errors.go create mode 100644 plugins/inputs/docker/sample.conf create mode 100644 plugins/inputs/docker_log/README.md create mode 100644 plugins/inputs/docker_log/client.go create mode 100644 plugins/inputs/docker_log/docker_log.go create mode 100644 plugins/inputs/docker_log/docker_log_test.go create mode 100644 plugins/inputs/docker_log/sample.conf create mode 100644 plugins/inputs/dovecot/README.md create mode 100644 plugins/inputs/dovecot/dovecot.go create mode 100644 plugins/inputs/dovecot/dovecot_test.go create mode 100644 plugins/inputs/dovecot/sample.conf create mode 100644 plugins/inputs/dovecot/testdata/dovecot.conf create mode 100644 plugins/inputs/dpdk/README.md create mode 100644 plugins/inputs/dpdk/dpdk.go create mode 100644 plugins/inputs/dpdk/dpdk_cmds.go create mode 100644 plugins/inputs/dpdk/dpdk_cmds_test.go create mode 100644 plugins/inputs/dpdk/dpdk_connector.go create mode 100644 plugins/inputs/dpdk/dpdk_connector_test.go create mode 100644 plugins/inputs/dpdk/dpdk_notlinux.go create mode 100644 plugins/inputs/dpdk/dpdk_test.go create mode 100644 plugins/inputs/dpdk/dpdk_utils.go create mode 100644 plugins/inputs/dpdk/dpdk_utils_test.go create mode 100644 plugins/inputs/dpdk/mocks/conn.go create mode 100644 plugins/inputs/dpdk/sample.conf create mode 100644 plugins/inputs/ecs/README.md create mode 100644 plugins/inputs/ecs/cgroupv2_test.go create mode 100644 plugins/inputs/ecs/client.go create mode 100644 plugins/inputs/ecs/client_test.go create mode 100644 plugins/inputs/ecs/ecs.go create mode 100644 plugins/inputs/ecs/ecs_test.go create mode 100644 plugins/inputs/ecs/sample.conf create mode 100644 plugins/inputs/ecs/stats.go create mode 100644 plugins/inputs/ecs/stats_test.go create mode 100644 plugins/inputs/ecs/testdata/cgroupv2/meta.json create mode 100644 plugins/inputs/ecs/testdata/cgroupv2/meta.out create mode 100644 plugins/inputs/ecs/testdata/cgroupv2/stats.json create mode 100644 plugins/inputs/ecs/testdata/cgroupv2/stats.out create mode 100644 plugins/inputs/ecs/testdata/metadata.golden create mode 100644 plugins/inputs/ecs/testdata/stats.golden create mode 100644 plugins/inputs/ecs/types.go create mode 100644 plugins/inputs/ecs/types_test.go create mode 100644 plugins/inputs/elasticsearch/README.md create mode 100644 plugins/inputs/elasticsearch/elasticsearch.go create mode 100644 plugins/inputs/elasticsearch/elasticsearch_test.go create mode 100644 plugins/inputs/elasticsearch/sample.conf create mode 100644 plugins/inputs/elasticsearch/testdata_test.go create mode 100644 plugins/inputs/elasticsearch_query/README.md create mode 100644 plugins/inputs/elasticsearch_query/aggregation_parser.go create mode 100644 plugins/inputs/elasticsearch_query/aggregation_query.go create mode 100644 plugins/inputs/elasticsearch_query/elasticsearch_query.go create mode 100644 plugins/inputs/elasticsearch_query/elasticsearch_query_test.go create mode 100644 plugins/inputs/elasticsearch_query/sample.conf create mode 100644 plugins/inputs/elasticsearch_query/testdata/nginx_logs create mode 100644 plugins/inputs/ethtool/README.md create mode 100644 plugins/inputs/ethtool/ethtool.go create mode 100644 plugins/inputs/ethtool/ethtool_linux.go create mode 100644 plugins/inputs/ethtool/ethtool_notlinux.go create mode 100644 plugins/inputs/ethtool/ethtool_test.go create mode 100644 plugins/inputs/ethtool/namespace_linux.go create mode 100644 plugins/inputs/ethtool/sample.conf create mode 100644 plugins/inputs/eventhub_consumer/README.md create mode 100644 plugins/inputs/eventhub_consumer/eventhub_consumer.go create mode 100644 plugins/inputs/eventhub_consumer/sample.conf create mode 100644 plugins/inputs/example/README.md create mode 100644 plugins/inputs/example/example.go create mode 100644 plugins/inputs/example/example_test.go create mode 100644 plugins/inputs/example/sample.conf create mode 100644 plugins/inputs/exec/README.md create mode 100644 plugins/inputs/exec/dev/telegraf.conf create mode 100644 plugins/inputs/exec/exec.go create mode 100644 plugins/inputs/exec/exec_test.go create mode 100644 plugins/inputs/exec/run_notwindows.go create mode 100644 plugins/inputs/exec/run_windows.go create mode 100644 plugins/inputs/exec/sample.conf create mode 100644 plugins/inputs/execd/README.md create mode 100644 plugins/inputs/execd/examples/count.go create mode 100644 plugins/inputs/execd/examples/count.py create mode 100644 plugins/inputs/execd/examples/count.rb create mode 100644 plugins/inputs/execd/examples/count.sh create mode 100644 plugins/inputs/execd/execd.go create mode 100644 plugins/inputs/execd/execd_posix.go create mode 100644 plugins/inputs/execd/execd_test.go create mode 100644 plugins/inputs/execd/execd_windows.go create mode 100644 plugins/inputs/execd/sample.conf create mode 100644 plugins/inputs/execd/shim/README.md create mode 100644 plugins/inputs/execd/shim/example/cmd/main.go create mode 100644 plugins/inputs/execd/shim/example/cmd/plugin.conf create mode 100644 plugins/inputs/execd/shim/goshim.go create mode 100644 plugins/inputs/execd/shim/goshim_posix.go create mode 100644 plugins/inputs/execd/shim/goshim_windows.go create mode 100644 plugins/inputs/execd/shim/input.go create mode 100644 plugins/inputs/execd/shim/shim_posix_test.go create mode 100644 plugins/inputs/execd/shim/shim_test.go create mode 100644 plugins/inputs/execd/shim/testdata/plugin.conf create mode 100644 plugins/inputs/fail2ban/README.md create mode 100644 plugins/inputs/fail2ban/fail2ban.go create mode 100644 plugins/inputs/fail2ban/fail2ban_test.go create mode 100644 plugins/inputs/fail2ban/sample.conf create mode 100644 plugins/inputs/fibaro/README.md create mode 100644 plugins/inputs/fibaro/fibaro.go create mode 100644 plugins/inputs/fibaro/fibaro_test.go create mode 100644 plugins/inputs/fibaro/hc2/parser.go create mode 100644 plugins/inputs/fibaro/hc2/types.go create mode 100644 plugins/inputs/fibaro/hc3/parser.go create mode 100644 plugins/inputs/fibaro/hc3/types.go create mode 100644 plugins/inputs/fibaro/sample.conf create mode 100644 plugins/inputs/fibaro/testdata/device_hc2.json create mode 100644 plugins/inputs/fibaro/testdata/device_hc3.json create mode 100644 plugins/inputs/fibaro/testdata/rooms.json create mode 100644 plugins/inputs/fibaro/testdata/sections.json create mode 100644 plugins/inputs/file/README.md create mode 100644 plugins/inputs/file/dev/docker-compose.yml create mode 100644 plugins/inputs/file/dev/telegraf.conf create mode 100644 plugins/inputs/file/dev/testfiles/grok_a.log create mode 100644 plugins/inputs/file/dev/testfiles/json_a.log create mode 100644 plugins/inputs/file/file.go create mode 100644 plugins/inputs/file/file_test.go create mode 100644 plugins/inputs/file/sample.conf create mode 100644 plugins/inputs/file/testdata/csv_behavior_input.csv create mode 100644 plugins/inputs/file/testdata/mtr-utf-16be.csv create mode 100644 plugins/inputs/file/testdata/mtr-utf-16le.csv create mode 100644 plugins/inputs/file/testdata/mtr-utf-8.csv create mode 100644 plugins/inputs/filecount/README.md create mode 100644 plugins/inputs/filecount/filecount.go create mode 100644 plugins/inputs/filecount/filecount_test.go create mode 100644 plugins/inputs/filecount/filesystem_helpers.go create mode 100644 plugins/inputs/filecount/filesystem_helpers_notwindows_test.go create mode 100644 plugins/inputs/filecount/filesystem_helpers_test.go create mode 100644 plugins/inputs/filecount/sample.conf create mode 100644 plugins/inputs/filecount/testdata/bar create mode 100644 plugins/inputs/filecount/testdata/baz create mode 100644 plugins/inputs/filecount/testdata/foo create mode 100644 plugins/inputs/filecount/testdata/qux create mode 100644 plugins/inputs/filecount/testdata/subdir/nested2/qux create mode 100644 plugins/inputs/filecount/testdata/subdir/quux create mode 100644 plugins/inputs/filecount/testdata/subdir/quuz create mode 100644 plugins/inputs/filestat/README.md create mode 100644 plugins/inputs/filestat/filestat.go create mode 100644 plugins/inputs/filestat/filestat_test.go create mode 100644 plugins/inputs/filestat/sample.conf create mode 100644 plugins/inputs/filestat/testdata/log1.log create mode 100644 plugins/inputs/filestat/testdata/log2.log create mode 100644 plugins/inputs/filestat/testdata/test.conf create mode 100644 plugins/inputs/fireboard/README.md create mode 100644 plugins/inputs/fireboard/fireboard.go create mode 100644 plugins/inputs/fireboard/fireboard_test.go create mode 100644 plugins/inputs/fireboard/sample.conf create mode 100644 plugins/inputs/firehose/README.md create mode 100644 plugins/inputs/firehose/firehose.go create mode 100644 plugins/inputs/firehose/firehose_request_test.go create mode 100644 plugins/inputs/firehose/firehose_test.go create mode 100644 plugins/inputs/firehose/message.go create mode 100644 plugins/inputs/firehose/sample.conf create mode 100644 plugins/inputs/firehose/testcases/common-attributes/body.json create mode 100644 plugins/inputs/firehose/testcases/common-attributes/expected.out create mode 100644 plugins/inputs/firehose/testcases/common-attributes/headers.json create mode 100644 plugins/inputs/firehose/testcases/common-attributes/telegraf.conf create mode 100644 plugins/inputs/fluentd/README.md create mode 100644 plugins/inputs/fluentd/fluentd.go create mode 100644 plugins/inputs/fluentd/fluentd_test.go create mode 100644 plugins/inputs/fluentd/sample.conf create mode 100644 plugins/inputs/github/README.md create mode 100644 plugins/inputs/github/github.go create mode 100644 plugins/inputs/github/github_test.go create mode 100644 plugins/inputs/github/sample.conf create mode 100644 plugins/inputs/gnmi/README.md create mode 100644 plugins/inputs/gnmi/extensions/jnpr_gnmi_extention/GnmiJuniperTelemetryHeaderExtension.pb.go create mode 100644 plugins/inputs/gnmi/gnmi.go create mode 100644 plugins/inputs/gnmi/gnmi_test.go create mode 100644 plugins/inputs/gnmi/handler.go create mode 100644 plugins/inputs/gnmi/path.go create mode 100644 plugins/inputs/gnmi/sample.conf create mode 100644 plugins/inputs/gnmi/sample.conf.in create mode 100644 plugins/inputs/gnmi/tag_store.go create mode 100644 plugins/inputs/gnmi/testcases/canonical_field_names/expected.out create mode 100644 plugins/inputs/gnmi/testcases/canonical_field_names/responses.json create mode 100644 plugins/inputs/gnmi/testcases/canonical_field_names/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/canonical_field_names_trim/expected.out create mode 100644 plugins/inputs/gnmi/testcases/canonical_field_names_trim/responses.json create mode 100644 plugins/inputs/gnmi/testcases/canonical_field_names_trim/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_11011/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_11011/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_11011/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_11778/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_11778/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_11778/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_11778_tag_only/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_11778_tag_only/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_11778_tag_only/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_12831/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_12831/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_12831/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_12931/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_12931/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_12931/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_13052/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_13052/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_13052/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_13512/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_13512/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_13512/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_14044/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_14044/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_14044/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_14063/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_14063/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_14063/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_14530/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_14530/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_14530/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_14833/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_14833/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_14833/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_14946/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_14946/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_14946/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_14946_canonical_field_names/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_14946_canonical_field_names/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_14946_canonical_field_names/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_15046/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_15046/models/LICENSE create mode 100644 plugins/inputs/gnmi/testcases/issue_15046/models/README.md create mode 100644 plugins/inputs/gnmi/testcases/issue_15046/models/openconfig-alarm-types.yang create mode 100644 plugins/inputs/gnmi/testcases/issue_15046/models/openconfig-extensions.yang create mode 100644 plugins/inputs/gnmi/testcases/issue_15046/models/openconfig-platform-psu.yang create mode 100644 plugins/inputs/gnmi/testcases/issue_15046/models/openconfig-platform-types.yang create mode 100644 plugins/inputs/gnmi/testcases/issue_15046/models/openconfig-platform.yang create mode 100644 plugins/inputs/gnmi/testcases/issue_15046/models/openconfig-types.yang create mode 100644 plugins/inputs/gnmi/testcases/issue_15046/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_15046/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_15546/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_15546/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_15546/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_16476/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_16476/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_16476/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/issue_16515/expected.out create mode 100644 plugins/inputs/gnmi/testcases/issue_16515/responses.json create mode 100644 plugins/inputs/gnmi/testcases/issue_16515/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/tagging_name_based/expected.out create mode 100644 plugins/inputs/gnmi/testcases/tagging_name_based/responses.json create mode 100644 plugins/inputs/gnmi/testcases/tagging_name_based/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/tagging_name_based_old/expected.out create mode 100644 plugins/inputs/gnmi/testcases/tagging_name_based_old/responses.json create mode 100644 plugins/inputs/gnmi/testcases/tagging_name_based_old/telegraf.conf create mode 100644 plugins/inputs/gnmi/testcases/tagging_subinterfaces/expected.out create mode 100644 plugins/inputs/gnmi/testcases/tagging_subinterfaces/responses.json create mode 100644 plugins/inputs/gnmi/testcases/tagging_subinterfaces/telegraf.conf create mode 100644 plugins/inputs/gnmi/update_fields.go create mode 100644 plugins/inputs/google_cloud_storage/README.md create mode 100644 plugins/inputs/google_cloud_storage/google_cloud_storage.go create mode 100644 plugins/inputs/google_cloud_storage/google_cloud_storage_test.go create mode 100644 plugins/inputs/google_cloud_storage/sample.conf create mode 100644 plugins/inputs/google_cloud_storage/testdata/file_listing.json create mode 100644 plugins/inputs/google_cloud_storage/testdata/first_file.json create mode 100644 plugins/inputs/google_cloud_storage/testdata/first_file_listing.json create mode 100644 plugins/inputs/google_cloud_storage/testdata/fourth_file.json create mode 100644 plugins/inputs/google_cloud_storage/testdata/fourth_file_listing.json create mode 100644 plugins/inputs/google_cloud_storage/testdata/second_file.json create mode 100644 plugins/inputs/google_cloud_storage/testdata/second_file_listing.json create mode 100644 plugins/inputs/google_cloud_storage/testdata/single_file_list.json create mode 100644 plugins/inputs/google_cloud_storage/testdata/single_object_not_found.json create mode 100644 plugins/inputs/google_cloud_storage/testdata/third_file.json create mode 100644 plugins/inputs/google_cloud_storage/testdata/third_file_listing.json create mode 100644 plugins/inputs/graylog/README.md create mode 100644 plugins/inputs/graylog/graylog.go create mode 100644 plugins/inputs/graylog/graylog_test.go create mode 100644 plugins/inputs/graylog/sample.conf create mode 100644 plugins/inputs/haproxy/README.md create mode 100644 plugins/inputs/haproxy/haproxy.go create mode 100644 plugins/inputs/haproxy/haproxy_test.go create mode 100644 plugins/inputs/haproxy/sample.conf create mode 100644 plugins/inputs/haproxy/testdata/sample_output.csv create mode 100644 plugins/inputs/hddtemp/README.md create mode 100644 plugins/inputs/hddtemp/go-hddtemp/LICENSE create mode 100644 plugins/inputs/hddtemp/go-hddtemp/hddtemp.go create mode 100644 plugins/inputs/hddtemp/go-hddtemp/hddtemp_test.go create mode 100644 plugins/inputs/hddtemp/hddtemp.go create mode 100644 plugins/inputs/hddtemp/hddtemp_test.go create mode 100644 plugins/inputs/hddtemp/sample.conf create mode 100644 plugins/inputs/http/README.md create mode 100644 plugins/inputs/http/http.go create mode 100644 plugins/inputs/http/http_test.go create mode 100644 plugins/inputs/http/sample.conf create mode 100644 plugins/inputs/http/sample.conf.in create mode 100644 plugins/inputs/http_listener_v2/README.md create mode 100644 plugins/inputs/http_listener_v2/http_listener_v2.go create mode 100644 plugins/inputs/http_listener_v2/http_listener_v2_test.go create mode 100644 plugins/inputs/http_listener_v2/sample.conf create mode 100644 plugins/inputs/http_listener_v2/testdata/huge_metric create mode 100644 plugins/inputs/http_listener_v2/testdata/testmsgs.gz create mode 100644 plugins/inputs/http_response/README.md create mode 100644 plugins/inputs/http_response/http_response.go create mode 100644 plugins/inputs/http_response/http_response_test.go create mode 100644 plugins/inputs/http_response/sample.conf create mode 100644 plugins/inputs/huebridge/README.md create mode 100644 plugins/inputs/huebridge/bridge.go create mode 100644 plugins/inputs/huebridge/huebridge.go create mode 100644 plugins/inputs/huebridge/huebridge_test.go create mode 100644 plugins/inputs/huebridge/sample.conf create mode 100644 plugins/inputs/huebridge/testdata/conf/huebridge.conf create mode 100644 plugins/inputs/huebridge/testdata/metrics/huebridge.txt create mode 100644 plugins/inputs/hugepages/README.md create mode 100644 plugins/inputs/hugepages/hugepages.go create mode 100644 plugins/inputs/hugepages/hugepages_notlinux.go create mode 100644 plugins/inputs/hugepages/hugepages_test.go create mode 100644 plugins/inputs/hugepages/sample.conf create mode 100644 plugins/inputs/hugepages/testdata/invalid/1/anode3/dir_lock create mode 100644 plugins/inputs/hugepages/testdata/invalid/1/node0/hugepages/hugepages-1048576kB/free_hugepages/dir_lock create mode 100644 plugins/inputs/hugepages/testdata/invalid/1/node0/hugepages/hugepages-1048576kB/nry_hugepages create mode 100644 plugins/inputs/hugepages/testdata/invalid/1/node0/hugepages/hugepages-2048kB create mode 100644 plugins/inputs/hugepages/testdata/invalid/1/node0/hugepages/hugepages-aaaa1048576kB/free_hugepages create mode 100644 plugins/inputs/hugepages/testdata/invalid/1/node0/hugepages/hugepages1048576kB/free_hugepages create mode 100644 plugins/inputs/hugepages/testdata/invalid/1/node1 create mode 100644 plugins/inputs/hugepages/testdata/invalid/1/node4b/dir_lock create mode 100644 plugins/inputs/hugepages/testdata/invalid/2/node1/hugepages/hugepages-1048576kB/nr_hugepages create mode 100644 plugins/inputs/hugepages/testdata/invalid/meminfo create mode 100644 plugins/inputs/hugepages/testdata/valid/meminfo create mode 100644 plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-1048576kB/free_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-1048576kB/nr_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-1048576kB/nr_hugepages_mempolicy create mode 100644 plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-1048576kB/nr_overcommit_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-1048576kB/resv_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-1048576kB/surplus_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-2048kB/free_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-2048kB/nr_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-2048kB/nr_hugepages_mempolicy create mode 100644 plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-2048kB/nr_overcommit_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-2048kB/resv_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/mm/hugepages/hugepages-2048kB/surplus_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/node/node0/hugepages/hugepages-1048576kB/free_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/node/node0/hugepages/hugepages-1048576kB/nr_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/node/node0/hugepages/hugepages-1048576kB/surplus_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/node/node0/hugepages/hugepages-2048kB/free_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/node/node0/hugepages/hugepages-2048kB/nr_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/node/node0/hugepages/hugepages-2048kB/surplus_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/node/node1/hugepages/hugepages-1048576kB/free_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/node/node1/hugepages/hugepages-1048576kB/nr_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/node/node1/hugepages/hugepages-1048576kB/surplus_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/node/node1/hugepages/hugepages-2048kB/free_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/node/node1/hugepages/hugepages-2048kB/nr_hugepages create mode 100644 plugins/inputs/hugepages/testdata/valid/node/node1/hugepages/hugepages-2048kB/surplus_hugepages create mode 100644 plugins/inputs/icinga2/README.md create mode 100644 plugins/inputs/icinga2/icinga2.go create mode 100644 plugins/inputs/icinga2/icinga2_test.go create mode 100644 plugins/inputs/icinga2/sample.conf create mode 100644 plugins/inputs/infiniband/README.md create mode 100644 plugins/inputs/infiniband/infiniband.go create mode 100644 plugins/inputs/infiniband/infiniband_linux.go create mode 100644 plugins/inputs/infiniband/infiniband_notlinux.go create mode 100644 plugins/inputs/infiniband/infiniband_test.go create mode 100644 plugins/inputs/infiniband/sample.conf create mode 100644 plugins/inputs/influxdb/README.md create mode 100644 plugins/inputs/influxdb/influxdb.go create mode 100644 plugins/inputs/influxdb/influxdb_test.go create mode 100644 plugins/inputs/influxdb/sample.conf create mode 100644 plugins/inputs/influxdb/testdata/cloud1.influx create mode 100644 plugins/inputs/influxdb/testdata/cloud1.json create mode 100644 plugins/inputs/influxdb/testdata/influx_return.json create mode 100644 plugins/inputs/influxdb/testdata/influx_return2.json create mode 100644 plugins/inputs/influxdb/types.go create mode 100644 plugins/inputs/influxdb_listener/README.md create mode 100644 plugins/inputs/influxdb_listener/influxdb_listener.go create mode 100644 plugins/inputs/influxdb_listener/influxdb_listener_benchmark_test.go create mode 100644 plugins/inputs/influxdb_listener/influxdb_listener_test.go create mode 100644 plugins/inputs/influxdb_listener/sample.conf create mode 100644 plugins/inputs/influxdb_listener/testdata/huge_metric create mode 100644 plugins/inputs/influxdb_listener/testdata/testmsgs.gz create mode 100644 plugins/inputs/influxdb_v2_listener/README.md create mode 100644 plugins/inputs/influxdb_v2_listener/influxdb_v2_listener.go create mode 100644 plugins/inputs/influxdb_v2_listener/influxdb_v2_listener_benchmark_test.go create mode 100644 plugins/inputs/influxdb_v2_listener/influxdb_v2_listener_test.go create mode 100644 plugins/inputs/influxdb_v2_listener/sample.conf create mode 100644 plugins/inputs/influxdb_v2_listener/testdata/huge_metric create mode 100644 plugins/inputs/influxdb_v2_listener/testdata/testmsgs.gz create mode 100644 plugins/inputs/intel_baseband/README.md create mode 100644 plugins/inputs/intel_baseband/intel_baseband.go create mode 100644 plugins/inputs/intel_baseband/intel_baseband_notamd64linux.go create mode 100644 plugins/inputs/intel_baseband/intel_baseband_test.go create mode 100644 plugins/inputs/intel_baseband/log_connector.go create mode 100644 plugins/inputs/intel_baseband/log_connector_test.go create mode 100644 plugins/inputs/intel_baseband/mocks/conn.go create mode 100644 plugins/inputs/intel_baseband/sample.conf create mode 100644 plugins/inputs/intel_baseband/sock_connector.go create mode 100644 plugins/inputs/intel_baseband/sock_connector_test.go create mode 100644 plugins/inputs/intel_baseband/testdata/logfiles/empty.log create mode 100644 plugins/inputs/intel_baseband/testdata/logfiles/example.log create mode 100644 plugins/inputs/intel_baseband/utils.go create mode 100644 plugins/inputs/intel_baseband/utils_test.go create mode 100644 plugins/inputs/intel_dlb/README.md create mode 100644 plugins/inputs/intel_dlb/intel_dlb.go create mode 100644 plugins/inputs/intel_dlb/intel_dlb_notlinux.go create mode 100644 plugins/inputs/intel_dlb/intel_dlb_test.go create mode 100644 plugins/inputs/intel_dlb/ras_reader.go create mode 100644 plugins/inputs/intel_dlb/ras_reader_mock.go create mode 100644 plugins/inputs/intel_dlb/sample.conf create mode 100644 plugins/inputs/intel_pmt/README.md create mode 100644 plugins/inputs/intel_pmt/filtering.go create mode 100644 plugins/inputs/intel_pmt/filtering_test.go create mode 100644 plugins/inputs/intel_pmt/intel_pmt.go create mode 100644 plugins/inputs/intel_pmt/intel_pmt_notamd64linux.go create mode 100644 plugins/inputs/intel_pmt/intel_pmt_test.go create mode 100644 plugins/inputs/intel_pmt/sample.conf create mode 100644 plugins/inputs/intel_pmt/tags_extraction.go create mode 100644 plugins/inputs/intel_pmt/tags_extraction_test.go create mode 100644 plugins/inputs/intel_pmt/xml_parser.go create mode 100644 plugins/inputs/intel_pmt/xml_parser_test.go create mode 100644 plugins/inputs/intel_pmu/README.md create mode 100644 plugins/inputs/intel_pmu/activators.go create mode 100644 plugins/inputs/intel_pmu/activators_test.go create mode 100644 plugins/inputs/intel_pmu/config.go create mode 100644 plugins/inputs/intel_pmu/config_test.go create mode 100644 plugins/inputs/intel_pmu/intel_pmu.go create mode 100644 plugins/inputs/intel_pmu/intel_pmu_notamd64linux.go create mode 100644 plugins/inputs/intel_pmu/intel_pmu_test.go create mode 100644 plugins/inputs/intel_pmu/mocks.go create mode 100644 plugins/inputs/intel_pmu/reader.go create mode 100644 plugins/inputs/intel_pmu/reader_test.go create mode 100644 plugins/inputs/intel_pmu/resolver.go create mode 100644 plugins/inputs/intel_pmu/resolver_test.go create mode 100644 plugins/inputs/intel_pmu/sample.conf create mode 100644 plugins/inputs/intel_powerstat/README.md create mode 100644 plugins/inputs/intel_powerstat/fetcher.go create mode 100644 plugins/inputs/intel_powerstat/intel_powerstat.go create mode 100644 plugins/inputs/intel_powerstat/intel_powerstat_notlinux.go create mode 100644 plugins/inputs/intel_powerstat/intel_powerstat_test.go create mode 100644 plugins/inputs/intel_powerstat/metrics.go create mode 100644 plugins/inputs/intel_powerstat/metrics_test.go create mode 100644 plugins/inputs/intel_powerstat/options.go create mode 100644 plugins/inputs/intel_powerstat/options_test.go create mode 100644 plugins/inputs/intel_powerstat/sample.conf create mode 100644 plugins/inputs/intel_powerstat/testdata/aperfmperf_flag_not_found/cpuinfo create mode 100644 plugins/inputs/intel_powerstat/testdata/cpu_model_missing/cpuinfo create mode 100644 plugins/inputs/intel_powerstat/testdata/cpuinfo create mode 100644 plugins/inputs/intel_powerstat/testdata/dts_flag_not_found/cpuinfo create mode 100644 plugins/inputs/intel_powerstat/testdata/model_not_supported/cpuinfo create mode 100644 plugins/inputs/intel_powerstat/testdata/msr_flag_not_found/cpuinfo create mode 100644 plugins/inputs/intel_powerstat/testdata/sapphirerapids_core.json create mode 100644 plugins/inputs/intel_powerstat/testdata/vendor_not_supported/cpuinfo create mode 100644 plugins/inputs/intel_rdt/README.md create mode 100644 plugins/inputs/intel_rdt/intel_rdt.go create mode 100644 plugins/inputs/intel_rdt/intel_rdt_test.go create mode 100644 plugins/inputs/intel_rdt/intel_rdt_windows.go create mode 100644 plugins/inputs/intel_rdt/processes.go create mode 100644 plugins/inputs/intel_rdt/publisher.go create mode 100644 plugins/inputs/intel_rdt/publisher_test.go create mode 100644 plugins/inputs/intel_rdt/sample.conf create mode 100644 plugins/inputs/internal/README.md create mode 100644 plugins/inputs/internal/internal.go create mode 100644 plugins/inputs/internal/internal_test.go create mode 100644 plugins/inputs/internal/sample.conf create mode 100644 plugins/inputs/internet_speed/README.md create mode 100644 plugins/inputs/internet_speed/internet_speed.go create mode 100644 plugins/inputs/internet_speed/internet_speed_test.go create mode 100644 plugins/inputs/internet_speed/sample.conf create mode 100644 plugins/inputs/interrupts/README.md create mode 100644 plugins/inputs/interrupts/interrupts.go create mode 100644 plugins/inputs/interrupts/interrupts_test.go create mode 100644 plugins/inputs/interrupts/sample.conf create mode 100644 plugins/inputs/ipmi_sensor/README.md create mode 100644 plugins/inputs/ipmi_sensor/connection.go create mode 100644 plugins/inputs/ipmi_sensor/connection_test.go create mode 100644 plugins/inputs/ipmi_sensor/ipmi_sensor.go create mode 100644 plugins/inputs/ipmi_sensor/ipmi_sensor_test.go create mode 100644 plugins/inputs/ipmi_sensor/sample.conf create mode 100644 plugins/inputs/ipset/README.md create mode 100644 plugins/inputs/ipset/ipset.go create mode 100644 plugins/inputs/ipset/ipset_entries.go create mode 100644 plugins/inputs/ipset/ipset_entries_test.go create mode 100644 plugins/inputs/ipset/ipset_test.go create mode 100644 plugins/inputs/ipset/sample.conf create mode 100644 plugins/inputs/iptables/README.md create mode 100644 plugins/inputs/iptables/iptables.go create mode 100644 plugins/inputs/iptables/iptables_notlinux.go create mode 100644 plugins/inputs/iptables/iptables_test.go create mode 100644 plugins/inputs/iptables/sample.conf create mode 100644 plugins/inputs/ipvs/README.md create mode 100644 plugins/inputs/ipvs/ipvs.go create mode 100644 plugins/inputs/ipvs/ipvs_notlinux.go create mode 100644 plugins/inputs/ipvs/sample.conf create mode 100644 plugins/inputs/jenkins/README.md create mode 100644 plugins/inputs/jenkins/client.go create mode 100644 plugins/inputs/jenkins/jenkins.go create mode 100644 plugins/inputs/jenkins/jenkins_test.go create mode 100644 plugins/inputs/jenkins/sample.conf create mode 100644 plugins/inputs/jolokia2_agent/README.md create mode 100644 plugins/inputs/jolokia2_agent/examples/activemq.conf create mode 100644 plugins/inputs/jolokia2_agent/examples/bitbucket.conf create mode 100644 plugins/inputs/jolokia2_agent/examples/cassandra.conf create mode 100644 plugins/inputs/jolokia2_agent/examples/hadoop-hdfs.conf create mode 100644 plugins/inputs/jolokia2_agent/examples/java.conf create mode 100644 plugins/inputs/jolokia2_agent/examples/jboss.conf create mode 100644 plugins/inputs/jolokia2_agent/examples/kafka-connect.conf create mode 100644 plugins/inputs/jolokia2_agent/examples/kafka.conf create mode 100644 plugins/inputs/jolokia2_agent/examples/tomcat.conf create mode 100644 plugins/inputs/jolokia2_agent/examples/weblogic.conf create mode 100644 plugins/inputs/jolokia2_agent/examples/zookeeper.conf create mode 100644 plugins/inputs/jolokia2_agent/jolokia2_agent.go create mode 100644 plugins/inputs/jolokia2_agent/jolokia2_agent_test.go create mode 100644 plugins/inputs/jolokia2_agent/sample.conf create mode 100644 plugins/inputs/jolokia2_agent/testdata/response.json create mode 100644 plugins/inputs/jolokia2_proxy/README.md create mode 100644 plugins/inputs/jolokia2_proxy/jolokia2_proxy.go create mode 100644 plugins/inputs/jolokia2_proxy/jolokia2_proxy_test.go create mode 100644 plugins/inputs/jolokia2_proxy/sample.conf create mode 100644 plugins/inputs/jti_openconfig_telemetry/README.md create mode 100644 plugins/inputs/jti_openconfig_telemetry/auth/authentication_service.pb.go create mode 100644 plugins/inputs/jti_openconfig_telemetry/auth/authentication_service.proto create mode 100644 plugins/inputs/jti_openconfig_telemetry/auth/authentication_service_grpc.pb.go create mode 100644 plugins/inputs/jti_openconfig_telemetry/collection.go create mode 100644 plugins/inputs/jti_openconfig_telemetry/gen.go create mode 100644 plugins/inputs/jti_openconfig_telemetry/jti_openconfig_telemetry.go create mode 100644 plugins/inputs/jti_openconfig_telemetry/jti_openconfig_telemetry_test.go create mode 100644 plugins/inputs/jti_openconfig_telemetry/oc/oc.pb.go create mode 100644 plugins/inputs/jti_openconfig_telemetry/oc/oc.proto create mode 100644 plugins/inputs/jti_openconfig_telemetry/oc/oc_grpc.pb.go create mode 100644 plugins/inputs/jti_openconfig_telemetry/sample.conf create mode 100644 plugins/inputs/kafka_consumer/README.md create mode 100644 plugins/inputs/kafka_consumer/kafka_consumer.go create mode 100644 plugins/inputs/kafka_consumer/kafka_consumer_test.go create mode 100644 plugins/inputs/kafka_consumer/sample.conf create mode 100644 plugins/inputs/kapacitor/README.md create mode 100644 plugins/inputs/kapacitor/kapacitor.go create mode 100644 plugins/inputs/kapacitor/kapacitor_test.go create mode 100644 plugins/inputs/kapacitor/sample.conf create mode 100644 plugins/inputs/kapacitor/testdata/kapacitor_return.json create mode 100644 plugins/inputs/kernel/README.md create mode 100644 plugins/inputs/kernel/kernel.go create mode 100644 plugins/inputs/kernel/kernel_notlinux.go create mode 100644 plugins/inputs/kernel/kernel_test.go create mode 100644 plugins/inputs/kernel/psi.go create mode 100644 plugins/inputs/kernel/psi_test.go create mode 100644 plugins/inputs/kernel/sample.conf create mode 100644 plugins/inputs/kernel/testdata/entropy_stat_file_full create mode 100644 plugins/inputs/kernel/testdata/entropy_stat_file_invalid create mode 100644 plugins/inputs/kernel/testdata/entropy_stat_file_partial create mode 100644 plugins/inputs/kernel/testdata/ksm/invalid/full_scans create mode 100644 plugins/inputs/kernel/testdata/ksm/invalid/max_page_sharing create mode 100644 plugins/inputs/kernel/testdata/ksm/invalid/merge_across_nodes create mode 100644 plugins/inputs/kernel/testdata/ksm/invalid/pages_shared create mode 100644 plugins/inputs/kernel/testdata/ksm/invalid/pages_sharing create mode 100644 plugins/inputs/kernel/testdata/ksm/invalid/pages_to_scan create mode 100644 plugins/inputs/kernel/testdata/ksm/invalid/pages_unshared create mode 100644 plugins/inputs/kernel/testdata/ksm/invalid/pages_volatile create mode 100644 plugins/inputs/kernel/testdata/ksm/invalid/run create mode 100644 plugins/inputs/kernel/testdata/ksm/invalid/sleep_millisecs create mode 100644 plugins/inputs/kernel/testdata/ksm/invalid/stable_node_chains create mode 100644 plugins/inputs/kernel/testdata/ksm/invalid/stable_node_chains_prune_millisecs create mode 100644 plugins/inputs/kernel/testdata/ksm/invalid/stable_node_dups create mode 100644 plugins/inputs/kernel/testdata/ksm/invalid/use_zero_pages create mode 100644 plugins/inputs/kernel/testdata/ksm/missing/full_scans create mode 100644 plugins/inputs/kernel/testdata/ksm/missing/max_page_sharing create mode 100644 plugins/inputs/kernel/testdata/ksm/missing/merge_across_nodes create mode 100644 plugins/inputs/kernel/testdata/ksm/missing/pages_shared create mode 100644 plugins/inputs/kernel/testdata/ksm/missing/pages_sharing create mode 100644 plugins/inputs/kernel/testdata/ksm/missing/pages_to_scan create mode 100644 plugins/inputs/kernel/testdata/ksm/missing/pages_unshared create mode 100644 plugins/inputs/kernel/testdata/ksm/missing/pages_volatile create mode 100644 plugins/inputs/kernel/testdata/ksm/missing/sleep_millisecs create mode 100644 plugins/inputs/kernel/testdata/ksm/missing/stable_node_chains create mode 100644 plugins/inputs/kernel/testdata/ksm/missing/stable_node_chains_prune_millisecs create mode 100644 plugins/inputs/kernel/testdata/ksm/missing/stable_node_dups create mode 100644 plugins/inputs/kernel/testdata/ksm/missing/use_zero_pages create mode 100644 plugins/inputs/kernel/testdata/ksm/valid/full_scans create mode 100644 plugins/inputs/kernel/testdata/ksm/valid/max_page_sharing create mode 100644 plugins/inputs/kernel/testdata/ksm/valid/merge_across_nodes create mode 100644 plugins/inputs/kernel/testdata/ksm/valid/pages_shared create mode 100644 plugins/inputs/kernel/testdata/ksm/valid/pages_sharing create mode 100644 plugins/inputs/kernel/testdata/ksm/valid/pages_to_scan create mode 100644 plugins/inputs/kernel/testdata/ksm/valid/pages_unshared create mode 100644 plugins/inputs/kernel/testdata/ksm/valid/pages_volatile create mode 100644 plugins/inputs/kernel/testdata/ksm/valid/run create mode 100644 plugins/inputs/kernel/testdata/ksm/valid/sleep_millisecs create mode 100644 plugins/inputs/kernel/testdata/ksm/valid/stable_node_chains create mode 100644 plugins/inputs/kernel/testdata/ksm/valid/stable_node_chains_prune_millisecs create mode 100644 plugins/inputs/kernel/testdata/ksm/valid/stable_node_dups create mode 100644 plugins/inputs/kernel/testdata/ksm/valid/use_zero_pages create mode 100644 plugins/inputs/kernel/testdata/pressure/cpu create mode 100644 plugins/inputs/kernel/testdata/pressure/io create mode 100644 plugins/inputs/kernel/testdata/pressure/memory create mode 100644 plugins/inputs/kernel/testdata/stat_file_full create mode 100644 plugins/inputs/kernel/testdata/stat_file_invalid create mode 100644 plugins/inputs/kernel/testdata/stat_file_invalid2 create mode 100644 plugins/inputs/kernel/testdata/stat_file_partial create mode 100644 plugins/inputs/kernel_vmstat/README.md create mode 100644 plugins/inputs/kernel_vmstat/kernel_vmstat.go create mode 100644 plugins/inputs/kernel_vmstat/kernel_vmstat_notlinux.go create mode 100644 plugins/inputs/kernel_vmstat/kernel_vmstat_test.go create mode 100644 plugins/inputs/kernel_vmstat/sample.conf create mode 100644 plugins/inputs/kibana/README.md create mode 100644 plugins/inputs/kibana/kibana.go create mode 100644 plugins/inputs/kibana/kibana_test.go create mode 100644 plugins/inputs/kibana/sample.conf create mode 100644 plugins/inputs/kibana/test_environment/basic_kibana_telegraf.conf create mode 100644 plugins/inputs/kibana/test_environment/docker-compose.yml create mode 100644 plugins/inputs/kibana/test_environment/run_test_env.sh create mode 100644 plugins/inputs/kibana/testdata_test6_3.go create mode 100644 plugins/inputs/kibana/testdata_test6_5.go create mode 100644 plugins/inputs/kinesis_consumer/README.md create mode 100644 plugins/inputs/kinesis_consumer/consumer.go create mode 100644 plugins/inputs/kinesis_consumer/encoding.go create mode 100644 plugins/inputs/kinesis_consumer/kinesis_consumer.go create mode 100644 plugins/inputs/kinesis_consumer/kinesis_consumer_test.go create mode 100644 plugins/inputs/kinesis_consumer/logging.go create mode 100644 plugins/inputs/kinesis_consumer/sample.conf create mode 100644 plugins/inputs/kinesis_consumer/store.go create mode 100644 plugins/inputs/knx_listener/README.md create mode 100644 plugins/inputs/knx_listener/knx_dummy_interface.go create mode 100644 plugins/inputs/knx_listener/knx_listener.go create mode 100644 plugins/inputs/knx_listener/knx_listener_test.go create mode 100644 plugins/inputs/knx_listener/sample.conf create mode 100644 plugins/inputs/kube_inventory/README.md create mode 100644 plugins/inputs/kube_inventory/certificate.go create mode 100644 plugins/inputs/kube_inventory/client.go create mode 100644 plugins/inputs/kube_inventory/client_test.go create mode 100644 plugins/inputs/kube_inventory/daemonset.go create mode 100644 plugins/inputs/kube_inventory/daemonset_test.go create mode 100644 plugins/inputs/kube_inventory/deployment.go create mode 100644 plugins/inputs/kube_inventory/deployment_test.go create mode 100644 plugins/inputs/kube_inventory/endpoint.go create mode 100644 plugins/inputs/kube_inventory/endpoint_test.go create mode 100644 plugins/inputs/kube_inventory/ingress.go create mode 100644 plugins/inputs/kube_inventory/ingress_test.go create mode 100644 plugins/inputs/kube_inventory/kube_inventory.go create mode 100644 plugins/inputs/kube_inventory/node.go create mode 100644 plugins/inputs/kube_inventory/node_test.go create mode 100644 plugins/inputs/kube_inventory/persistentvolume.go create mode 100644 plugins/inputs/kube_inventory/persistentvolume_test.go create mode 100644 plugins/inputs/kube_inventory/persistentvolumeclaim.go create mode 100644 plugins/inputs/kube_inventory/persistentvolumeclaim_test.go create mode 100644 plugins/inputs/kube_inventory/pod.go create mode 100644 plugins/inputs/kube_inventory/pod_test.go create mode 100644 plugins/inputs/kube_inventory/resourcequotas.go create mode 100644 plugins/inputs/kube_inventory/resourcequotas_test.go create mode 100644 plugins/inputs/kube_inventory/sample.conf create mode 100644 plugins/inputs/kube_inventory/service.go create mode 100644 plugins/inputs/kube_inventory/service_test.go create mode 100644 plugins/inputs/kube_inventory/statefulset.go create mode 100644 plugins/inputs/kube_inventory/statefulset_test.go create mode 100644 plugins/inputs/kubernetes/README.md create mode 100644 plugins/inputs/kubernetes/kubernetes.go create mode 100644 plugins/inputs/kubernetes/kubernetes_metrics.go create mode 100644 plugins/inputs/kubernetes/kubernetes_pods.go create mode 100644 plugins/inputs/kubernetes/kubernetes_test.go create mode 100644 plugins/inputs/kubernetes/sample.conf create mode 100644 plugins/inputs/lanz/README.md create mode 100644 plugins/inputs/lanz/lanz.go create mode 100644 plugins/inputs/lanz/lanz_test.go create mode 100644 plugins/inputs/lanz/sample.conf create mode 100644 plugins/inputs/ldap/389ds.go create mode 100644 plugins/inputs/ldap/README.md create mode 100644 plugins/inputs/ldap/ldap.go create mode 100644 plugins/inputs/ldap/ldap_test.go create mode 100644 plugins/inputs/ldap/openldap.go create mode 100644 plugins/inputs/ldap/sample.conf create mode 100644 plugins/inputs/ldap/sample.conf.in create mode 100644 plugins/inputs/leofs/README.md create mode 100644 plugins/inputs/leofs/leofs.go create mode 100644 plugins/inputs/leofs/leofs_test.go create mode 100644 plugins/inputs/leofs/sample.conf create mode 100644 plugins/inputs/libvirt/README.md create mode 100644 plugins/inputs/libvirt/libvirt.go create mode 100644 plugins/inputs/libvirt/libvirt_metric_format.go create mode 100644 plugins/inputs/libvirt/libvirt_test.go create mode 100644 plugins/inputs/libvirt/libvirt_utils.go create mode 100644 plugins/inputs/libvirt/libvirt_utils_mock.go create mode 100644 plugins/inputs/libvirt/sample.conf create mode 100644 plugins/inputs/linux_cpu/README.md create mode 100644 plugins/inputs/linux_cpu/linux_cpu.go create mode 100644 plugins/inputs/linux_cpu/linux_cpu_nonlinux.go create mode 100644 plugins/inputs/linux_cpu/linux_cpu_test.go create mode 100644 plugins/inputs/linux_cpu/sample.conf create mode 100644 plugins/inputs/linux_sysctl_fs/README.md create mode 100644 plugins/inputs/linux_sysctl_fs/linux_sysctl_fs.go create mode 100644 plugins/inputs/linux_sysctl_fs/linux_sysctl_fs_test.go create mode 100644 plugins/inputs/linux_sysctl_fs/sample.conf create mode 100644 plugins/inputs/logparser/README.md create mode 100644 plugins/inputs/logparser/dev/docker-compose.yml create mode 100644 plugins/inputs/logparser/dev/telegraf.conf create mode 100644 plugins/inputs/logparser/dev/test.log create mode 100644 plugins/inputs/logparser/logparser.go create mode 100644 plugins/inputs/logparser/logparser_solaris.go create mode 100644 plugins/inputs/logparser/logparser_test.go create mode 100644 plugins/inputs/logparser/sample.conf create mode 100644 plugins/inputs/logparser/testdata/test-patterns create mode 100644 plugins/inputs/logparser/testdata/test_a.log create mode 100644 plugins/inputs/logparser/testdata/test_b.log create mode 100644 plugins/inputs/logparser/testdata/test_c.log create mode 100644 plugins/inputs/logstash/README.md create mode 100644 plugins/inputs/logstash/logstash.go create mode 100644 plugins/inputs/logstash/logstash_test.go create mode 100644 plugins/inputs/logstash/sample.conf create mode 100644 plugins/inputs/logstash/samples_logstash5.go create mode 100644 plugins/inputs/logstash/samples_logstash6.go create mode 100644 plugins/inputs/logstash/samples_logstash7.go create mode 100644 plugins/inputs/lustre2/README.md create mode 100644 plugins/inputs/lustre2/lustre2.go create mode 100644 plugins/inputs/lustre2/lustre2_notlinux.go create mode 100644 plugins/inputs/lustre2/lustre2_test.go create mode 100644 plugins/inputs/lustre2/sample.conf create mode 100644 plugins/inputs/lvm/README.md create mode 100644 plugins/inputs/lvm/lvm.go create mode 100644 plugins/inputs/lvm/lvm_test.go create mode 100644 plugins/inputs/lvm/sample.conf create mode 100644 plugins/inputs/mailchimp/README.md create mode 100644 plugins/inputs/mailchimp/chimp_api.go create mode 100644 plugins/inputs/mailchimp/mailchimp.go create mode 100644 plugins/inputs/mailchimp/mailchimp_test.go create mode 100644 plugins/inputs/mailchimp/sample.conf create mode 100644 plugins/inputs/marklogic/README.md create mode 100644 plugins/inputs/marklogic/marklogic.go create mode 100644 plugins/inputs/marklogic/marklogic_test.go create mode 100644 plugins/inputs/marklogic/sample.conf create mode 100644 plugins/inputs/mcrouter/README.md create mode 100644 plugins/inputs/mcrouter/mcrouter.go create mode 100644 plugins/inputs/mcrouter/mcrouter_test.go create mode 100644 plugins/inputs/mcrouter/sample.conf create mode 100644 plugins/inputs/mcrouter/testdata/mcrouter_stats create mode 100644 plugins/inputs/mdstat/README.md create mode 100644 plugins/inputs/mdstat/mdstat.go create mode 100644 plugins/inputs/mdstat/mdstat_notlinux.go create mode 100644 plugins/inputs/mdstat/mdstat_test.go create mode 100644 plugins/inputs/mdstat/sample.conf create mode 100644 plugins/inputs/mem/README.md create mode 100644 plugins/inputs/mem/mem.go create mode 100644 plugins/inputs/mem/mem_test.go create mode 100644 plugins/inputs/mem/sample.conf create mode 100644 plugins/inputs/memcached/README.md create mode 100644 plugins/inputs/memcached/memcached.go create mode 100644 plugins/inputs/memcached/memcached_test.go create mode 100644 plugins/inputs/memcached/sample.conf create mode 100644 plugins/inputs/mesos/README.md create mode 100644 plugins/inputs/mesos/mesos.go create mode 100644 plugins/inputs/mesos/mesos_test.go create mode 100644 plugins/inputs/mesos/sample.conf create mode 100644 plugins/inputs/minecraft/README.md create mode 100644 plugins/inputs/minecraft/client.go create mode 100644 plugins/inputs/minecraft/client_test.go create mode 100644 plugins/inputs/minecraft/minecraft.go create mode 100644 plugins/inputs/minecraft/minecraft_test.go create mode 100644 plugins/inputs/minecraft/sample.conf create mode 100644 plugins/inputs/mock/README.md create mode 100644 plugins/inputs/mock/mock.go create mode 100644 plugins/inputs/mock/mock_test.go create mode 100644 plugins/inputs/mock/sample.conf create mode 100644 plugins/inputs/modbus/README.md create mode 100644 plugins/inputs/modbus/configuration.go create mode 100644 plugins/inputs/modbus/configuration_metric.go create mode 100644 plugins/inputs/modbus/configuration_metric_test.go create mode 100644 plugins/inputs/modbus/configuration_register.go create mode 100644 plugins/inputs/modbus/configuration_register_test.go create mode 100644 plugins/inputs/modbus/configuration_request.go create mode 100644 plugins/inputs/modbus/configuration_request_test.go create mode 100644 plugins/inputs/modbus/modbus.go create mode 100644 plugins/inputs/modbus/modbus_test.go create mode 100644 plugins/inputs/modbus/request.go create mode 100644 plugins/inputs/modbus/sample_general_begin.conf create mode 100644 plugins/inputs/modbus/sample_general_end.conf create mode 100644 plugins/inputs/modbus/sample_metric.conf create mode 100644 plugins/inputs/modbus/sample_register.conf create mode 100644 plugins/inputs/modbus/sample_request.conf create mode 100644 plugins/inputs/modbus/testcases/duplicate_fields_different_registers/init.err create mode 100644 plugins/inputs/modbus/testcases/duplicate_fields_different_registers/telegraf.conf create mode 100644 plugins/inputs/modbus/testcases/duplicate_fields_different_slave/expected.out create mode 100644 plugins/inputs/modbus/testcases/duplicate_fields_different_slave/telegraf.conf create mode 100644 plugins/inputs/modbus/testcases/duplicate_fields_different_tags/expected.out create mode 100644 plugins/inputs/modbus/testcases/duplicate_fields_different_tags/telegraf.conf create mode 100644 plugins/inputs/modbus/testcases/duplicate_fields_issue_12091/expected.out create mode 100644 plugins/inputs/modbus/testcases/duplicate_fields_issue_12091/telegraf.conf create mode 100644 plugins/inputs/modbus/testcases/duplicate_fields_same_slave_and_request/init.err create mode 100644 plugins/inputs/modbus/testcases/duplicate_fields_same_slave_and_request/telegraf.conf create mode 100644 plugins/inputs/modbus/testcases/duplicate_fields_same_tags/init.err create mode 100644 plugins/inputs/modbus/testcases/duplicate_fields_same_tags/telegraf.conf create mode 100644 plugins/inputs/modbus/testcases/field_request_too_short_issue_13482/init.err create mode 100644 plugins/inputs/modbus/testcases/field_request_too_short_issue_13482/telegraf.conf create mode 100644 plugins/inputs/modbus/testcases/metric_style_issue_16031/expected.out create mode 100644 plugins/inputs/modbus/testcases/metric_style_issue_16031/telegraf.conf create mode 100644 plugins/inputs/modbus/testcases/overflow_issue_14387/expected.out create mode 100644 plugins/inputs/modbus/testcases/overflow_issue_14387/telegraf.conf create mode 100644 plugins/inputs/modbus/type_conversions.go create mode 100644 plugins/inputs/modbus/type_conversions16.go create mode 100644 plugins/inputs/modbus/type_conversions32.go create mode 100644 plugins/inputs/modbus/type_conversions64.go create mode 100644 plugins/inputs/modbus/type_conversions8.go create mode 100644 plugins/inputs/modbus/type_conversions_bit.go create mode 100644 plugins/inputs/modbus/type_conversions_string.go create mode 100644 plugins/inputs/mongodb/README.md create mode 100644 plugins/inputs/mongodb/dev/docker-compose.yml create mode 100644 plugins/inputs/mongodb/dev/telegraf.conf create mode 100644 plugins/inputs/mongodb/mongodb.go create mode 100644 plugins/inputs/mongodb/mongodb_data.go create mode 100644 plugins/inputs/mongodb/mongodb_data_test.go create mode 100644 plugins/inputs/mongodb/mongodb_server.go create mode 100644 plugins/inputs/mongodb/mongodb_server_test.go create mode 100644 plugins/inputs/mongodb/mongostat.go create mode 100644 plugins/inputs/mongodb/mongostat_test.go create mode 100644 plugins/inputs/mongodb/sample.conf create mode 100644 plugins/inputs/monit/README.md create mode 100644 plugins/inputs/monit/monit.go create mode 100644 plugins/inputs/monit/monit_test.go create mode 100644 plugins/inputs/monit/sample.conf create mode 100644 plugins/inputs/monit/testdata/response_invalidxml_1.xml create mode 100644 plugins/inputs/monit/testdata/response_invalidxml_2.xml create mode 100644 plugins/inputs/monit/testdata/response_invalidxml_3.xml create mode 100644 plugins/inputs/monit/testdata/response_servicetype_0.xml create mode 100644 plugins/inputs/monit/testdata/response_servicetype_1.xml create mode 100644 plugins/inputs/monit/testdata/response_servicetype_2.xml create mode 100644 plugins/inputs/monit/testdata/response_servicetype_3.xml create mode 100644 plugins/inputs/monit/testdata/response_servicetype_4.xml create mode 100644 plugins/inputs/monit/testdata/response_servicetype_5.xml create mode 100644 plugins/inputs/monit/testdata/response_servicetype_6.xml create mode 100644 plugins/inputs/monit/testdata/response_servicetype_7.xml create mode 100644 plugins/inputs/monit/testdata/response_servicetype_8.xml create mode 100644 plugins/inputs/monit/testdata/response_servicetype_8_failure.xml create mode 100644 plugins/inputs/monit/testdata/response_servicetype_8_initializingmode.xml create mode 100644 plugins/inputs/monit/testdata/response_servicetype_8_passivemode.xml create mode 100644 plugins/inputs/monit/testdata/response_servicetype_8_pendingaction.xml create mode 100644 plugins/inputs/mqtt_consumer/README.md create mode 100644 plugins/inputs/mqtt_consumer/mqtt_consumer.go create mode 100644 plugins/inputs/mqtt_consumer/mqtt_consumer_test.go create mode 100644 plugins/inputs/mqtt_consumer/mqtt_logger.go create mode 100644 plugins/inputs/mqtt_consumer/sample.conf create mode 100644 plugins/inputs/mqtt_consumer/testdata/mosquitto.conf create mode 100644 plugins/inputs/mqtt_consumer/topic_parser.go create mode 100644 plugins/inputs/multifile/README.md create mode 100644 plugins/inputs/multifile/multifile.go create mode 100644 plugins/inputs/multifile/multifile_test.go create mode 100644 plugins/inputs/multifile/sample.conf create mode 100644 plugins/inputs/multifile/testdata/bool.txt create mode 100644 plugins/inputs/multifile/testdata/float.txt create mode 100644 plugins/inputs/multifile/testdata/int.txt create mode 100644 plugins/inputs/multifile/testdata/string.txt create mode 100644 plugins/inputs/multifile/testdata/tag.txt create mode 100644 plugins/inputs/mysql/README.md create mode 100644 plugins/inputs/mysql/dev/docker-compose.yml create mode 100644 plugins/inputs/mysql/dev/telegraf.conf create mode 100644 plugins/inputs/mysql/mysql.go create mode 100644 plugins/inputs/mysql/mysql_test.go create mode 100644 plugins/inputs/mysql/sample.conf create mode 100644 plugins/inputs/mysql/v1/mysql.go create mode 100644 plugins/inputs/mysql/v2/convert.go create mode 100644 plugins/inputs/mysql/v2/convert_test.go create mode 100644 plugins/inputs/nats/README.md create mode 100644 plugins/inputs/nats/nats.go create mode 100644 plugins/inputs/nats/nats_freebsd.go create mode 100644 plugins/inputs/nats/nats_test.go create mode 100644 plugins/inputs/nats/sample.conf create mode 100644 plugins/inputs/nats_consumer/README.md create mode 100644 plugins/inputs/nats_consumer/nats_consumer.go create mode 100644 plugins/inputs/nats_consumer/nats_consumer_test.go create mode 100644 plugins/inputs/nats_consumer/sample.conf create mode 100644 plugins/inputs/neoom_beaam/README.md create mode 100644 plugins/inputs/neoom_beaam/neoom_beaam.go create mode 100644 plugins/inputs/neoom_beaam/neoom_beaam_test.go create mode 100644 plugins/inputs/neoom_beaam/sample.conf create mode 100644 plugins/inputs/neoom_beaam/sample.conf.in create mode 100644 plugins/inputs/neoom_beaam/testcases/small/configuration.json create mode 100644 plugins/inputs/neoom_beaam/testcases/small/expected.out create mode 100644 plugins/inputs/neoom_beaam/testcases/small/state.json create mode 100644 plugins/inputs/neoom_beaam/testcases/small/telegraf.conf create mode 100644 plugins/inputs/neoom_beaam/testcases/small/thing_22222222-bbbb-2222-bbbb-222222222222.json create mode 100644 plugins/inputs/neoom_beaam/testcases/small/thing_33333333-cccc-3333-cccc-333333333333.json create mode 100644 plugins/inputs/neoom_beaam/testcases/small/thing_44444444-dddd-4444-dddd-444444444444.json create mode 100644 plugins/inputs/neoom_beaam/testcases/small/thing_55555555-eeee-5555-eeee-555555555555.json create mode 100644 plugins/inputs/neoom_beaam/types.go create mode 100644 plugins/inputs/neptune_apex/README.md create mode 100644 plugins/inputs/neptune_apex/neptune_apex.go create mode 100644 plugins/inputs/neptune_apex/neptune_apex_test.go create mode 100644 plugins/inputs/neptune_apex/sample.conf create mode 100644 plugins/inputs/net/README.md create mode 100644 plugins/inputs/net/net.go create mode 100644 plugins/inputs/net/net_test.go create mode 100644 plugins/inputs/net/sample.conf create mode 100644 plugins/inputs/net/testdata/general/sys/class/net/eth0/speed create mode 100644 plugins/inputs/net/testdata/general/sys/class/net/eth1/speed create mode 100644 plugins/inputs/net_response/README.md create mode 100644 plugins/inputs/net_response/net_response.go create mode 100644 plugins/inputs/net_response/net_response_test.go create mode 100644 plugins/inputs/net_response/sample.conf create mode 100644 plugins/inputs/netflow/README.md create mode 100644 plugins/inputs/netflow/ipv4_options.csv create mode 100644 plugins/inputs/netflow/layer4_protocol_numbers.csv create mode 100644 plugins/inputs/netflow/mappings.go create mode 100644 plugins/inputs/netflow/mappings_ipfix_pen/ntop-35632.csv create mode 100644 plugins/inputs/netflow/netflow.go create mode 100644 plugins/inputs/netflow/netflow_decoder.go create mode 100644 plugins/inputs/netflow/netflow_test.go create mode 100644 plugins/inputs/netflow/netflow_v5.go create mode 100644 plugins/inputs/netflow/sample.conf create mode 100644 plugins/inputs/netflow/sflow_v5.go create mode 100644 plugins/inputs/netflow/testcases/ipfix_example/expected.out create mode 100644 plugins/inputs/netflow/testcases/ipfix_example/ipfix_0.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_example/ipfix_1.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_example/ipfix_2.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_example/ipfix_3.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_example/ipfix_4.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_example/ipfix_5.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_example/ipfix_6.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_example/telegraf.conf create mode 100644 plugins/inputs/netflow/testcases/ipfix_options/expected.out create mode 100644 plugins/inputs/netflow/testcases/ipfix_options/message-001.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_options/message-002.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_options/message-003.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_options/message-004.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_options/message-005.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_options/message-006.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_options/message-007.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_options/message-008.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_options/message-009.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_options/telegraf.conf create mode 100644 plugins/inputs/netflow/testcases/ipfix_pen_35632/expected.out create mode 100644 plugins/inputs/netflow/testcases/ipfix_pen_35632/message-1.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_pen_35632/message-2.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_pen_35632/message-3.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_pen_35632/message-4.bin create mode 100644 plugins/inputs/netflow/testcases/ipfix_pen_35632/telegraf.conf create mode 100644 plugins/inputs/netflow/testcases/issue_13305/expected.out create mode 100644 plugins/inputs/netflow/testcases/issue_13305/message-1.bin create mode 100644 plugins/inputs/netflow/testcases/issue_13305/message-2.bin create mode 100644 plugins/inputs/netflow/testcases/issue_13305/message-3.bin create mode 100644 plugins/inputs/netflow/testcases/issue_13305/message-4.bin create mode 100644 plugins/inputs/netflow/testcases/issue_13305/telegraf.conf create mode 100644 plugins/inputs/netflow/testcases/issue_14370/expected.out create mode 100644 plugins/inputs/netflow/testcases/issue_14370/message.bin create mode 100644 plugins/inputs/netflow/testcases/issue_14370/telegraf.conf create mode 100644 plugins/inputs/netflow/testcases/netflow_mapping.csv create mode 100644 plugins/inputs/netflow/testcases/netflow_v5_example/expected.out create mode 100644 plugins/inputs/netflow/testcases/netflow_v5_example/netflow_v5.bin create mode 100644 plugins/inputs/netflow/testcases/netflow_v5_example/telegraf.conf create mode 100644 plugins/inputs/netflow/testcases/netflow_v9_example/expected.out create mode 100644 plugins/inputs/netflow/testcases/netflow_v9_example/netflow_v9.bin create mode 100644 plugins/inputs/netflow/testcases/netflow_v9_example/telegraf.conf create mode 100644 plugins/inputs/netflow/testcases/netflow_v9_options/expected.out create mode 100644 plugins/inputs/netflow/testcases/netflow_v9_options/message.bin create mode 100644 plugins/inputs/netflow/testcases/netflow_v9_options/telegraf.conf create mode 100644 plugins/inputs/netflow/testcases/sflow_issue_15375/expected.out create mode 100644 plugins/inputs/netflow/testcases/sflow_issue_15375/sflow_drop_1036.bin create mode 100644 plugins/inputs/netflow/testcases/sflow_issue_15375/telegraf.conf create mode 100644 plugins/inputs/netflow/testcases/sflow_issue_15918/expected.out create mode 100644 plugins/inputs/netflow/testcases/sflow_issue_15918/message.bin create mode 100644 plugins/inputs/netflow/testcases/sflow_issue_15918/telegraf.conf create mode 100644 plugins/inputs/netflow/testcases/sflow_v5_example/expected.out create mode 100644 plugins/inputs/netflow/testcases/sflow_v5_example/sflow_v5.bin create mode 100644 plugins/inputs/netflow/testcases/sflow_v5_example/telegraf.conf create mode 100644 plugins/inputs/netflow/type_conversion.go create mode 100644 plugins/inputs/netflow/type_conversion_test.go create mode 100644 plugins/inputs/netstat/README.md create mode 100644 plugins/inputs/netstat/netstat.go create mode 100644 plugins/inputs/netstat/netstat_test.go create mode 100644 plugins/inputs/netstat/sample.conf create mode 100644 plugins/inputs/nfsclient/README.md create mode 100644 plugins/inputs/nfsclient/nfsclient.go create mode 100644 plugins/inputs/nfsclient/nfsclient_test.go create mode 100644 plugins/inputs/nfsclient/sample.conf create mode 100644 plugins/inputs/nfsclient/testdata/mountstats create mode 100644 plugins/inputs/nginx/README.md create mode 100644 plugins/inputs/nginx/nginx.go create mode 100644 plugins/inputs/nginx/nginx_test.go create mode 100644 plugins/inputs/nginx/sample.conf create mode 100644 plugins/inputs/nginx_plus/README.md create mode 100644 plugins/inputs/nginx_plus/nginx_plus.go create mode 100644 plugins/inputs/nginx_plus/nginx_plus_test.go create mode 100644 plugins/inputs/nginx_plus/sample.conf create mode 100644 plugins/inputs/nginx_plus_api/README.md create mode 100644 plugins/inputs/nginx_plus_api/nginx_plus_api.go create mode 100644 plugins/inputs/nginx_plus_api/nginx_plus_api_metrics.go create mode 100644 plugins/inputs/nginx_plus_api/nginx_plus_api_metrics_test.go create mode 100644 plugins/inputs/nginx_plus_api/nginx_plus_api_types.go create mode 100644 plugins/inputs/nginx_plus_api/sample.conf create mode 100644 plugins/inputs/nginx_sts/README.md create mode 100644 plugins/inputs/nginx_sts/nginx_sts.go create mode 100644 plugins/inputs/nginx_sts/nginx_sts_test.go create mode 100644 plugins/inputs/nginx_sts/sample.conf create mode 100644 plugins/inputs/nginx_upstream_check/README.md create mode 100644 plugins/inputs/nginx_upstream_check/nginx_upstream_check.go create mode 100644 plugins/inputs/nginx_upstream_check/nginx_upstream_check_test.go create mode 100644 plugins/inputs/nginx_upstream_check/sample.conf create mode 100644 plugins/inputs/nginx_vts/README.md create mode 100644 plugins/inputs/nginx_vts/nginx_vts.go create mode 100644 plugins/inputs/nginx_vts/nginx_vts_test.go create mode 100644 plugins/inputs/nginx_vts/sample.conf create mode 100644 plugins/inputs/nomad/README.md create mode 100644 plugins/inputs/nomad/nomad.go create mode 100644 plugins/inputs/nomad/nomad_metrics.go create mode 100644 plugins/inputs/nomad/nomad_test.go create mode 100644 plugins/inputs/nomad/sample.conf create mode 100644 plugins/inputs/nomad/testdata/response_key_metrics.json create mode 100644 plugins/inputs/nsd/README.md create mode 100644 plugins/inputs/nsd/nsd.go create mode 100644 plugins/inputs/nsd/nsd_test.go create mode 100644 plugins/inputs/nsd/sample.conf create mode 100644 plugins/inputs/nsdp/README.md create mode 100644 plugins/inputs/nsdp/nsdp.go create mode 100644 plugins/inputs/nsdp/nsdp_test.go create mode 100644 plugins/inputs/nsdp/sample.conf create mode 100644 plugins/inputs/nsdp/testdata/conf/nsdp.conf create mode 100644 plugins/inputs/nsdp/testdata/metrics/nsdp_device_port.txt create mode 100644 plugins/inputs/nsq/README.md create mode 100644 plugins/inputs/nsq/nsq.go create mode 100644 plugins/inputs/nsq/nsq_test.go create mode 100644 plugins/inputs/nsq/sample.conf create mode 100644 plugins/inputs/nsq_consumer/README.md create mode 100644 plugins/inputs/nsq_consumer/nsq_consumer.go create mode 100644 plugins/inputs/nsq_consumer/nsq_consumer_test.go create mode 100644 plugins/inputs/nsq_consumer/sample.conf create mode 100644 plugins/inputs/nstat/README.md create mode 100644 plugins/inputs/nstat/nstat.go create mode 100644 plugins/inputs/nstat/nstat_test.go create mode 100644 plugins/inputs/nstat/sample.conf create mode 100644 plugins/inputs/ntpq/README.md create mode 100644 plugins/inputs/ntpq/ntpq.go create mode 100644 plugins/inputs/ntpq/ntpq_test.go create mode 100644 plugins/inputs/ntpq/sample.conf create mode 100644 plugins/inputs/ntpq/testcases/bad_float_parse/expected.err create mode 100644 plugins/inputs/ntpq/testcases/bad_float_parse/expected.out create mode 100644 plugins/inputs/ntpq/testcases/bad_float_parse/input.txt create mode 100644 plugins/inputs/ntpq/testcases/bad_float_parse/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/bad_header/expected.out create mode 100644 plugins/inputs/ntpq/testcases/bad_header/input.txt create mode 100644 plugins/inputs/ntpq/testcases/bad_header/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/bad_int_parse/expected.err create mode 100644 plugins/inputs/ntpq/testcases/bad_int_parse/expected.out create mode 100644 plugins/inputs/ntpq/testcases/bad_int_parse/input.txt create mode 100644 plugins/inputs/ntpq/testcases/bad_int_parse/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/bad_when/expected.err create mode 100644 plugins/inputs/ntpq/testcases/bad_when/expected.out create mode 100644 plugins/inputs/ntpq/testcases/bad_when/input.txt create mode 100644 plugins/inputs/ntpq/testcases/bad_when/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/days/expected.out create mode 100644 plugins/inputs/ntpq/testcases/days/input.txt create mode 100644 plugins/inputs/ntpq/testcases/days/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/failed/expected.err create mode 100644 plugins/inputs/ntpq/testcases/failed/input.err create mode 100644 plugins/inputs/ntpq/testcases/failed/input.txt create mode 100644 plugins/inputs/ntpq/testcases/failed/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/hours/expected.out create mode 100644 plugins/inputs/ntpq/testcases/hours/input.txt create mode 100644 plugins/inputs/ntpq/testcases/hours/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/issue_2386/expected.out create mode 100644 plugins/inputs/ntpq/testcases/issue_2386/input.txt create mode 100644 plugins/inputs/ntpq/testcases/issue_2386/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/long_poll/expected.out create mode 100644 plugins/inputs/ntpq/testcases/long_poll/input.txt create mode 100644 plugins/inputs/ntpq/testcases/long_poll/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/minutes/expected.out create mode 100644 plugins/inputs/ntpq/testcases/minutes/input.txt create mode 100644 plugins/inputs/ntpq/testcases/minutes/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/missing_delay_column/expected.out create mode 100644 plugins/inputs/ntpq/testcases/missing_delay_column/input.txt create mode 100644 plugins/inputs/ntpq/testcases/missing_delay_column/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/multi/expected.out create mode 100644 plugins/inputs/ntpq/testcases/multi/input.txt create mode 100644 plugins/inputs/ntpq/testcases/multi/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/no_ref_id/expected.out create mode 100644 plugins/inputs/ntpq/testcases/no_ref_id/input.txt create mode 100644 plugins/inputs/ntpq/testcases/no_ref_id/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/pool_when_minus/expected.out create mode 100644 plugins/inputs/ntpq/testcases/pool_when_minus/input.txt create mode 100644 plugins/inputs/ntpq/testcases/pool_when_minus/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/servers/expected.out create mode 100644 plugins/inputs/ntpq/testcases/servers/input_serverA.txt create mode 100644 plugins/inputs/ntpq/testcases/servers/input_serverB.txt create mode 100644 plugins/inputs/ntpq/testcases/servers/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/servers_one_fail/expected.err create mode 100644 plugins/inputs/ntpq/testcases/servers_one_fail/expected.out create mode 100644 plugins/inputs/ntpq/testcases/servers_one_fail/input_serverA.txt create mode 100644 plugins/inputs/ntpq/testcases/servers_one_fail/input_serverB.txt create mode 100644 plugins/inputs/ntpq/testcases/servers_one_fail/input_serverC.err create mode 100644 plugins/inputs/ntpq/testcases/servers_one_fail/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/single/expected.out create mode 100644 plugins/inputs/ntpq/testcases/single/input.txt create mode 100644 plugins/inputs/ntpq/testcases/single/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/single_reach_count/expected.out create mode 100644 plugins/inputs/ntpq/testcases/single_reach_count/input.txt create mode 100644 plugins/inputs/ntpq/testcases/single_reach_count/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/single_reach_decimal/expected.out create mode 100644 plugins/inputs/ntpq/testcases/single_reach_decimal/input.txt create mode 100644 plugins/inputs/ntpq/testcases/single_reach_decimal/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/single_reach_octal/expected.out create mode 100644 plugins/inputs/ntpq/testcases/single_reach_octal/input.txt create mode 100644 plugins/inputs/ntpq/testcases/single_reach_octal/telegraf.conf create mode 100644 plugins/inputs/ntpq/testcases/single_reach_ratio/expected.out create mode 100644 plugins/inputs/ntpq/testcases/single_reach_ratio/input.txt create mode 100644 plugins/inputs/ntpq/testcases/single_reach_ratio/telegraf.conf create mode 100644 plugins/inputs/nvidia_smi/README.md create mode 100644 plugins/inputs/nvidia_smi/common/setters.go create mode 100644 plugins/inputs/nvidia_smi/nvidia_smi.go create mode 100644 plugins/inputs/nvidia_smi/nvidia_smi_test.go create mode 100644 plugins/inputs/nvidia_smi/sample.conf create mode 100644 plugins/inputs/nvidia_smi/schema_v11/parser.go create mode 100644 plugins/inputs/nvidia_smi/schema_v11/types.go create mode 100644 plugins/inputs/nvidia_smi/schema_v12/parser.go create mode 100644 plugins/inputs/nvidia_smi/schema_v12/types.go create mode 100644 plugins/inputs/nvidia_smi/testdata/a100-sxm4-v12.xml create mode 100644 plugins/inputs/nvidia_smi/testdata/a10g.xml create mode 100644 plugins/inputs/nvidia_smi/testdata/gtx-1070-ti.xml create mode 100644 plugins/inputs/nvidia_smi/testdata/gtx-1660-ti.xml create mode 100644 plugins/inputs/nvidia_smi/testdata/quadro-p2000-v12.xml create mode 100644 plugins/inputs/nvidia_smi/testdata/quadro-p400.xml create mode 100644 plugins/inputs/nvidia_smi/testdata/rtx-3060-v12.xml create mode 100644 plugins/inputs/nvidia_smi/testdata/rtx-3080-v12.xml create mode 100644 plugins/inputs/nvidia_smi/testdata/rtx-3090-v12.xml create mode 100644 plugins/inputs/nvidia_smi/testdata/tesla-t4.xml create mode 100644 plugins/inputs/opcua/README.md create mode 100644 plugins/inputs/opcua/opcua.go create mode 100644 plugins/inputs/opcua/opcua_test.go create mode 100644 plugins/inputs/opcua/read_client.go create mode 100644 plugins/inputs/opcua/sample.conf create mode 100644 plugins/inputs/opcua_listener/README.md create mode 100644 plugins/inputs/opcua_listener/opcua_listener.go create mode 100644 plugins/inputs/opcua_listener/opcua_listener_test.go create mode 100644 plugins/inputs/opcua_listener/sample.conf create mode 100644 plugins/inputs/opcua_listener/subscribe_client.go create mode 100644 plugins/inputs/openldap/README.md create mode 100644 plugins/inputs/openldap/openldap.go create mode 100644 plugins/inputs/openldap/openldap_test.go create mode 100644 plugins/inputs/openldap/sample.conf create mode 100644 plugins/inputs/openntpd/README.md create mode 100644 plugins/inputs/openntpd/openntpd.go create mode 100644 plugins/inputs/openntpd/openntpd_test.go create mode 100644 plugins/inputs/openntpd/sample.conf create mode 100644 plugins/inputs/opensearch_query/README.md create mode 100644 plugins/inputs/opensearch_query/aggregation.bucket.go create mode 100644 plugins/inputs/opensearch_query/aggregation.go create mode 100644 plugins/inputs/opensearch_query/aggregation.metric.go create mode 100644 plugins/inputs/opensearch_query/aggregation.response.go create mode 100644 plugins/inputs/opensearch_query/opensearch_query.go create mode 100644 plugins/inputs/opensearch_query/opensearch_query_test.go create mode 100644 plugins/inputs/opensearch_query/query.go create mode 100644 plugins/inputs/opensearch_query/sample.conf create mode 100644 plugins/inputs/opensearch_query/testdata/nginx_logs create mode 100644 plugins/inputs/opensmtpd/README.md create mode 100644 plugins/inputs/opensmtpd/opensmtpd.go create mode 100644 plugins/inputs/opensmtpd/opensmtpd_test.go create mode 100644 plugins/inputs/opensmtpd/sample.conf create mode 100644 plugins/inputs/openstack/README.md create mode 100644 plugins/inputs/openstack/openstack.go create mode 100644 plugins/inputs/openstack/sample.conf create mode 100644 plugins/inputs/opentelemetry/README.md create mode 100644 plugins/inputs/opentelemetry/grpc_service_profile.go create mode 100644 plugins/inputs/opentelemetry/grpc_services.go create mode 100644 plugins/inputs/opentelemetry/logger.go create mode 100644 plugins/inputs/opentelemetry/opentelemetry.go create mode 100644 plugins/inputs/opentelemetry/opentelemetry_test.go create mode 100644 plugins/inputs/opentelemetry/sample.conf create mode 100644 plugins/inputs/opentelemetry/testcases/profiles/expected.out create mode 100644 plugins/inputs/opentelemetry/testcases/profiles/profiles.json create mode 100644 plugins/inputs/opentelemetry/testcases/profiles/telegraf.conf create mode 100644 plugins/inputs/opentelemetry/writer.go create mode 100644 plugins/inputs/openweathermap/README.md create mode 100644 plugins/inputs/openweathermap/openweathermap.go create mode 100644 plugins/inputs/openweathermap/openweathermap_test.go create mode 100644 plugins/inputs/openweathermap/sample.conf create mode 100644 plugins/inputs/openweathermap/testcases/forecast/expected.out create mode 100644 plugins/inputs/openweathermap/testcases/forecast/response_forecast.json create mode 100644 plugins/inputs/openweathermap/testcases/forecast/response_group.json create mode 100644 plugins/inputs/openweathermap/testcases/forecast/telegraf.conf create mode 100644 plugins/inputs/openweathermap/testcases/rain_batch/expected.out create mode 100644 plugins/inputs/openweathermap/testcases/rain_batch/response_group.json create mode 100644 plugins/inputs/openweathermap/testcases/rain_batch/telegraf.conf create mode 100644 plugins/inputs/openweathermap/testcases/snow_batch/expected.out create mode 100644 plugins/inputs/openweathermap/testcases/snow_batch/response_group.json create mode 100644 plugins/inputs/openweathermap/testcases/snow_batch/telegraf.conf create mode 100644 plugins/inputs/openweathermap/testcases/weather/expected.out create mode 100644 plugins/inputs/openweathermap/testcases/weather/response_group.json create mode 100644 plugins/inputs/openweathermap/testcases/weather/telegraf.conf create mode 100644 plugins/inputs/openweathermap/testcases/weather_batch/expected.out create mode 100644 plugins/inputs/openweathermap/testcases/weather_batch/response_forecast.json create mode 100644 plugins/inputs/openweathermap/testcases/weather_batch/response_group.json create mode 100644 plugins/inputs/openweathermap/testcases/weather_batch/telegraf.conf create mode 100644 plugins/inputs/openweathermap/testcases/weather_single/expected.out create mode 100644 plugins/inputs/openweathermap/testcases/weather_single/response_forecast.json create mode 100644 plugins/inputs/openweathermap/testcases/weather_single/response_weather_2643743.json create mode 100644 plugins/inputs/openweathermap/testcases/weather_single/response_weather_524901.json create mode 100644 plugins/inputs/openweathermap/testcases/weather_single/response_weather_703448.json create mode 100644 plugins/inputs/openweathermap/testcases/weather_single/telegraf.conf create mode 100644 plugins/inputs/openweathermap/types.go create mode 100644 plugins/inputs/p4runtime/README.md create mode 100644 plugins/inputs/p4runtime/p4runtime.go create mode 100644 plugins/inputs/p4runtime/p4runtime_fake_client_test.go create mode 100644 plugins/inputs/p4runtime/p4runtime_test.go create mode 100644 plugins/inputs/p4runtime/sample.conf create mode 100644 plugins/inputs/passenger/README.md create mode 100644 plugins/inputs/passenger/passenger.go create mode 100644 plugins/inputs/passenger/passenger_test.go create mode 100644 plugins/inputs/passenger/sample.conf create mode 100644 plugins/inputs/pf/README.md create mode 100644 plugins/inputs/pf/pf.go create mode 100644 plugins/inputs/pf/pf_test.go create mode 100644 plugins/inputs/pf/sample.conf create mode 100644 plugins/inputs/pgbouncer/README.md create mode 100644 plugins/inputs/pgbouncer/pgbouncer.go create mode 100644 plugins/inputs/pgbouncer/pgbouncer_test.go create mode 100644 plugins/inputs/pgbouncer/sample.conf create mode 100644 plugins/inputs/phpfpm/README.md create mode 100644 plugins/inputs/phpfpm/child.go create mode 100644 plugins/inputs/phpfpm/fcgi.go create mode 100644 plugins/inputs/phpfpm/fcgi_client.go create mode 100644 plugins/inputs/phpfpm/fcgi_test.go create mode 100644 plugins/inputs/phpfpm/phpfpm.go create mode 100644 plugins/inputs/phpfpm/phpfpm_test.go create mode 100644 plugins/inputs/phpfpm/sample.conf create mode 100644 plugins/inputs/phpfpm/testdata/expected.out create mode 100644 plugins/inputs/phpfpm/testdata/phpfpm.json create mode 100644 plugins/inputs/ping/README.md create mode 100644 plugins/inputs/ping/ping.go create mode 100644 plugins/inputs/ping/ping_notwindows.go create mode 100644 plugins/inputs/ping/ping_test.go create mode 100644 plugins/inputs/ping/ping_windows.go create mode 100644 plugins/inputs/ping/ping_windows_test.go create mode 100644 plugins/inputs/ping/sample.conf create mode 100644 plugins/inputs/postfix/README.md create mode 100644 plugins/inputs/postfix/postfix.go create mode 100644 plugins/inputs/postfix/postfix_test.go create mode 100644 plugins/inputs/postfix/postfix_windows.go create mode 100644 plugins/inputs/postfix/sample.conf create mode 100644 plugins/inputs/postfix/stat_ctim.go create mode 100644 plugins/inputs/postfix/stat_ctimespec.go create mode 100644 plugins/inputs/postgresql/README.md create mode 100644 plugins/inputs/postgresql/postgresql.go create mode 100644 plugins/inputs/postgresql/postgresql_test.go create mode 100644 plugins/inputs/postgresql/sample.conf create mode 100644 plugins/inputs/postgresql_extensible/README.md create mode 100644 plugins/inputs/postgresql_extensible/postgresql_extensible.go create mode 100644 plugins/inputs/postgresql_extensible/postgresql_extensible_test.go create mode 100644 plugins/inputs/postgresql_extensible/sample.conf create mode 100644 plugins/inputs/postgresql_extensible/testdata/test.sql create mode 100644 plugins/inputs/powerdns/README.md create mode 100644 plugins/inputs/powerdns/powerdns.go create mode 100644 plugins/inputs/powerdns/powerdns_linux_test.go create mode 100644 plugins/inputs/powerdns/powerdns_test.go create mode 100644 plugins/inputs/powerdns/sample.conf create mode 100644 plugins/inputs/powerdns_recursor/README.md create mode 100644 plugins/inputs/powerdns_recursor/powerdns_recursor.go create mode 100644 plugins/inputs/powerdns_recursor/powerdns_recursor_test.go create mode 100644 plugins/inputs/powerdns_recursor/protocol_commons.go create mode 100644 plugins/inputs/powerdns_recursor/protocol_v1.go create mode 100644 plugins/inputs/powerdns_recursor/protocol_v2.go create mode 100644 plugins/inputs/powerdns_recursor/protocol_v3.go create mode 100644 plugins/inputs/powerdns_recursor/sample.conf create mode 100644 plugins/inputs/processes/README.md create mode 100644 plugins/inputs/processes/processes.go create mode 100644 plugins/inputs/processes/processes_notwindows.go create mode 100644 plugins/inputs/processes/processes_test.go create mode 100644 plugins/inputs/processes/processes_windows.go create mode 100644 plugins/inputs/processes/sample.conf create mode 100644 plugins/inputs/procstat/README.md create mode 100644 plugins/inputs/procstat/filter.go create mode 100644 plugins/inputs/procstat/native_finder.go create mode 100644 plugins/inputs/procstat/native_finder_test.go create mode 100644 plugins/inputs/procstat/os_linux.go create mode 100644 plugins/inputs/procstat/os_others.go create mode 100644 plugins/inputs/procstat/os_windows.go create mode 100644 plugins/inputs/procstat/pgrep.go create mode 100644 plugins/inputs/procstat/process.go create mode 100644 plugins/inputs/procstat/procstat.go create mode 100644 plugins/inputs/procstat/procstat_test.go create mode 100644 plugins/inputs/procstat/sample.conf create mode 100644 plugins/inputs/procstat/service_finders.go create mode 100644 plugins/inputs/prometheus/README.md create mode 100644 plugins/inputs/prometheus/consul.go create mode 100644 plugins/inputs/prometheus/kubernetes.go create mode 100644 plugins/inputs/prometheus/kubernetes_test.go create mode 100644 plugins/inputs/prometheus/prometheus.go create mode 100644 plugins/inputs/prometheus/prometheus_test.go create mode 100644 plugins/inputs/prometheus/sample.conf create mode 100644 plugins/inputs/prometheus/testdata/openmetric-proto.bin create mode 100644 plugins/inputs/proxmox/README.md create mode 100644 plugins/inputs/proxmox/proxmox.go create mode 100644 plugins/inputs/proxmox/proxmox_test.go create mode 100644 plugins/inputs/proxmox/sample.conf create mode 100644 plugins/inputs/proxmox/structs.go create mode 100644 plugins/inputs/puppetagent/README.md create mode 100644 plugins/inputs/puppetagent/last_run_summary.yaml create mode 100644 plugins/inputs/puppetagent/puppetagent.go create mode 100644 plugins/inputs/puppetagent/puppetagent_test.go create mode 100644 plugins/inputs/puppetagent/sample.conf create mode 100644 plugins/inputs/rabbitmq/README.md create mode 100644 plugins/inputs/rabbitmq/rabbitmq.go create mode 100644 plugins/inputs/rabbitmq/rabbitmq_test.go create mode 100644 plugins/inputs/rabbitmq/sample.conf create mode 100644 plugins/inputs/rabbitmq/testdata/set1/exchanges.json create mode 100644 plugins/inputs/rabbitmq/testdata/set1/federation-links.json create mode 100644 plugins/inputs/rabbitmq/testdata/set1/memory.json create mode 100644 plugins/inputs/rabbitmq/testdata/set1/nodes.json create mode 100644 plugins/inputs/rabbitmq/testdata/set1/overview.json create mode 100644 plugins/inputs/rabbitmq/testdata/set1/queues.json create mode 100644 plugins/inputs/rabbitmq/testdata/set2/exchanges.json create mode 100644 plugins/inputs/rabbitmq/testdata/set2/federation-links.json create mode 100644 plugins/inputs/rabbitmq/testdata/set2/memory.json create mode 100644 plugins/inputs/rabbitmq/testdata/set2/nodes.json create mode 100644 plugins/inputs/rabbitmq/testdata/set2/overview.json create mode 100644 plugins/inputs/rabbitmq/testdata/set2/queues.json create mode 100644 plugins/inputs/radius/README.md create mode 100644 plugins/inputs/radius/radius.go create mode 100644 plugins/inputs/radius/radius_test.go create mode 100644 plugins/inputs/radius/sample.conf create mode 100644 plugins/inputs/radius/testdata/invalidSourceIP/clients.conf create mode 100644 plugins/inputs/radius/testdata/invalidSourceIP/mods-config/files/authorize create mode 100644 plugins/inputs/radius/testdata/invalidSourceIP/radiusd.conf create mode 100644 plugins/inputs/radius/testdata/raddb/clients.conf create mode 100644 plugins/inputs/radius/testdata/raddb/mods-config/files/authorize create mode 100644 plugins/inputs/radius/testdata/raddb/radiusd.conf create mode 100644 plugins/inputs/raindrops/README.md create mode 100644 plugins/inputs/raindrops/raindrops.go create mode 100644 plugins/inputs/raindrops/raindrops_test.go create mode 100644 plugins/inputs/raindrops/sample.conf create mode 100644 plugins/inputs/ras/README.md create mode 100644 plugins/inputs/ras/ras.go create mode 100644 plugins/inputs/ras/ras_notlinux.go create mode 100644 plugins/inputs/ras/ras_test.go create mode 100644 plugins/inputs/ras/sample.conf create mode 100644 plugins/inputs/ravendb/README.md create mode 100644 plugins/inputs/ravendb/ravendb.go create mode 100644 plugins/inputs/ravendb/ravendb_dto.go create mode 100644 plugins/inputs/ravendb/ravendb_test.go create mode 100644 plugins/inputs/ravendb/sample.conf create mode 100644 plugins/inputs/ravendb/testdata/collections_full.json create mode 100644 plugins/inputs/ravendb/testdata/collections_min.json create mode 100644 plugins/inputs/ravendb/testdata/databases_full.json create mode 100644 plugins/inputs/ravendb/testdata/databases_min.json create mode 100644 plugins/inputs/ravendb/testdata/indexes_full.json create mode 100644 plugins/inputs/ravendb/testdata/indexes_min.json create mode 100644 plugins/inputs/ravendb/testdata/server_full.json create mode 100644 plugins/inputs/ravendb/testdata/server_min.json create mode 100644 plugins/inputs/redfish/README.md create mode 100644 plugins/inputs/redfish/redfish.go create mode 100644 plugins/inputs/redfish/redfish_test.go create mode 100644 plugins/inputs/redfish/sample.conf create mode 100644 plugins/inputs/redfish/testdata/dell_chassis.json create mode 100644 plugins/inputs/redfish/testdata/dell_chassisinvalid.json create mode 100644 plugins/inputs/redfish/testdata/dell_power.json create mode 100644 plugins/inputs/redfish/testdata/dell_powerinvalid.json create mode 100644 plugins/inputs/redfish/testdata/dell_systems.json create mode 100644 plugins/inputs/redfish/testdata/dell_systemsinvalid.json create mode 100644 plugins/inputs/redfish/testdata/dell_thermal.json create mode 100644 plugins/inputs/redfish/testdata/dell_thermalinvalid.json create mode 100644 plugins/inputs/redfish/testdata/hp_chassis.json create mode 100644 plugins/inputs/redfish/testdata/hp_power.json create mode 100644 plugins/inputs/redfish/testdata/hp_powerinvalid.json create mode 100644 plugins/inputs/redfish/testdata/hp_systems.json create mode 100644 plugins/inputs/redfish/testdata/hp_systemsinvalid.json create mode 100644 plugins/inputs/redfish/testdata/hp_thermal.json create mode 100644 plugins/inputs/redfish/testdata/hp_thermal_ilo4.json create mode 100644 plugins/inputs/redfish/testdata/hp_thermalinvalid.json create mode 100644 plugins/inputs/redis/README.md create mode 100644 plugins/inputs/redis/redis.go create mode 100644 plugins/inputs/redis/redis_test.go create mode 100644 plugins/inputs/redis/sample.conf create mode 100644 plugins/inputs/redis_sentinel/README.md create mode 100644 plugins/inputs/redis_sentinel/redis_sentinel.go create mode 100644 plugins/inputs/redis_sentinel/redis_sentinel_test.go create mode 100644 plugins/inputs/redis_sentinel/redis_sentinel_types.go create mode 100644 plugins/inputs/redis_sentinel/sample.conf create mode 100644 plugins/inputs/redis_sentinel/testdata/sentinel.info.response create mode 100644 plugins/inputs/registry.go create mode 100644 plugins/inputs/rethinkdb/README.md create mode 100644 plugins/inputs/rethinkdb/rethinkdb.go create mode 100644 plugins/inputs/rethinkdb/rethinkdb_data.go create mode 100644 plugins/inputs/rethinkdb/rethinkdb_data_test.go create mode 100644 plugins/inputs/rethinkdb/rethinkdb_server.go create mode 100644 plugins/inputs/rethinkdb/rethinkdb_server_test.go create mode 100644 plugins/inputs/rethinkdb/rethinkdb_test.go create mode 100644 plugins/inputs/rethinkdb/sample.conf create mode 100644 plugins/inputs/riak/README.md create mode 100644 plugins/inputs/riak/riak.go create mode 100644 plugins/inputs/riak/riak_test.go create mode 100644 plugins/inputs/riak/sample.conf create mode 100644 plugins/inputs/riemann_listener/README.md create mode 100644 plugins/inputs/riemann_listener/riemann_listener.go create mode 100644 plugins/inputs/riemann_listener/riemann_listener_test.go create mode 100644 plugins/inputs/riemann_listener/sample.conf create mode 100644 plugins/inputs/s7comm/README.md create mode 100644 plugins/inputs/s7comm/s7comm.go create mode 100644 plugins/inputs/s7comm/s7comm_test.go create mode 100644 plugins/inputs/s7comm/sample.conf create mode 100644 plugins/inputs/s7comm/type_conversions.go create mode 100644 plugins/inputs/salesforce/README.md create mode 100644 plugins/inputs/salesforce/salesforce.go create mode 100644 plugins/inputs/salesforce/salesforce_test.go create mode 100644 plugins/inputs/salesforce/sample.conf create mode 100644 plugins/inputs/sensors/README.md create mode 100644 plugins/inputs/sensors/sample.conf create mode 100644 plugins/inputs/sensors/sensors.go create mode 100644 plugins/inputs/sensors/sensors_notlinux.go create mode 100644 plugins/inputs/sensors/sensors_test.go create mode 100644 plugins/inputs/sflow/README.md create mode 100644 plugins/inputs/sflow/binaryio/minreader.go create mode 100644 plugins/inputs/sflow/binaryio/minreader_test.go create mode 100644 plugins/inputs/sflow/decoder_test.go create mode 100644 plugins/inputs/sflow/metricencoder.go create mode 100644 plugins/inputs/sflow/packetdecoder.go create mode 100644 plugins/inputs/sflow/packetdecoder_test.go create mode 100644 plugins/inputs/sflow/sample.conf create mode 100644 plugins/inputs/sflow/sflow.go create mode 100644 plugins/inputs/sflow/sflow_test.go create mode 100644 plugins/inputs/sflow/types.go create mode 100644 plugins/inputs/sflow/types_test.go create mode 100644 plugins/inputs/slab/README.md create mode 100644 plugins/inputs/slab/sample.conf create mode 100644 plugins/inputs/slab/slab.go create mode 100644 plugins/inputs/slab/slab_notlinux.go create mode 100644 plugins/inputs/slab/slab_test.go create mode 100644 plugins/inputs/slab/testdata/slabinfo create mode 100644 plugins/inputs/slurm/README.md create mode 100644 plugins/inputs/slurm/sample.conf create mode 100644 plugins/inputs/slurm/sample.conf.in create mode 100644 plugins/inputs/slurm/slurm.go create mode 100644 plugins/inputs/slurm/slurm_test.go create mode 100644 plugins/inputs/slurm/testcases/gather/expected.out create mode 100644 plugins/inputs/slurm/testcases/gather/responses/diag.json create mode 100644 plugins/inputs/slurm/testcases/gather/responses/jobs.json create mode 100644 plugins/inputs/slurm/testcases/gather/responses/nodes.json create mode 100644 plugins/inputs/slurm/testcases/gather/responses/partitions.json create mode 100644 plugins/inputs/slurm/testcases/gather/responses/reservations.json create mode 100644 plugins/inputs/slurm/testcases/gather/telegraf.conf create mode 100644 plugins/inputs/slurm/testcases/panic/responses/diag.json create mode 100644 plugins/inputs/slurm/testcases/panic/responses/jobs.json create mode 100644 plugins/inputs/slurm/testcases/panic/responses/nodes.json create mode 100644 plugins/inputs/slurm/testcases/panic/responses/partitions.json create mode 100644 plugins/inputs/slurm/testcases/panic/responses/reservations.json create mode 100644 plugins/inputs/slurm/testcases/panic/telegraf.conf create mode 100644 plugins/inputs/smart/README.md create mode 100644 plugins/inputs/smart/sample.conf create mode 100644 plugins/inputs/smart/smart.go create mode 100644 plugins/inputs/smart/smart_test.go create mode 100644 plugins/inputs/smartctl/README.md create mode 100644 plugins/inputs/smartctl/sample.conf create mode 100644 plugins/inputs/smartctl/smartctl.go create mode 100644 plugins/inputs/smartctl/smartctl_device.go create mode 100644 plugins/inputs/smartctl/smartctl_json.go create mode 100644 plugins/inputs/smartctl/smartctl_scan.go create mode 100644 plugins/inputs/smartctl/smartctl_test.go create mode 100644 plugins/inputs/smartctl/testcases_device/megaraid/device create mode 100644 plugins/inputs/smartctl/testcases_device/megaraid/deviceType create mode 100644 plugins/inputs/smartctl/testcases_device/megaraid/expected.out create mode 100644 plugins/inputs/smartctl/testcases_device/megaraid/response.json create mode 100644 plugins/inputs/smartctl/testcases_device/nvme/device create mode 100644 plugins/inputs/smartctl/testcases_device/nvme/deviceType create mode 100644 plugins/inputs/smartctl/testcases_device/nvme/expected.out create mode 100644 plugins/inputs/smartctl/testcases_device/nvme/response.json create mode 100644 plugins/inputs/smartctl/testcases_device/scsi/device create mode 100644 plugins/inputs/smartctl/testcases_device/scsi/deviceType create mode 100644 plugins/inputs/smartctl/testcases_device/scsi/expected.out create mode 100644 plugins/inputs/smartctl/testcases_device/scsi/response.json create mode 100644 plugins/inputs/smartctl/testcases_device/scsi_extended/device create mode 100644 plugins/inputs/smartctl/testcases_device/scsi_extended/deviceType create mode 100644 plugins/inputs/smartctl/testcases_device/scsi_extended/expected.out create mode 100644 plugins/inputs/smartctl/testcases_device/scsi_extended/response.json create mode 100644 plugins/inputs/smartctl/testcases_device/usb/device create mode 100644 plugins/inputs/smartctl/testcases_device/usb/deviceType create mode 100644 plugins/inputs/smartctl/testcases_device/usb/expected.out create mode 100644 plugins/inputs/smartctl/testcases_device/usb/response.json create mode 100644 plugins/inputs/smartctl/testcases_scan/all/expected.out create mode 100644 plugins/inputs/smartctl/testcases_scan/all/response.json create mode 100644 plugins/inputs/smartctl/testcases_scan/all/telegraf.toml create mode 100644 plugins/inputs/smartctl/testcases_scan/exclude/expected.out create mode 100644 plugins/inputs/smartctl/testcases_scan/exclude/response.json create mode 100644 plugins/inputs/smartctl/testcases_scan/exclude/telegraf.toml create mode 100644 plugins/inputs/smartctl/testcases_scan/include/expected.out create mode 100644 plugins/inputs/smartctl/testcases_scan/include/response.json create mode 100644 plugins/inputs/smartctl/testcases_scan/include/telegraf.toml create mode 100644 plugins/inputs/smartctl/testcases_scan/megaraid/expected.out create mode 100644 plugins/inputs/smartctl/testcases_scan/megaraid/response.json create mode 100644 plugins/inputs/smartctl/testcases_scan/megaraid/telegraf.toml create mode 100644 plugins/inputs/snmp/README.md create mode 100644 plugins/inputs/snmp/sample.conf create mode 100644 plugins/inputs/snmp/snmp.go create mode 100644 plugins/inputs/snmp/snmp_test.go create mode 100644 plugins/inputs/snmp_trap/README.md create mode 100644 plugins/inputs/snmp_trap/gosmi.go create mode 100644 plugins/inputs/snmp_trap/logger.go create mode 100644 plugins/inputs/snmp_trap/netsnmp.go create mode 100644 plugins/inputs/snmp_trap/sample.conf create mode 100644 plugins/inputs/snmp_trap/snmp_trap.go create mode 100644 plugins/inputs/snmp_trap/snmp_trap_test.go create mode 100644 plugins/inputs/socket_listener/README.md create mode 100644 plugins/inputs/socket_listener/sample.conf create mode 100644 plugins/inputs/socket_listener/sample.conf.in create mode 100644 plugins/inputs/socket_listener/socket_listener.go create mode 100644 plugins/inputs/socket_listener/socket_listener_test.go create mode 100644 plugins/inputs/socket_listener/testcases/invalid_line_format/expected.err create mode 100644 plugins/inputs/socket_listener/testcases/invalid_line_format/expected.out create mode 100644 plugins/inputs/socket_listener/testcases/invalid_line_format/sequence.json create mode 100644 plugins/inputs/socket_listener/testcases/invalid_line_format/telegraf.conf create mode 100644 plugins/inputs/socket_listener/testcases/powerdns/dnsmessage.proto create mode 100644 plugins/inputs/socket_listener/testcases/powerdns/expected.out create mode 100644 plugins/inputs/socket_listener/testcases/powerdns/powerdns_message.bin create mode 100644 plugins/inputs/socket_listener/testcases/powerdns/sequence.json create mode 100644 plugins/inputs/socket_listener/testcases/powerdns/telegraf.conf create mode 100644 plugins/inputs/socket_listener/testcases/splitting_delimiter/expected.out create mode 100644 plugins/inputs/socket_listener/testcases/splitting_delimiter/message.bin create mode 100644 plugins/inputs/socket_listener/testcases/splitting_delimiter/sequence.json create mode 100644 plugins/inputs/socket_listener/testcases/splitting_delimiter/telegraf.conf create mode 100644 plugins/inputs/socket_listener/testcases/splitting_fixed_length/expected.out create mode 100644 plugins/inputs/socket_listener/testcases/splitting_fixed_length/sequence.json create mode 100644 plugins/inputs/socket_listener/testcases/splitting_fixed_length/telegraf.conf create mode 100644 plugins/inputs/socket_listener/testcases/splitting_newline/expected.out create mode 100644 plugins/inputs/socket_listener/testcases/splitting_newline/sequence.json create mode 100644 plugins/inputs/socket_listener/testcases/splitting_newline/telegraf.conf create mode 100644 plugins/inputs/socket_listener/testcases/splitting_null/expected.out create mode 100644 plugins/inputs/socket_listener/testcases/splitting_null/message.bin create mode 100644 plugins/inputs/socket_listener/testcases/splitting_null/sequence.json create mode 100644 plugins/inputs/socket_listener/testcases/splitting_null/telegraf.conf create mode 100644 plugins/inputs/socket_listener/testcases/splitting_variable_length/expected.out create mode 100644 plugins/inputs/socket_listener/testcases/splitting_variable_length/message_1.bin create mode 100644 plugins/inputs/socket_listener/testcases/splitting_variable_length/message_2.bin create mode 100644 plugins/inputs/socket_listener/testcases/splitting_variable_length/message_3.bin create mode 100644 plugins/inputs/socket_listener/testcases/splitting_variable_length/message_4.bin create mode 100644 plugins/inputs/socket_listener/testcases/splitting_variable_length/message_5.bin create mode 100644 plugins/inputs/socket_listener/testcases/splitting_variable_length/sequence.json create mode 100644 plugins/inputs/socket_listener/testcases/splitting_variable_length/telegraf.conf create mode 100644 plugins/inputs/socket_listener/testcases/timeout/sequence.json create mode 100644 plugins/inputs/socket_listener/testcases/timeout/telegraf.conf create mode 100644 plugins/inputs/socketstat/README.md create mode 100644 plugins/inputs/socketstat/sample.conf create mode 100644 plugins/inputs/socketstat/socketstat.go create mode 100644 plugins/inputs/socketstat/socketstat_test.go create mode 100644 plugins/inputs/socketstat/socketstat_windows.go create mode 100644 plugins/inputs/socketstat/testdata/tcp_no_sockets.txt create mode 100644 plugins/inputs/socketstat/testdata/tcp_traffic.txt create mode 100644 plugins/inputs/socketstat/testdata/udp_no_sockets.txt create mode 100644 plugins/inputs/socketstat/testdata/udp_traffic.txt create mode 100644 plugins/inputs/solr/README.md create mode 100644 plugins/inputs/solr/api.go create mode 100644 plugins/inputs/solr/sample.conf create mode 100644 plugins/inputs/solr/solr.go create mode 100644 plugins/inputs/solr/solr_test.go create mode 100644 plugins/inputs/solr/testcases/integration-v6.result create mode 100644 plugins/inputs/solr/testcases/integration-v7.result create mode 100644 plugins/inputs/solr/testcases/integration-v8.result create mode 100644 plugins/inputs/solr/testcases/integration-v9.result create mode 100644 plugins/inputs/solr/testcases/no_core_data/admin/cores.json create mode 100644 plugins/inputs/solr/testcases/no_core_data/core1/admin/mbeans.json create mode 100644 plugins/inputs/solr/testcases/no_core_data/expected.out create mode 100644 plugins/inputs/solr/testcases/no_core_data/main/admin/mbeans.json create mode 100644 plugins/inputs/solr/testcases/no_core_data/telegraf.conf create mode 100644 plugins/inputs/solr/testcases/v3.5/admin/cores.json create mode 100644 plugins/inputs/solr/testcases/v3.5/core1/admin/mbeans.json create mode 100644 plugins/inputs/solr/testcases/v3.5/expected.out create mode 100644 plugins/inputs/solr/testcases/v3.5/main/admin/mbeans.json create mode 100644 plugins/inputs/solr/testcases/v3.5/telegraf.conf create mode 100644 plugins/inputs/solr/testcases/v4.3/admin/cores.json create mode 100644 plugins/inputs/solr/testcases/v4.3/core1/admin/mbeans.json create mode 100644 plugins/inputs/solr/testcases/v4.3/expected.out create mode 100644 plugins/inputs/solr/testcases/v4.3/main/admin/mbeans.json create mode 100644 plugins/inputs/solr/testcases/v4.3/telegraf.conf create mode 100644 plugins/inputs/solr/testcases/v7/admin/cores.json create mode 100644 plugins/inputs/solr/testcases/v7/expected.out create mode 100644 plugins/inputs/solr/testcases/v7/main/admin/mbeans.json create mode 100644 plugins/inputs/solr/testcases/v7/telegraf.conf create mode 100644 plugins/inputs/solr/types.go create mode 100644 plugins/inputs/solr/util.go create mode 100644 plugins/inputs/sql/README.md create mode 100644 plugins/inputs/sql/drivers.go create mode 100644 plugins/inputs/sql/drivers_sqlite.go create mode 100644 plugins/inputs/sql/sample.conf create mode 100644 plugins/inputs/sql/sql.go create mode 100644 plugins/inputs/sql/sql_test.go create mode 100644 plugins/inputs/sql/testdata/clickhouse/expected.sql create mode 100644 plugins/inputs/sql/testdata/mariadb/expected.sql create mode 100644 plugins/inputs/sql/testdata/postgres/expected.sql create mode 100644 plugins/inputs/sqlserver/README.md create mode 100644 plugins/inputs/sqlserver/azurearcsqlmiqueries.go create mode 100644 plugins/inputs/sqlserver/azurearcsqlmiqueries_test.go create mode 100644 plugins/inputs/sqlserver/azuresqldbqueries.go create mode 100644 plugins/inputs/sqlserver/azuresqldbqueries_test.go create mode 100644 plugins/inputs/sqlserver/azuresqlmanagedqueries.go create mode 100644 plugins/inputs/sqlserver/azuresqlmanagedqueries_test.go create mode 100644 plugins/inputs/sqlserver/azuresqlpoolqueries.go create mode 100644 plugins/inputs/sqlserver/azuresqlpoolqueries_test.go create mode 100644 plugins/inputs/sqlserver/azuretoken.go create mode 100644 plugins/inputs/sqlserver/connectionstring.go create mode 100644 plugins/inputs/sqlserver/sample.conf create mode 100644 plugins/inputs/sqlserver/sqlqueriesV1.go create mode 100644 plugins/inputs/sqlserver/sqlqueriesV2.go create mode 100644 plugins/inputs/sqlserver/sqlserver.go create mode 100644 plugins/inputs/sqlserver/sqlserver_test.go create mode 100644 plugins/inputs/sqlserver/sqlserverqueries.go create mode 100644 plugins/inputs/stackdriver/README.md create mode 100644 plugins/inputs/stackdriver/sample.conf create mode 100644 plugins/inputs/stackdriver/stackdriver.go create mode 100644 plugins/inputs/stackdriver/stackdriver_test.go create mode 100644 plugins/inputs/statsd/README.md create mode 100644 plugins/inputs/statsd/datadog.go create mode 100644 plugins/inputs/statsd/datadog_test.go create mode 100644 plugins/inputs/statsd/running_stats.go create mode 100644 plugins/inputs/statsd/running_stats_test.go create mode 100644 plugins/inputs/statsd/sample.conf create mode 100644 plugins/inputs/statsd/statsd.go create mode 100644 plugins/inputs/statsd/statsd_test.go create mode 100644 plugins/inputs/supervisor/README.md create mode 100644 plugins/inputs/supervisor/sample.conf create mode 100644 plugins/inputs/supervisor/supervisor.go create mode 100644 plugins/inputs/supervisor/supervisor_test.go create mode 100644 plugins/inputs/supervisor/testdata/supervisord.conf create mode 100644 plugins/inputs/suricata/README.md create mode 100644 plugins/inputs/suricata/sample.conf create mode 100644 plugins/inputs/suricata/suricata.go create mode 100644 plugins/inputs/suricata/suricata_test.go create mode 100644 plugins/inputs/suricata/testdata/test1.json create mode 100644 plugins/inputs/suricata/testdata/test2.json create mode 100644 plugins/inputs/suricata/testdata/test3.json create mode 100644 plugins/inputs/suricata/testdata/v2/alert.json create mode 100644 plugins/inputs/suricata/testdata/v2/dns.json create mode 100644 plugins/inputs/suricata/testdata/v2/drop.json create mode 100644 plugins/inputs/suricata/testdata/v2/flow.json create mode 100644 plugins/inputs/suricata/testdata/v2/http.json create mode 100644 plugins/inputs/suricata/testdata/v2/status.json create mode 100644 plugins/inputs/swap/README.md create mode 100644 plugins/inputs/swap/sample.conf create mode 100644 plugins/inputs/swap/swap.go create mode 100644 plugins/inputs/swap/swap_test.go create mode 100644 plugins/inputs/synproxy/README.md create mode 100644 plugins/inputs/synproxy/sample.conf create mode 100644 plugins/inputs/synproxy/synproxy.go create mode 100644 plugins/inputs/synproxy/synproxy_notlinux.go create mode 100644 plugins/inputs/synproxy/synproxy_test.go create mode 100644 plugins/inputs/syslog/README.md create mode 100644 plugins/inputs/syslog/sample.conf create mode 100644 plugins/inputs/syslog/sample.conf.in create mode 100644 plugins/inputs/syslog/syslog.go create mode 100644 plugins/inputs/syslog/syslog_test.go create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_tcp_1st_avg_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_tcp_1st_avg_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_tcp_1st_avg_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_tcp_1st_min_ok_2nd_min_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_tcp_1st_min_ok_2nd_min_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_tcp_1st_min_ok_2nd_min_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_tcptls_1st_avg_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_tcptls_1st_avg_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_tcptls_1st_avg_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_tcptls_1st_min_ok_2nd_min_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_tcptls_1st_min_ok_2nd_min_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_tcptls_1st_min_ok_2nd_min_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_unix/expected.out create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_unix/input.txt create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_unix/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_unixtls/expected.out create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_unixtls/input.txt create mode 100644 plugins/inputs/syslog/testcases/non_transparent_best_effort_unixtls/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_tcp_1st_avg_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_tcp_1st_avg_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_tcp_1st_avg_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_tcp_1st_min_ok_2nd_min_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_tcp_1st_min_ok_2nd_min_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_tcp_1st_min_ok_2nd_min_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_tcptls_1st_avg_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_tcptls_1st_avg_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_tcptls_1st_avg_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_tcptls_1st_min_ok_2nd_min_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_tcptls_1st_min_ok_2nd_min_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_tcptls_1st_min_ok_2nd_min_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_unix/expected.out create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_unix/input.txt create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_unix/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_unixtls/expected.out create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_unixtls/input.txt create mode 100644 plugins/inputs/syslog/testcases/non_transparent_strict_unixtls/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_avg_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_avg_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_avg_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_max_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_max_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_max_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_min_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_min_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_min_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_min_ok_2nd_min_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_min_ok_2nd_min_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_min_ok_2nd_min_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_newline_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_newline_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_newline_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_underflow_malfunction/expected.err create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_underflow_malfunction/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_underflow_malfunction/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_underflow_malfunction/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_underflow_nok/expected.err create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_underflow_nok/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_underflow_nok/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_underflow_nok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_utf8_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_utf8_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcp_1st_utf8_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcptls/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcptls/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_tcptls/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_unix/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_unix/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_unix/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_unixtls/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_unixtls/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_best_effort_unixtls/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_avg_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_avg_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_avg_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_max_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_max_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_max_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_min_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_min_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_min_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_min_ok_2nd_min_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_min_ok_2nd_min_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_min_ok_2nd_min_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_newline_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_newline_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_newline_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_underflow_malfunction/expected.err create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_underflow_malfunction/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_underflow_malfunction/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_underflow_nok/expected.err create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_underflow_nok/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_underflow_nok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_utf8_ok/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_utf8_ok/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcp_1st_utf8_ok/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcptls/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcptls/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_tcptls/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_unix/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_unix/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_unix/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_unixtls/expected.out create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_unixtls/input.txt create mode 100644 plugins/inputs/syslog/testcases/octet_counting_strict_unixtls/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc3164_best_effort_udp/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc3164_best_effort_udp/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc3164_best_effort_udp/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc3164_strict_udp/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc3164_strict_udp/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc3164_strict_udp/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_toolong_appname/expected.err create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_toolong_appname/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_toolong_appname/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_toolong_appname/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_average/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_average/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_average/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_max/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_max/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_max/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_min_incomplete/expected.err create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_min_incomplete/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_min_incomplete/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_min_incomplete/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_one_per_packet/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_one_per_packet/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_one_per_packet/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_trim_message/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_trim_message/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_best_effort_udp_trim_message/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_long_appname/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc5424_long_appname/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_long_appname/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_toolong_appname/expected.err create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_toolong_appname/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_toolong_appname/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_average/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_average/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_average/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_max/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_max/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_max/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_min_incomplete/expected.err create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_min_incomplete/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_min_incomplete/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_one_per_packet/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_one_per_packet/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_one_per_packet/telegraf.conf create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_trim_message/expected.out create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_trim_message/input.txt create mode 100644 plugins/inputs/syslog/testcases/rfc5424_strict_udp_trim_message/telegraf.conf create mode 100644 plugins/inputs/sysstat/README.md create mode 100644 plugins/inputs/sysstat/sample.conf create mode 100644 plugins/inputs/sysstat/sysstat.go create mode 100644 plugins/inputs/sysstat/sysstat_interval_test.go create mode 100644 plugins/inputs/sysstat/sysstat_notlinux.go create mode 100644 plugins/inputs/sysstat/sysstat_test.go create mode 100644 plugins/inputs/system/README.md create mode 100644 plugins/inputs/system/sample.conf create mode 100644 plugins/inputs/system/system.go create mode 100644 plugins/inputs/system/system_test.go create mode 100644 plugins/inputs/systemd_units/README.md create mode 100644 plugins/inputs/systemd_units/sample.conf create mode 100644 plugins/inputs/systemd_units/systemd_units.go create mode 100644 plugins/inputs/systemd_units/systemd_units_notlinux.go create mode 100644 plugins/inputs/systemd_units/systemd_units_test.go create mode 100644 plugins/inputs/tacacs/README.md create mode 100644 plugins/inputs/tacacs/sample.conf create mode 100644 plugins/inputs/tacacs/tacacs.go create mode 100644 plugins/inputs/tacacs/tacacs_test.go create mode 100644 plugins/inputs/tail/README.md create mode 100644 plugins/inputs/tail/multiline.go create mode 100644 plugins/inputs/tail/multiline_test.go create mode 100644 plugins/inputs/tail/sample.conf create mode 100644 plugins/inputs/tail/tail.go create mode 100644 plugins/inputs/tail/tail_solaris.go create mode 100644 plugins/inputs/tail/tail_test.go create mode 100644 plugins/inputs/tail/testdata/cpu-utf-16be.influx create mode 100644 plugins/inputs/tail/testdata/cpu-utf-16le.influx create mode 100644 plugins/inputs/tail/testdata/cpu-utf-8.influx create mode 100644 plugins/inputs/tail/testdata/multiline_quoted_backticks.csv create mode 100644 plugins/inputs/tail/testdata/multiline_quoted_double.csv create mode 100644 plugins/inputs/tail/testdata/multiline_quoted_messed_up.csv create mode 100644 plugins/inputs/tail/testdata/multiline_quoted_missing_close.csv create mode 100644 plugins/inputs/tail/testdata/multiline_quoted_single.csv create mode 100644 plugins/inputs/tail/testdata/test-patterns create mode 100644 plugins/inputs/tail/testdata/test_multiline.log create mode 100644 plugins/inputs/teamspeak/README.md create mode 100644 plugins/inputs/teamspeak/sample.conf create mode 100644 plugins/inputs/teamspeak/teamspeak.go create mode 100644 plugins/inputs/teamspeak/teamspeak_test.go create mode 100644 plugins/inputs/temp/README.md create mode 100644 plugins/inputs/temp/sample.conf create mode 100644 plugins/inputs/temp/temp.go create mode 100644 plugins/inputs/temp/temp_linux.go create mode 100644 plugins/inputs/temp/temp_notlinux.go create mode 100644 plugins/inputs/temp/temp_test.go create mode 100644 plugins/inputs/temp/testcases/general/expected_v1.out create mode 100644 plugins/inputs/temp/testcases/general/expected_v2.out create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/name create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/temp1_alarm create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/temp1_crit create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/temp1_input create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/temp1_label create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/temp1_max create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/temp1_min create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/temp2_input create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/temp2_label create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/temp2_max create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/temp2_min create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/temp3_input create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/temp3_label create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/temp3_max create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon0/temp3_min create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon1/name create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon1/temp1_input create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon1/temp1_label create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon1/temp3_input create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon1/temp3_label create mode 100644 plugins/inputs/temp/testcases/general/sys/class/hwmon/hwmon1/uevent create mode 100644 plugins/inputs/temp/testcases/general/telegraf.conf create mode 100644 plugins/inputs/temp/testcases/with_device_tag/expected_v1.out create mode 100644 plugins/inputs/temp/testcases/with_device_tag/expected_v2.out create mode 120000 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/device create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/name create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/temp1_alarm create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/temp1_crit create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/temp1_input create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/temp1_label create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/temp1_max create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/temp1_min create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/temp2_input create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/temp2_label create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/temp2_max create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/temp2_min create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/temp3_input create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/temp3_label create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/temp3_max create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/temp3_min create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon0/uevent create mode 120000 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/device create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/name create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/temp1_alarm create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/temp1_crit create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/temp1_input create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/temp1_label create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/temp1_max create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/temp1_min create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/temp2_input create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/temp2_label create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/temp2_max create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/temp2_min create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/temp3_input create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/temp3_label create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/temp3_max create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/temp3_min create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon1/uevent create mode 120000 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon2/device create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon2/name create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon2/temp1_input create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon2/temp1_label create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon2/temp3_input create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon2/temp3_label create mode 100644 plugins/inputs/temp/testcases/with_device_tag/sys/class/hwmon/hwmon2/uevent create mode 100644 plugins/inputs/temp/testcases/with_device_tag/telegraf.conf create mode 100644 plugins/inputs/temp/testcases/with_name/expected_v1.out create mode 100644 plugins/inputs/temp/testcases/with_name/expected_v2.out create mode 120000 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/device create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/name create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/temp1_alarm create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/temp1_crit create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/temp1_input create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/temp1_label create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/temp1_max create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/temp1_min create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/temp2_input create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/temp2_label create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/temp2_max create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/temp2_min create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/temp3_input create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/temp3_label create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/temp3_max create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/temp3_min create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon0/uevent create mode 120000 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/device create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/name create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/temp1_alarm create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/temp1_crit create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/temp1_input create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/temp1_label create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/temp1_max create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/temp1_min create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/temp2_input create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/temp2_label create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/temp2_max create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/temp2_min create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/temp3_input create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/temp3_label create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/temp3_max create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/temp3_min create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon1/uevent create mode 120000 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon2/device create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon2/name create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon2/temp1_input create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon2/temp1_label create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon2/temp3_input create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon2/temp3_label create mode 100644 plugins/inputs/temp/testcases/with_name/sys/class/hwmon/hwmon2/uevent create mode 100644 plugins/inputs/temp/testcases/with_name/telegraf.conf create mode 100644 plugins/inputs/tengine/README.md create mode 100644 plugins/inputs/tengine/sample.conf create mode 100644 plugins/inputs/tengine/tengine.go create mode 100644 plugins/inputs/tengine/tengine_test.go create mode 100644 plugins/inputs/tomcat/README.md create mode 100644 plugins/inputs/tomcat/sample.conf create mode 100644 plugins/inputs/tomcat/tomcat.go create mode 100644 plugins/inputs/tomcat/tomcat_test.go create mode 100644 plugins/inputs/trig/README.md create mode 100644 plugins/inputs/trig/sample.conf create mode 100644 plugins/inputs/trig/trig.go create mode 100644 plugins/inputs/trig/trig_test.go create mode 100644 plugins/inputs/twemproxy/README.md create mode 100644 plugins/inputs/twemproxy/sample.conf create mode 100644 plugins/inputs/twemproxy/twemproxy.go create mode 100644 plugins/inputs/twemproxy/twemproxy_test.go create mode 100644 plugins/inputs/unbound/README.md create mode 100644 plugins/inputs/unbound/sample.conf create mode 100644 plugins/inputs/unbound/unbound.go create mode 100644 plugins/inputs/unbound/unbound_test.go create mode 100644 plugins/inputs/upsd/README.md create mode 100644 plugins/inputs/upsd/sample.conf create mode 100644 plugins/inputs/upsd/testcases/CyberPowerSystems_CP900EPFCLCD/expected.out create mode 100644 plugins/inputs/upsd/testcases/CyberPowerSystems_CP900EPFCLCD/telegraf.conf create mode 100644 plugins/inputs/upsd/testcases/CyberPowerSystems_CP900EPFCLCD/types.dev create mode 100644 plugins/inputs/upsd/testcases/CyberPowerSystems_CP900EPFCLCD/variables.dev create mode 100644 plugins/inputs/upsd/testcases/CyberPowerSystems_CP900EPFCLCD_additional/expected.out create mode 100644 plugins/inputs/upsd/testcases/CyberPowerSystems_CP900EPFCLCD_additional/telegraf.conf create mode 100644 plugins/inputs/upsd/testcases/CyberPowerSystems_CP900EPFCLCD_additional/types.dev create mode 100644 plugins/inputs/upsd/testcases/CyberPowerSystems_CP900EPFCLCD_additional/variables.dev create mode 100644 plugins/inputs/upsd/testcases/CyberPowerSystems_CP900EPFCLCD_full/expected.out create mode 100644 plugins/inputs/upsd/testcases/CyberPowerSystems_CP900EPFCLCD_full/telegraf.conf create mode 100644 plugins/inputs/upsd/testcases/CyberPowerSystems_CP900EPFCLCD_full/types.dev create mode 100644 plugins/inputs/upsd/testcases/CyberPowerSystems_CP900EPFCLCD_full/variables.dev create mode 100644 plugins/inputs/upsd/testcases/fake/expected.out create mode 100644 plugins/inputs/upsd/testcases/fake/telegraf.conf create mode 100644 plugins/inputs/upsd/testcases/fake/types.dev create mode 100644 plugins/inputs/upsd/testcases/fake/variables.dev create mode 100644 plugins/inputs/upsd/testcases/fake_force_float/expected.out create mode 100644 plugins/inputs/upsd/testcases/fake_force_float/telegraf.conf create mode 100644 plugins/inputs/upsd/testcases/fake_force_float/types.dev create mode 100644 plugins/inputs/upsd/testcases/fake_force_float/variables.dev create mode 100644 plugins/inputs/upsd/testcases/fake_force_float_with_string/expected.out create mode 100644 plugins/inputs/upsd/testcases/fake_force_float_with_string/telegraf.conf create mode 100644 plugins/inputs/upsd/testcases/fake_force_float_with_string/types.dev create mode 100644 plugins/inputs/upsd/testcases/fake_force_float_with_string/variables.dev create mode 100644 plugins/inputs/upsd/upsd.go create mode 100644 plugins/inputs/upsd/upsd_test.go create mode 100644 plugins/inputs/uwsgi/README.md create mode 100644 plugins/inputs/uwsgi/sample.conf create mode 100644 plugins/inputs/uwsgi/uwsgi.go create mode 100644 plugins/inputs/uwsgi/uwsgi_test.go create mode 100644 plugins/inputs/varnish/README.md create mode 100644 plugins/inputs/varnish/sample.conf create mode 100644 plugins/inputs/varnish/test_data/varnish4_4.json create mode 100644 plugins/inputs/varnish/test_data/varnish6.2.1_reload.json create mode 100644 plugins/inputs/varnish/test_data/varnish6.6.json create mode 100644 plugins/inputs/varnish/test_data/varnish_types.json create mode 100644 plugins/inputs/varnish/test_data/varnish_v1_reload.txt create mode 100644 plugins/inputs/varnish/test_data/varnishadm-200.json create mode 100644 plugins/inputs/varnish/test_data/varnishadm-reload.json create mode 100644 plugins/inputs/varnish/varnish.go create mode 100644 plugins/inputs/varnish/varnish_test.go create mode 100644 plugins/inputs/varnish/varnish_windows.go create mode 100644 plugins/inputs/vault/README.md create mode 100644 plugins/inputs/vault/sample.conf create mode 100644 plugins/inputs/vault/testdata/response_key_metrics.json create mode 100644 plugins/inputs/vault/vault.go create mode 100644 plugins/inputs/vault/vault_metrics.go create mode 100644 plugins/inputs/vault/vault_test.go create mode 100644 plugins/inputs/vsphere/METRICS.md create mode 100644 plugins/inputs/vsphere/README.md create mode 100644 plugins/inputs/vsphere/client.go create mode 100644 plugins/inputs/vsphere/endpoint.go create mode 100644 plugins/inputs/vsphere/finder.go create mode 100644 plugins/inputs/vsphere/sample.conf create mode 100644 plugins/inputs/vsphere/selfhealth.go create mode 100644 plugins/inputs/vsphere/throttled_exec.go create mode 100644 plugins/inputs/vsphere/tscache.go create mode 100644 plugins/inputs/vsphere/vsan.go create mode 100644 plugins/inputs/vsphere/vsphere.go create mode 100644 plugins/inputs/vsphere/vsphere_test.go create mode 100644 plugins/inputs/webhooks/README.md create mode 100644 plugins/inputs/webhooks/artifactory/README.md create mode 100644 plugins/inputs/webhooks/artifactory/artifactory_webhook.go create mode 100644 plugins/inputs/webhooks/artifactory/artifactory_webhook_mock_json_test.go create mode 100644 plugins/inputs/webhooks/artifactory/artifactory_webhook_models.go create mode 100644 plugins/inputs/webhooks/artifactory/artifactory_webhook_test.go create mode 100644 plugins/inputs/webhooks/filestack/README.md create mode 100644 plugins/inputs/webhooks/filestack/filestack_webhooks.go create mode 100644 plugins/inputs/webhooks/filestack/filestack_webhooks_events.go create mode 100644 plugins/inputs/webhooks/filestack/filestack_webhooks_test.go create mode 100644 plugins/inputs/webhooks/filestack/testdata/dialog_open.json create mode 100644 plugins/inputs/webhooks/filestack/testdata/upload.json create mode 100644 plugins/inputs/webhooks/filestack/testdata/video_conversion.json create mode 100644 plugins/inputs/webhooks/github/README.md create mode 100644 plugins/inputs/webhooks/github/github_webhooks.go create mode 100644 plugins/inputs/webhooks/github/github_webhooks_mock_json_test.go create mode 100644 plugins/inputs/webhooks/github/github_webhooks_models.go create mode 100644 plugins/inputs/webhooks/github/github_webhooks_test.go create mode 100644 plugins/inputs/webhooks/mandrill/README.md create mode 100644 plugins/inputs/webhooks/mandrill/mandrill_webhooks.go create mode 100644 plugins/inputs/webhooks/mandrill/mandrill_webhooks_events.go create mode 100644 plugins/inputs/webhooks/mandrill/mandrill_webhooks_test.go create mode 100644 plugins/inputs/webhooks/mandrill/testdata/hard_bounce_event.json create mode 100644 plugins/inputs/webhooks/mandrill/testdata/send_event.json create mode 100644 plugins/inputs/webhooks/papertrail/README.md create mode 100644 plugins/inputs/webhooks/papertrail/papertrail_test.go create mode 100644 plugins/inputs/webhooks/papertrail/papertrail_webhooks.go create mode 100644 plugins/inputs/webhooks/papertrail/papertrail_webhooks_models.go create mode 100644 plugins/inputs/webhooks/particle/README.md create mode 100644 plugins/inputs/webhooks/particle/particle_webhooks.go create mode 100644 plugins/inputs/webhooks/particle/particle_webhooks_test.go create mode 100644 plugins/inputs/webhooks/rollbar/README.md create mode 100644 plugins/inputs/webhooks/rollbar/rollbar_webhooks.go create mode 100644 plugins/inputs/webhooks/rollbar/rollbar_webhooks_events.go create mode 100644 plugins/inputs/webhooks/rollbar/rollbar_webhooks_events_json_test.go create mode 100644 plugins/inputs/webhooks/rollbar/rollbar_webhooks_test.go create mode 100644 plugins/inputs/webhooks/sample.conf create mode 100644 plugins/inputs/webhooks/webhooks.go create mode 100644 plugins/inputs/webhooks/webhooks_test.go create mode 100644 plugins/inputs/win_eventlog/README.md create mode 100644 plugins/inputs/win_eventlog/event.go create mode 100644 plugins/inputs/win_eventlog/sample.conf create mode 100644 plugins/inputs/win_eventlog/syscall_windows.go create mode 100644 plugins/inputs/win_eventlog/util.go create mode 100644 plugins/inputs/win_eventlog/util_test.go create mode 100644 plugins/inputs/win_eventlog/win_eventlog.go create mode 100644 plugins/inputs/win_eventlog/win_eventlog_notwindows.go create mode 100644 plugins/inputs/win_eventlog/win_eventlog_test.go create mode 100644 plugins/inputs/win_eventlog/zsyscall_windows.go create mode 100644 plugins/inputs/win_perf_counters/README.md create mode 100644 plugins/inputs/win_perf_counters/kernel32.go create mode 100644 plugins/inputs/win_perf_counters/pdh.go create mode 100644 plugins/inputs/win_perf_counters/pdh_386.go create mode 100644 plugins/inputs/win_perf_counters/pdh_amd64.go create mode 100644 plugins/inputs/win_perf_counters/pdh_arm64.go create mode 100644 plugins/inputs/win_perf_counters/performance_query.go create mode 100644 plugins/inputs/win_perf_counters/sample.conf create mode 100644 plugins/inputs/win_perf_counters/win_perf_counters.go create mode 100644 plugins/inputs/win_perf_counters/win_perf_counters_integration_test.go create mode 100644 plugins/inputs/win_perf_counters/win_perf_counters_notwindows.go create mode 100644 plugins/inputs/win_perf_counters/win_perf_counters_test.go create mode 100644 plugins/inputs/win_services/README.md create mode 100644 plugins/inputs/win_services/sample.conf create mode 100644 plugins/inputs/win_services/win_services.go create mode 100644 plugins/inputs/win_services/win_services_integration_test.go create mode 100644 plugins/inputs/win_services/win_services_notwindows.go create mode 100644 plugins/inputs/win_services/win_services_test.go create mode 100644 plugins/inputs/win_wmi/README.md create mode 100644 plugins/inputs/win_wmi/method.go create mode 100644 plugins/inputs/win_wmi/query.go create mode 100644 plugins/inputs/win_wmi/sample.conf create mode 100644 plugins/inputs/win_wmi/win_wmi.go create mode 100644 plugins/inputs/win_wmi/win_wmi_notwindows.go create mode 100644 plugins/inputs/win_wmi/win_wmi_test.go create mode 100644 plugins/inputs/wireguard/README.md create mode 100644 plugins/inputs/wireguard/sample.conf create mode 100644 plugins/inputs/wireguard/wireguard.go create mode 100644 plugins/inputs/wireguard/wireguard_test.go create mode 100644 plugins/inputs/wireless/README.md create mode 100644 plugins/inputs/wireless/sample.conf create mode 100644 plugins/inputs/wireless/wireless.go create mode 100644 plugins/inputs/wireless/wireless_linux.go create mode 100644 plugins/inputs/wireless/wireless_notlinux.go create mode 100644 plugins/inputs/wireless/wireless_test.go create mode 100644 plugins/inputs/x509_cert/README.md create mode 100644 plugins/inputs/x509_cert/java_key_store.go create mode 100644 plugins/inputs/x509_cert/java_key_store_test.go create mode 100644 plugins/inputs/x509_cert/sample.conf create mode 100644 plugins/inputs/x509_cert/x509_cert.go create mode 100644 plugins/inputs/x509_cert/x509_cert_test.go create mode 100644 plugins/inputs/xtremio/README.md create mode 100644 plugins/inputs/xtremio/sample.conf create mode 100644 plugins/inputs/xtremio/testdata/sample_bbu_response.json create mode 100644 plugins/inputs/xtremio/testdata/sample_get_bbu_response.json create mode 100644 plugins/inputs/xtremio/xtremio.go create mode 100644 plugins/inputs/xtremio/xtremio_test.go create mode 100644 plugins/inputs/xtremio/xtremio_types.go create mode 100644 plugins/inputs/zfs/README.md create mode 100644 plugins/inputs/zfs/sample.conf create mode 100644 plugins/inputs/zfs/testcases/freebsd/cache/expected.out create mode 100644 plugins/inputs/zfs/testcases/freebsd/cache/sysctl.json create mode 100644 plugins/inputs/zfs/testcases/freebsd/cache/telegraf.conf create mode 100644 plugins/inputs/zfs/testcases/freebsd/cache/zdataset.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/cache/zpool.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/cache_poolmetrics/expected.out create mode 100644 plugins/inputs/zfs/testcases/freebsd/cache_poolmetrics/sysctl.json create mode 100644 plugins/inputs/zfs/testcases/freebsd/cache_poolmetrics/telegraf.conf create mode 100644 plugins/inputs/zfs/testcases/freebsd/cache_poolmetrics/zdataset.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/cache_poolmetrics/zpool.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/dataset/expected.out create mode 100644 plugins/inputs/zfs/testcases/freebsd/dataset/sysctl.json create mode 100644 plugins/inputs/zfs/testcases/freebsd/dataset/telegraf.conf create mode 100644 plugins/inputs/zfs/testcases/freebsd/dataset/zdataset.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/dataset/zpool.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/dataset_datasetmetrics/expected.out create mode 100644 plugins/inputs/zfs/testcases/freebsd/dataset_datasetmetrics/sysctl.json create mode 100644 plugins/inputs/zfs/testcases/freebsd/dataset_datasetmetrics/telegraf.conf create mode 100644 plugins/inputs/zfs/testcases/freebsd/dataset_datasetmetrics/zdataset.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/dataset_datasetmetrics/zpool.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/freebsd14/expected.out create mode 100644 plugins/inputs/zfs/testcases/freebsd/freebsd14/sysctl.json create mode 100644 plugins/inputs/zfs/testcases/freebsd/freebsd14/telegraf.conf create mode 100644 plugins/inputs/zfs/testcases/freebsd/freebsd14/uname.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/freebsd14/zdataset.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/freebsd14/zpool.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/freenas/expected.out create mode 100644 plugins/inputs/zfs/testcases/freebsd/freenas/sysctl.json create mode 100644 plugins/inputs/zfs/testcases/freebsd/freenas/telegraf.conf create mode 100644 plugins/inputs/zfs/testcases/freebsd/freenas/zdataset.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/freenas/zpool.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/freenas_zfetchstats/expected.out create mode 100644 plugins/inputs/zfs/testcases/freebsd/freenas_zfetchstats/sysctl.json create mode 100644 plugins/inputs/zfs/testcases/freebsd/freenas_zfetchstats/telegraf.conf create mode 100644 plugins/inputs/zfs/testcases/freebsd/freenas_zfetchstats/zdataset.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/freenas_zfetchstats/zpool.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/unavailable/expected.out create mode 100644 plugins/inputs/zfs/testcases/freebsd/unavailable/sysctl.json create mode 100644 plugins/inputs/zfs/testcases/freebsd/unavailable/telegraf.conf create mode 100644 plugins/inputs/zfs/testcases/freebsd/unavailable/zdataset.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/unavailable/zpool.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/unavailable_poolmetrics/expected.out create mode 100644 plugins/inputs/zfs/testcases/freebsd/unavailable_poolmetrics/sysctl.json create mode 100644 plugins/inputs/zfs/testcases/freebsd/unavailable_poolmetrics/telegraf.conf create mode 100644 plugins/inputs/zfs/testcases/freebsd/unavailable_poolmetrics/zdataset.txt create mode 100644 plugins/inputs/zfs/testcases/freebsd/unavailable_poolmetrics/zpool.txt create mode 100644 plugins/inputs/zfs/zfs.go create mode 100644 plugins/inputs/zfs/zfs_freebsd.go create mode 100644 plugins/inputs/zfs/zfs_freebsd_test.go create mode 100644 plugins/inputs/zfs/zfs_linux.go create mode 100644 plugins/inputs/zfs/zfs_linux_test.go create mode 100644 plugins/inputs/zfs/zfs_other.go create mode 100644 plugins/inputs/zipkin/README.md create mode 100644 plugins/inputs/zipkin/cmd/stress_test_write/stress_test_write.go create mode 100644 plugins/inputs/zipkin/cmd/thrift_serialize/thrift_serialize.go create mode 100644 plugins/inputs/zipkin/codec/codec.go create mode 100644 plugins/inputs/zipkin/codec/codec_test.go create mode 100644 plugins/inputs/zipkin/codec/jsonV1/jsonV1.go create mode 100644 plugins/inputs/zipkin/codec/jsonV1/jsonV1_test.go create mode 100644 plugins/inputs/zipkin/codec/thrift/gen-go/zipkincore/GoUnusedProtection__.go create mode 100644 plugins/inputs/zipkin/codec/thrift/gen-go/zipkincore/zipkinCore-consts.go create mode 100644 plugins/inputs/zipkin/codec/thrift/gen-go/zipkincore/zipkinCore.go create mode 100644 plugins/inputs/zipkin/codec/thrift/thrift.go create mode 100644 plugins/inputs/zipkin/codec/thrift/thrift_test.go create mode 100644 plugins/inputs/zipkin/convert.go create mode 100644 plugins/inputs/zipkin/convert_test.go create mode 100644 plugins/inputs/zipkin/handler.go create mode 100644 plugins/inputs/zipkin/handler_test.go create mode 100644 plugins/inputs/zipkin/sample.conf create mode 100644 plugins/inputs/zipkin/testdata/cli_microservice.dat create mode 100644 plugins/inputs/zipkin/testdata/distributed_trace_sample.dat create mode 100644 plugins/inputs/zipkin/testdata/json/brave-tracer-example.json create mode 100644 plugins/inputs/zipkin/testdata/json/cli_microservice.json create mode 100644 plugins/inputs/zipkin/testdata/json/distributed_trace_sample.json create mode 100644 plugins/inputs/zipkin/testdata/json/threespans.json create mode 100644 plugins/inputs/zipkin/testdata/threespans.dat create mode 100644 plugins/inputs/zipkin/trace/trace.go create mode 100644 plugins/inputs/zipkin/zipkin.go create mode 100644 plugins/inputs/zipkin/zipkin_test.go create mode 100644 plugins/inputs/zookeeper/README.md create mode 100644 plugins/inputs/zookeeper/dev/docker-compose.yml create mode 100644 plugins/inputs/zookeeper/dev/telegraf.conf create mode 100644 plugins/inputs/zookeeper/sample.conf create mode 100644 plugins/inputs/zookeeper/zookeeper.go create mode 100644 plugins/inputs/zookeeper/zookeeper_test.go create mode 100644 plugins/outputs/all/all.go create mode 100644 plugins/outputs/all/amon.go create mode 100644 plugins/outputs/all/amqp.go create mode 100644 plugins/outputs/all/application_insights.go create mode 100644 plugins/outputs/all/azure_data_explorer.go create mode 100644 plugins/outputs/all/azure_monitor.go create mode 100644 plugins/outputs/all/bigquery.go create mode 100644 plugins/outputs/all/clarify.go create mode 100644 plugins/outputs/all/cloud_pubsub.go create mode 100644 plugins/outputs/all/cloudwatch.go create mode 100644 plugins/outputs/all/cloudwatch_logs.go create mode 100644 plugins/outputs/all/cratedb.go create mode 100644 plugins/outputs/all/datadog.go create mode 100644 plugins/outputs/all/discard.go create mode 100644 plugins/outputs/all/dynatrace.go create mode 100644 plugins/outputs/all/elasticsearch.go create mode 100644 plugins/outputs/all/event_hubs.go create mode 100644 plugins/outputs/all/exec.go create mode 100644 plugins/outputs/all/execd.go create mode 100644 plugins/outputs/all/file.go create mode 100644 plugins/outputs/all/graphite.go create mode 100644 plugins/outputs/all/graylog.go create mode 100644 plugins/outputs/all/groundwork.go create mode 100644 plugins/outputs/all/health.go create mode 100644 plugins/outputs/all/http.go create mode 100644 plugins/outputs/all/influxdb.go create mode 100644 plugins/outputs/all/influxdb_v2.go create mode 100644 plugins/outputs/all/instrumental.go create mode 100644 plugins/outputs/all/iotdb.go create mode 100644 plugins/outputs/all/kafka.go create mode 100644 plugins/outputs/all/kinesis.go create mode 100644 plugins/outputs/all/librato.go create mode 100644 plugins/outputs/all/logzio.go create mode 100644 plugins/outputs/all/loki.go create mode 100644 plugins/outputs/all/mongodb.go create mode 100644 plugins/outputs/all/mqtt.go create mode 100644 plugins/outputs/all/nats.go create mode 100644 plugins/outputs/all/nebius_cloud_monitoring.go create mode 100644 plugins/outputs/all/newrelic.go create mode 100644 plugins/outputs/all/nsq.go create mode 100644 plugins/outputs/all/opensearch.go create mode 100644 plugins/outputs/all/opentelemetry.go create mode 100644 plugins/outputs/all/opentsdb.go create mode 100644 plugins/outputs/all/parquet.go create mode 100644 plugins/outputs/all/postgresql.go create mode 100644 plugins/outputs/all/prometheus_client.go create mode 100644 plugins/outputs/all/quix.go create mode 100644 plugins/outputs/all/redistimeseries.go create mode 100644 plugins/outputs/all/remotefile.go create mode 100644 plugins/outputs/all/riemann.go create mode 100644 plugins/outputs/all/sensu.go create mode 100644 plugins/outputs/all/signalfx.go create mode 100644 plugins/outputs/all/socket_writer.go create mode 100644 plugins/outputs/all/sql.go create mode 100644 plugins/outputs/all/stackdriver.go create mode 100644 plugins/outputs/all/stomp.go create mode 100644 plugins/outputs/all/sumologic.go create mode 100644 plugins/outputs/all/syslog.go create mode 100644 plugins/outputs/all/timestream.go create mode 100644 plugins/outputs/all/warp10.go create mode 100644 plugins/outputs/all/wavefront.go create mode 100644 plugins/outputs/all/websocket.go create mode 100644 plugins/outputs/all/yandex_cloud_monitoring.go create mode 100644 plugins/outputs/all/zabbix.go create mode 100644 plugins/outputs/amon/README.md create mode 100644 plugins/outputs/amon/amon.go create mode 100644 plugins/outputs/amon/amon_test.go create mode 100644 plugins/outputs/amon/sample.conf create mode 100644 plugins/outputs/amqp/README.md create mode 100644 plugins/outputs/amqp/amqp.go create mode 100644 plugins/outputs/amqp/amqp_test.go create mode 100644 plugins/outputs/amqp/client.go create mode 100644 plugins/outputs/amqp/sample.conf create mode 100644 plugins/outputs/application_insights/README.md create mode 100644 plugins/outputs/application_insights/application_insights.go create mode 100644 plugins/outputs/application_insights/application_insights_test.go create mode 100644 plugins/outputs/application_insights/diagnostic_message_subscriber.go create mode 100644 plugins/outputs/application_insights/mocks/diagnostics_message_listener.go create mode 100644 plugins/outputs/application_insights/mocks/diagnostics_message_subscriber.go create mode 100644 plugins/outputs/application_insights/mocks/transmitter.go create mode 100644 plugins/outputs/application_insights/sample.conf create mode 100644 plugins/outputs/application_insights/transmitter.go create mode 100644 plugins/outputs/azure_data_explorer/README.md create mode 100644 plugins/outputs/azure_data_explorer/azure_data_explorer.go create mode 100644 plugins/outputs/azure_data_explorer/azure_data_explorer_test.go create mode 100644 plugins/outputs/azure_data_explorer/sample.conf create mode 100644 plugins/outputs/azure_monitor/README.md create mode 100644 plugins/outputs/azure_monitor/azure_monitor.go create mode 100644 plugins/outputs/azure_monitor/azure_monitor_test.go create mode 100644 plugins/outputs/azure_monitor/sample.conf create mode 100644 plugins/outputs/azure_monitor/types.go create mode 100644 plugins/outputs/bigquery/README.md create mode 100644 plugins/outputs/bigquery/bigquery.go create mode 100644 plugins/outputs/bigquery/bigquery_test.go create mode 100644 plugins/outputs/bigquery/sample.conf create mode 100644 plugins/outputs/clarify/README.md create mode 100644 plugins/outputs/clarify/clarify.go create mode 100644 plugins/outputs/clarify/clarify_test.go create mode 100644 plugins/outputs/clarify/sample.conf create mode 100644 plugins/outputs/cloud_pubsub/README.md create mode 100644 plugins/outputs/cloud_pubsub/cloud_pubsub.go create mode 100644 plugins/outputs/cloud_pubsub/cloud_pubsub_test.go create mode 100644 plugins/outputs/cloud_pubsub/sample.conf create mode 100644 plugins/outputs/cloud_pubsub/topic_gcp.go create mode 100644 plugins/outputs/cloud_pubsub/topic_stubbed.go create mode 100644 plugins/outputs/cloudwatch/README.md create mode 100644 plugins/outputs/cloudwatch/cloudwatch.go create mode 100644 plugins/outputs/cloudwatch/cloudwatch_test.go create mode 100644 plugins/outputs/cloudwatch/sample.conf create mode 100644 plugins/outputs/cloudwatch_logs/README.md create mode 100644 plugins/outputs/cloudwatch_logs/cloudwatch_logs.go create mode 100644 plugins/outputs/cloudwatch_logs/cloudwatch_logs_test.go create mode 100644 plugins/outputs/cloudwatch_logs/sample.conf create mode 100644 plugins/outputs/cratedb/README.md create mode 100644 plugins/outputs/cratedb/cratedb.go create mode 100644 plugins/outputs/cratedb/cratedb_test.go create mode 100644 plugins/outputs/cratedb/sample.conf create mode 100644 plugins/outputs/datadog/README.md create mode 100644 plugins/outputs/datadog/datadog.go create mode 100644 plugins/outputs/datadog/datadog_test.go create mode 100644 plugins/outputs/datadog/sample.conf create mode 100644 plugins/outputs/deprecations.go create mode 100644 plugins/outputs/discard/README.md create mode 100644 plugins/outputs/discard/discard.go create mode 100644 plugins/outputs/discard/sample.conf create mode 100644 plugins/outputs/dynatrace/README.md create mode 100644 plugins/outputs/dynatrace/dynatrace.go create mode 100644 plugins/outputs/dynatrace/dynatrace_test.go create mode 100644 plugins/outputs/dynatrace/sample.conf create mode 100644 plugins/outputs/elasticsearch/README.md create mode 100644 plugins/outputs/elasticsearch/elasticsearch.go create mode 100644 plugins/outputs/elasticsearch/elasticsearch_test.go create mode 100644 plugins/outputs/elasticsearch/sample.conf create mode 100644 plugins/outputs/event_hubs/README.md create mode 100644 plugins/outputs/event_hubs/event_hubs.go create mode 100644 plugins/outputs/event_hubs/event_hubs_test.go create mode 100644 plugins/outputs/event_hubs/sample.conf create mode 100644 plugins/outputs/event_hubs/testdata/Config.json create mode 100644 plugins/outputs/exec/README.md create mode 100644 plugins/outputs/exec/exec.go create mode 100644 plugins/outputs/exec/exec_test.go create mode 100644 plugins/outputs/exec/sample.conf create mode 100644 plugins/outputs/execd/README.md create mode 100644 plugins/outputs/execd/examples/file/file.sh create mode 100644 plugins/outputs/execd/examples/file/telegraf.conf create mode 100644 plugins/outputs/execd/examples/redis/redis_influx.rb create mode 100644 plugins/outputs/execd/examples/redis/redis_json.rb create mode 100644 plugins/outputs/execd/examples/redis/telegraf.conf create mode 100644 plugins/outputs/execd/execd.go create mode 100644 plugins/outputs/execd/execd_test.go create mode 100644 plugins/outputs/execd/sample.conf create mode 100644 plugins/outputs/file/README.md create mode 100644 plugins/outputs/file/file.go create mode 100644 plugins/outputs/file/file_test.go create mode 100644 plugins/outputs/file/sample.conf create mode 100644 plugins/outputs/graphite/README.md create mode 100644 plugins/outputs/graphite/graphite.go create mode 100644 plugins/outputs/graphite/graphite_test.go create mode 100644 plugins/outputs/graphite/sample.conf create mode 100644 plugins/outputs/graylog/README.md create mode 100644 plugins/outputs/graylog/graylog.go create mode 100644 plugins/outputs/graylog/graylog_test.go create mode 100644 plugins/outputs/graylog/graylog_test_linux.go create mode 100644 plugins/outputs/graylog/sample.conf create mode 100644 plugins/outputs/groundwork/README.md create mode 100644 plugins/outputs/groundwork/groundwork.go create mode 100644 plugins/outputs/groundwork/groundwork_test.go create mode 100644 plugins/outputs/groundwork/log_adapter.go create mode 100644 plugins/outputs/groundwork/sample.conf create mode 100644 plugins/outputs/health/README.md create mode 100644 plugins/outputs/health/compares.go create mode 100644 plugins/outputs/health/compares_test.go create mode 100644 plugins/outputs/health/contains.go create mode 100644 plugins/outputs/health/contains_test.go create mode 100644 plugins/outputs/health/health.go create mode 100644 plugins/outputs/health/health_test.go create mode 100644 plugins/outputs/health/sample.conf create mode 100644 plugins/outputs/http/README.md create mode 100644 plugins/outputs/http/http.go create mode 100644 plugins/outputs/http/http_test.go create mode 100644 plugins/outputs/http/sample.conf create mode 100644 plugins/outputs/influxdb/README.md create mode 100644 plugins/outputs/influxdb/http.go create mode 100644 plugins/outputs/influxdb/http_test.go create mode 100644 plugins/outputs/influxdb/influxdb.go create mode 100644 plugins/outputs/influxdb/influxdb_test.go create mode 100644 plugins/outputs/influxdb/sample.conf create mode 100644 plugins/outputs/influxdb/udp.go create mode 100644 plugins/outputs/influxdb/udp_test.go create mode 100644 plugins/outputs/influxdb_v2/README.md create mode 100644 plugins/outputs/influxdb_v2/http.go create mode 100644 plugins/outputs/influxdb_v2/http_test.go create mode 100644 plugins/outputs/influxdb_v2/influxdb_v2.go create mode 100644 plugins/outputs/influxdb_v2/influxdb_v2_test.go create mode 100644 plugins/outputs/influxdb_v2/sample.conf create mode 100644 plugins/outputs/instrumental/README.md create mode 100644 plugins/outputs/instrumental/instrumental.go create mode 100644 plugins/outputs/instrumental/instrumental_test.go create mode 100644 plugins/outputs/instrumental/sample.conf create mode 100644 plugins/outputs/iotdb/README.md create mode 100644 plugins/outputs/iotdb/iotdb.go create mode 100644 plugins/outputs/iotdb/iotdb_test.go create mode 100644 plugins/outputs/iotdb/sample.conf create mode 100644 plugins/outputs/kafka/README.md create mode 100644 plugins/outputs/kafka/kafka.go create mode 100644 plugins/outputs/kafka/kafka_test.go create mode 100644 plugins/outputs/kafka/sample.conf create mode 100644 plugins/outputs/kinesis/README.md create mode 100644 plugins/outputs/kinesis/kinesis.go create mode 100644 plugins/outputs/kinesis/kinesis_test.go create mode 100644 plugins/outputs/kinesis/sample.conf create mode 100644 plugins/outputs/librato/README.md create mode 100644 plugins/outputs/librato/librato.go create mode 100644 plugins/outputs/librato/librato_test.go create mode 100644 plugins/outputs/librato/sample.conf create mode 100644 plugins/outputs/logzio/README.md create mode 100644 plugins/outputs/logzio/logzio.go create mode 100644 plugins/outputs/logzio/logzio_test.go create mode 100644 plugins/outputs/logzio/sample.conf create mode 100644 plugins/outputs/loki/README.md create mode 100644 plugins/outputs/loki/loki.go create mode 100644 plugins/outputs/loki/loki_test.go create mode 100644 plugins/outputs/loki/sample.conf create mode 100644 plugins/outputs/loki/stream.go create mode 100644 plugins/outputs/loki/stream_test.go create mode 100644 plugins/outputs/mongodb/README.md create mode 100644 plugins/outputs/mongodb/mongodb.go create mode 100644 plugins/outputs/mongodb/mongodb_test.go create mode 100644 plugins/outputs/mongodb/sample.conf create mode 100644 plugins/outputs/mongodb/testdata/auth_scram/setup.js create mode 100644 plugins/outputs/mongodb/testdata/auth_x509/setup.js create mode 100644 plugins/outputs/mqtt/README.md create mode 100644 plugins/outputs/mqtt/homie.go create mode 100644 plugins/outputs/mqtt/mqtt.go create mode 100644 plugins/outputs/mqtt/mqtt_test.go create mode 100644 plugins/outputs/mqtt/sample.conf create mode 100644 plugins/outputs/mqtt/testdata/mosquitto.conf create mode 100644 plugins/outputs/mqtt/topic_name_generator.go create mode 100644 plugins/outputs/nats/README.md create mode 100644 plugins/outputs/nats/nats.go create mode 100644 plugins/outputs/nats/nats_test.go create mode 100644 plugins/outputs/nats/sample.conf create mode 100644 plugins/outputs/nats/testcases/js-config.conf create mode 100644 plugins/outputs/nats/testcases/js-default.conf create mode 100644 plugins/outputs/nats/testcases/js-no-stream.conf create mode 100644 plugins/outputs/nats/testcases/js-subjects.conf create mode 100644 plugins/outputs/nats/testcases/no-js.conf create mode 100644 plugins/outputs/nebius_cloud_monitoring/README.md create mode 100644 plugins/outputs/nebius_cloud_monitoring/nebius_cloud_monitoring.go create mode 100644 plugins/outputs/nebius_cloud_monitoring/nebius_cloud_monitoring_test.go create mode 100644 plugins/outputs/nebius_cloud_monitoring/sample.conf create mode 100644 plugins/outputs/newrelic/README.md create mode 100644 plugins/outputs/newrelic/newrelic.go create mode 100644 plugins/outputs/newrelic/newrelic_test.go create mode 100644 plugins/outputs/newrelic/sample.conf create mode 100644 plugins/outputs/nsq/README.md create mode 100644 plugins/outputs/nsq/nsq.go create mode 100644 plugins/outputs/nsq/nsq_test.go create mode 100644 plugins/outputs/nsq/sample.conf create mode 100644 plugins/outputs/opensearch/README.md create mode 100644 plugins/outputs/opensearch/opensearch.go create mode 100644 plugins/outputs/opensearch/opensearch_test.go create mode 100644 plugins/outputs/opensearch/opensearch_v1_test.go create mode 100644 plugins/outputs/opensearch/opensearch_v2_test.go create mode 100644 plugins/outputs/opensearch/sample.conf create mode 100644 plugins/outputs/opensearch/template.json create mode 100644 plugins/outputs/opentelemetry/README.md create mode 100644 plugins/outputs/opentelemetry/logger.go create mode 100644 plugins/outputs/opentelemetry/opentelemetry.go create mode 100644 plugins/outputs/opentelemetry/opentelemetry_test.go create mode 100644 plugins/outputs/opentelemetry/sample.conf create mode 100644 plugins/outputs/opentsdb/README.md create mode 100644 plugins/outputs/opentsdb/opentsdb.go create mode 100644 plugins/outputs/opentsdb/opentsdb_http.go create mode 100644 plugins/outputs/opentsdb/opentsdb_test.go create mode 100644 plugins/outputs/opentsdb/sample.conf create mode 100644 plugins/outputs/parquet/README.md create mode 100644 plugins/outputs/parquet/parquet.go create mode 100644 plugins/outputs/parquet/parquet_test.go create mode 100644 plugins/outputs/parquet/sample.conf create mode 100644 plugins/outputs/postgresql/Dockerfile create mode 100644 plugins/outputs/postgresql/README.md create mode 100644 plugins/outputs/postgresql/columns.go create mode 100644 plugins/outputs/postgresql/datatype_uint8.go create mode 100644 plugins/outputs/postgresql/datatypes.go create mode 100644 plugins/outputs/postgresql/postgresql.go create mode 100644 plugins/outputs/postgresql/postgresql_bench_test.go create mode 100644 plugins/outputs/postgresql/postgresql_test.go create mode 100644 plugins/outputs/postgresql/sample.conf create mode 100644 plugins/outputs/postgresql/sqltemplate/template.go create mode 100644 plugins/outputs/postgresql/table_manager.go create mode 100644 plugins/outputs/postgresql/table_manager_test.go create mode 100644 plugins/outputs/postgresql/table_source.go create mode 100644 plugins/outputs/postgresql/table_source_test.go create mode 100644 plugins/outputs/postgresql/utils/column.go create mode 100644 plugins/outputs/postgresql/utils/utils.go create mode 100644 plugins/outputs/prometheus_client/README.md create mode 100644 plugins/outputs/prometheus_client/prometheus_client.go create mode 100644 plugins/outputs/prometheus_client/prometheus_client_test.go create mode 100644 plugins/outputs/prometheus_client/prometheus_client_v1_test.go create mode 100644 plugins/outputs/prometheus_client/prometheus_client_v2_test.go create mode 100644 plugins/outputs/prometheus_client/sample.conf create mode 100644 plugins/outputs/prometheus_client/v1/collector.go create mode 100644 plugins/outputs/prometheus_client/v2/collector.go create mode 100644 plugins/outputs/quix/README.md create mode 100644 plugins/outputs/quix/config.go create mode 100644 plugins/outputs/quix/quix.go create mode 100644 plugins/outputs/quix/quix_test.go create mode 100644 plugins/outputs/quix/sample.conf create mode 100644 plugins/outputs/redistimeseries/README.md create mode 100644 plugins/outputs/redistimeseries/redistimeseries.go create mode 100644 plugins/outputs/redistimeseries/redistimeseries_test.go create mode 100644 plugins/outputs/redistimeseries/sample.conf create mode 100644 plugins/outputs/redistimeseries/testcases/normal/expected.out create mode 100644 plugins/outputs/redistimeseries/testcases/normal/input.influx create mode 100644 plugins/outputs/redistimeseries/testcases/normal/telegraf.conf create mode 100644 plugins/outputs/redistimeseries/testcases/normal_varying_labels/expected.out create mode 100644 plugins/outputs/redistimeseries/testcases/normal_varying_labels/input.influx create mode 100644 plugins/outputs/redistimeseries/testcases/normal_varying_labels/telegraf.conf create mode 100644 plugins/outputs/redistimeseries/testcases/string_convert/expected.out create mode 100644 plugins/outputs/redistimeseries/testcases/string_convert/input.influx create mode 100644 plugins/outputs/redistimeseries/testcases/string_convert/telegraf.conf create mode 100644 plugins/outputs/redistimeseries/testcases/string_drop/expected.out create mode 100644 plugins/outputs/redistimeseries/testcases/string_drop/input.influx create mode 100644 plugins/outputs/redistimeseries/testcases/string_drop/telegraf.conf create mode 100644 plugins/outputs/registry.go create mode 100644 plugins/outputs/remotefile/README.md create mode 100644 plugins/outputs/remotefile/backends.go create mode 100644 plugins/outputs/remotefile/remotefile.go create mode 100644 plugins/outputs/remotefile/remotefile_test.go create mode 100644 plugins/outputs/remotefile/sample.conf create mode 100644 plugins/outputs/riemann/README.md create mode 100644 plugins/outputs/riemann/riemann.go create mode 100644 plugins/outputs/riemann/riemann_test.go create mode 100644 plugins/outputs/riemann/sample.conf create mode 100644 plugins/outputs/sensu/README.md create mode 100644 plugins/outputs/sensu/sample.conf create mode 100644 plugins/outputs/sensu/sensu.go create mode 100644 plugins/outputs/sensu/sensu_test.go create mode 100644 plugins/outputs/signalfx/README.md create mode 100644 plugins/outputs/signalfx/sample.conf create mode 100644 plugins/outputs/signalfx/signalfx.go create mode 100644 plugins/outputs/signalfx/signalfx_test.go create mode 100644 plugins/outputs/socket_writer/README.md create mode 100644 plugins/outputs/socket_writer/sample.conf create mode 100644 plugins/outputs/socket_writer/socket_writer.go create mode 100644 plugins/outputs/socket_writer/socket_writer_test.go create mode 100644 plugins/outputs/sql/README.md create mode 100644 plugins/outputs/sql/sample.conf create mode 100644 plugins/outputs/sql/sql.go create mode 100644 plugins/outputs/sql/sql_test.go create mode 100644 plugins/outputs/sql/sqlite.go create mode 100644 plugins/outputs/sql/sqlite_test.go create mode 100644 plugins/outputs/sql/testdata/clickhouse/enable_stdout_log.xml create mode 100644 plugins/outputs/sql/testdata/clickhouse/expected.txt create mode 100644 plugins/outputs/sql/testdata/clickhouse/initdb/init.sql create mode 100644 plugins/outputs/sql/testdata/mariadb/expected_metric_one.sql create mode 100644 plugins/outputs/sql/testdata/mariadb/expected_metric_three.sql create mode 100644 plugins/outputs/sql/testdata/mariadb/expected_metric_two.sql create mode 100644 plugins/outputs/sql/testdata/mariadb/initdb/script.sql create mode 100644 plugins/outputs/sql/testdata/mariadb_no_timestamp/expected_metric_one.sql create mode 100644 plugins/outputs/sql/testdata/mariadb_no_timestamp/expected_metric_three.sql create mode 100644 plugins/outputs/sql/testdata/mariadb_no_timestamp/expected_metric_two.sql create mode 100644 plugins/outputs/sql/testdata/mariadb_no_timestamp/initdb/script.sql create mode 100644 plugins/outputs/sql/testdata/postgres/expected.sql create mode 100644 plugins/outputs/sql/testdata/postgres/initdb/init.sql create mode 100644 plugins/outputs/stackdriver/README.md create mode 100644 plugins/outputs/stackdriver/counter_cache.go create mode 100644 plugins/outputs/stackdriver/counter_cache_test.go create mode 100644 plugins/outputs/stackdriver/sample.conf create mode 100644 plugins/outputs/stackdriver/stackdriver.go create mode 100644 plugins/outputs/stackdriver/stackdriver_test.go create mode 100644 plugins/outputs/stomp/README.md create mode 100644 plugins/outputs/stomp/sample.conf create mode 100644 plugins/outputs/stomp/stomp.go create mode 100644 plugins/outputs/stomp/stomp_test.go create mode 100644 plugins/outputs/sumologic/README.md create mode 100644 plugins/outputs/sumologic/sample.conf create mode 100644 plugins/outputs/sumologic/sumologic.go create mode 100644 plugins/outputs/sumologic/sumologic_test.go create mode 100644 plugins/outputs/syslog/README.md create mode 100644 plugins/outputs/syslog/sample.conf create mode 100644 plugins/outputs/syslog/syslog.go create mode 100644 plugins/outputs/syslog/syslog_mapper.go create mode 100644 plugins/outputs/syslog/syslog_mapper_test.go create mode 100644 plugins/outputs/syslog/syslog_test.go create mode 100644 plugins/outputs/syslog/testcases/issue_16012/expected.out create mode 100644 plugins/outputs/syslog/testcases/issue_16012/input.influx create mode 100644 plugins/outputs/syslog/testcases/issue_16012/telegraf.conf create mode 100644 plugins/outputs/timestream/README.md create mode 100644 plugins/outputs/timestream/sample.conf create mode 100644 plugins/outputs/timestream/timestream.go create mode 100644 plugins/outputs/timestream/timestream_internal_test.go create mode 100644 plugins/outputs/timestream/timestream_test.go create mode 100644 plugins/outputs/warp10/README.md create mode 100644 plugins/outputs/warp10/sample.conf create mode 100644 plugins/outputs/warp10/warp10.go create mode 100644 plugins/outputs/warp10/warp10_test.go create mode 100644 plugins/outputs/wavefront/README.md create mode 100644 plugins/outputs/wavefront/sample.conf create mode 100644 plugins/outputs/wavefront/wavefront.go create mode 100644 plugins/outputs/wavefront/wavefront_test.go create mode 100644 plugins/outputs/websocket/README.md create mode 100644 plugins/outputs/websocket/sample.conf create mode 100644 plugins/outputs/websocket/websocket.go create mode 100644 plugins/outputs/websocket/websocket_test.go create mode 100644 plugins/outputs/yandex_cloud_monitoring/README.md create mode 100644 plugins/outputs/yandex_cloud_monitoring/sample.conf create mode 100644 plugins/outputs/yandex_cloud_monitoring/yandex_cloud_monitoring.go create mode 100644 plugins/outputs/yandex_cloud_monitoring/yandex_cloud_monitoring_test.go create mode 100644 plugins/outputs/zabbix/README.md create mode 100644 plugins/outputs/zabbix/autoregister.go create mode 100644 plugins/outputs/zabbix/autoregister_test.go create mode 100644 plugins/outputs/zabbix/lld.go create mode 100644 plugins/outputs/zabbix/lld_test.go create mode 100644 plugins/outputs/zabbix/sample.conf create mode 100644 plugins/outputs/zabbix/testcases/receive/expected.out create mode 100644 plugins/outputs/zabbix/testcases/receive/input.influx create mode 100644 plugins/outputs/zabbix/testcases/receive/telegraf.conf create mode 100644 plugins/outputs/zabbix/zabbix.go create mode 100644 plugins/outputs/zabbix/zabbix_test.go create mode 100644 plugins/parsers/EXAMPLE_README.md create mode 100644 plugins/parsers/all/all.go create mode 100644 plugins/parsers/all/avro.go create mode 100644 plugins/parsers/all/binary.go create mode 100644 plugins/parsers/all/collectd.go create mode 100644 plugins/parsers/all/csv.go create mode 100644 plugins/parsers/all/dropwizard.go create mode 100644 plugins/parsers/all/form_urlencoded.go create mode 100644 plugins/parsers/all/graphite.go create mode 100644 plugins/parsers/all/grok.go create mode 100644 plugins/parsers/all/influx.go create mode 100644 plugins/parsers/all/json.go create mode 100644 plugins/parsers/all/json_v2.go create mode 100644 plugins/parsers/all/logfmt.go create mode 100644 plugins/parsers/all/nagios.go create mode 100644 plugins/parsers/all/openmetrics.go create mode 100644 plugins/parsers/all/opentsdb.go create mode 100644 plugins/parsers/all/parquet.go create mode 100644 plugins/parsers/all/prometheus.go create mode 100644 plugins/parsers/all/prometheusremotewrite.go create mode 100644 plugins/parsers/all/value.go create mode 100644 plugins/parsers/all/wavefront.go create mode 100644 plugins/parsers/all/xpath.go create mode 100644 plugins/parsers/avro/README.md create mode 100644 plugins/parsers/avro/parser.go create mode 100644 plugins/parsers/avro/parser_test.go create mode 100644 plugins/parsers/avro/schema_registry.go create mode 100644 plugins/parsers/avro/testcases/bad-timestamp-format/expected.err create mode 100644 plugins/parsers/avro/testcases/bad-timestamp-format/expected.out create mode 100644 plugins/parsers/avro/testcases/bad-timestamp-format/message.avro create mode 100644 plugins/parsers/avro/testcases/bad-timestamp-format/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/benchmark/expected.out create mode 100644 plugins/parsers/avro/testcases/benchmark/message.json create mode 100644 plugins/parsers/avro/testcases/benchmark/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/config-both/expected.err create mode 100644 plugins/parsers/avro/testcases/config-both/expected.out create mode 100644 plugins/parsers/avro/testcases/config-both/message.avro create mode 100644 plugins/parsers/avro/testcases/config-both/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/config-neither/expected.err create mode 100644 plugins/parsers/avro/testcases/config-neither/expected.out create mode 100644 plugins/parsers/avro/testcases/config-neither/message.avro create mode 100644 plugins/parsers/avro/testcases/config-neither/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/enum/expected.out create mode 100644 plugins/parsers/avro/testcases/enum/message.json create mode 100644 plugins/parsers/avro/testcases/enum/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/json-array/expected.out create mode 100644 plugins/parsers/avro/testcases/json-array/message.json create mode 100644 plugins/parsers/avro/testcases/json-array/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/json-format/expected.out create mode 100644 plugins/parsers/avro/testcases/json-format/message.json create mode 100644 plugins/parsers/avro/testcases/json-format/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/measurement_name_from_message/expected.out create mode 100644 plugins/parsers/avro/testcases/measurement_name_from_message/message.avro create mode 100644 plugins/parsers/avro/testcases/measurement_name_from_message/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/no-timestamp-format/expected.out create mode 100644 plugins/parsers/avro/testcases/no-timestamp-format/message.avro create mode 100644 plugins/parsers/avro/testcases/no-timestamp-format/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/supplied_timestamp/expected.out create mode 100644 plugins/parsers/avro/testcases/supplied_timestamp/message.avro create mode 100644 plugins/parsers/avro/testcases/supplied_timestamp/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/supplied_timestamp_fields_specified/expected.out create mode 100644 plugins/parsers/avro/testcases/supplied_timestamp_fields_specified/message.avro create mode 100644 plugins/parsers/avro/testcases/supplied_timestamp_fields_specified/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/supplied_timestamp_fields_unspecified/expected.out create mode 100644 plugins/parsers/avro/testcases/supplied_timestamp_fields_unspecified/message.avro create mode 100644 plugins/parsers/avro/testcases/supplied_timestamp_fields_unspecified/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/union-any/expected.out create mode 100644 plugins/parsers/avro/testcases/union-any/message.json create mode 100644 plugins/parsers/avro/testcases/union-any/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/union-array/expected.out create mode 100644 plugins/parsers/avro/testcases/union-array/message.json create mode 100644 plugins/parsers/avro/testcases/union-array/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/union-nullable-tag/expected.out create mode 100644 plugins/parsers/avro/testcases/union-nullable-tag/message.json create mode 100644 plugins/parsers/avro/testcases/union-nullable-tag/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/union-nullable/expected.out create mode 100644 plugins/parsers/avro/testcases/union-nullable/message.json create mode 100644 plugins/parsers/avro/testcases/union-nullable/telegraf.conf create mode 100644 plugins/parsers/avro/testcases/union/expected.out create mode 100644 plugins/parsers/avro/testcases/union/message.json create mode 100644 plugins/parsers/avro/testcases/union/telegraf.conf create mode 100644 plugins/parsers/binary/README.md create mode 100644 plugins/parsers/binary/config.go create mode 100644 plugins/parsers/binary/entry.go create mode 100644 plugins/parsers/binary/entry_test.go create mode 100644 plugins/parsers/binary/parser.go create mode 100644 plugins/parsers/binary/parser_test.go create mode 100644 plugins/parsers/binary/testcases/base64_encoding/expected.out create mode 100644 plugins/parsers/binary/testcases/base64_encoding/messageA.bin create mode 100644 plugins/parsers/binary/testcases/base64_encoding/messageB.bin create mode 100644 plugins/parsers/binary/testcases/base64_encoding/messageC.bin create mode 100644 plugins/parsers/binary/testcases/base64_encoding/telegraf.conf create mode 100644 plugins/parsers/binary/testcases/hex_encoding/expected.out create mode 100644 plugins/parsers/binary/testcases/hex_encoding/messageA.bin create mode 100644 plugins/parsers/binary/testcases/hex_encoding/messageB.bin create mode 100644 plugins/parsers/binary/testcases/hex_encoding/messageC.bin create mode 100644 plugins/parsers/binary/testcases/hex_encoding/telegraf.conf create mode 100644 plugins/parsers/binary/testcases/multiple_messages/expected.out create mode 100644 plugins/parsers/binary/testcases/multiple_messages/messageA.bin create mode 100644 plugins/parsers/binary/testcases/multiple_messages/messageB.bin create mode 100644 plugins/parsers/binary/testcases/multiple_messages/messageC.bin create mode 100644 plugins/parsers/binary/testcases/multiple_messages/telegraf.conf create mode 100644 plugins/parsers/collectd/README.md create mode 100644 plugins/parsers/collectd/parser.go create mode 100644 plugins/parsers/collectd/parser_test.go create mode 100644 plugins/parsers/collectd/testdata/authfile create mode 100644 plugins/parsers/csv/README.md create mode 100644 plugins/parsers/csv/parser.go create mode 100644 plugins/parsers/csv/parser_test.go create mode 100644 plugins/parsers/deprecations.go create mode 100644 plugins/parsers/dropwizard/README.md create mode 100644 plugins/parsers/dropwizard/parser.go create mode 100644 plugins/parsers/dropwizard/parser_test.go create mode 100644 plugins/parsers/errors.go create mode 100644 plugins/parsers/form_urlencoded/README.md create mode 100644 plugins/parsers/form_urlencoded/parser.go create mode 100644 plugins/parsers/form_urlencoded/parser_test.go create mode 100644 plugins/parsers/graphite/README.md create mode 100644 plugins/parsers/graphite/config.go create mode 100644 plugins/parsers/graphite/parser.go create mode 100644 plugins/parsers/graphite/parser_test.go create mode 100644 plugins/parsers/grok/README.md create mode 100644 plugins/parsers/grok/influx_patterns.go create mode 100644 plugins/parsers/grok/parser.go create mode 100644 plugins/parsers/grok/parser_test.go create mode 100644 plugins/parsers/grok/testdata/test-patterns create mode 100644 plugins/parsers/grok/testdata/test_a.log create mode 100644 plugins/parsers/grok/testdata/test_b.log create mode 100644 plugins/parsers/grok/testdata/test_multiline.log create mode 100644 plugins/parsers/influx/README.md create mode 100644 plugins/parsers/influx/escape.go create mode 100644 plugins/parsers/influx/handler.go create mode 100644 plugins/parsers/influx/influx_upstream/README.md create mode 100644 plugins/parsers/influx/influx_upstream/parser.go create mode 100644 plugins/parsers/influx/influx_upstream/parser_test.go create mode 100644 plugins/parsers/influx/machine.go create mode 100644 plugins/parsers/influx/machine.go.rl create mode 100644 plugins/parsers/influx/machine_test.go create mode 100644 plugins/parsers/influx/parser.go create mode 100644 plugins/parsers/influx/parser_test.go create mode 100644 plugins/parsers/json/README.md create mode 100644 plugins/parsers/json/json_flattener.go create mode 100644 plugins/parsers/json/parser.go create mode 100644 plugins/parsers/json/parser_test.go create mode 100644 plugins/parsers/json_v2/README.md create mode 100644 plugins/parsers/json_v2/parser.go create mode 100644 plugins/parsers/json_v2/parser_test.go create mode 100644 plugins/parsers/json_v2/testdata/10670/expected.out create mode 100644 plugins/parsers/json_v2/testdata/10670/input.json create mode 100644 plugins/parsers/json_v2/testdata/10670/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/array_of_objects/expected.out create mode 100644 plugins/parsers/json_v2/testdata/array_of_objects/input.json create mode 100644 plugins/parsers/json_v2/testdata/array_of_objects/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/benchmark/benchmark.json create mode 100644 plugins/parsers/json_v2/testdata/benchmark/expected.out create mode 100644 plugins/parsers/json_v2/testdata/benchmark/input.json create mode 100644 plugins/parsers/json_v2/testdata/benchmark/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/complex_nesting/expected.out create mode 100644 plugins/parsers/json_v2/testdata/complex_nesting/input.json create mode 100644 plugins/parsers/json_v2/testdata/complex_nesting/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/fields_and_tags/expected.out create mode 100644 plugins/parsers/json_v2/testdata/fields_and_tags/input.json create mode 100644 plugins/parsers/json_v2/testdata/fields_and_tags/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/fields_and_tags_complex/expected.out create mode 100644 plugins/parsers/json_v2/testdata/fields_and_tags_complex/input.json create mode 100644 plugins/parsers/json_v2/testdata/fields_and_tags_complex/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/large_numbers/expected.out create mode 100644 plugins/parsers/json_v2/testdata/large_numbers/input.json create mode 100644 plugins/parsers/json_v2/testdata/large_numbers/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/measurement_name_int/expected.out create mode 100644 plugins/parsers/json_v2/testdata/measurement_name_int/input.json create mode 100644 plugins/parsers/json_v2/testdata/measurement_name_int/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/mix_field_and_object/expected.out create mode 100644 plugins/parsers/json_v2/testdata/mix_field_and_object/input.json create mode 100644 plugins/parsers/json_v2/testdata/mix_field_and_object/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/multiple_arrays_in_object/expected.out create mode 100644 plugins/parsers/json_v2/testdata/multiple_arrays_in_object/input.json create mode 100644 plugins/parsers/json_v2/testdata/multiple_arrays_in_object/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/multiple_json_input/expected.out create mode 100644 plugins/parsers/json_v2/testdata/multiple_json_input/input_1.json create mode 100644 plugins/parsers/json_v2/testdata/multiple_json_input/input_2.json create mode 100644 plugins/parsers/json_v2/testdata/multiple_json_input/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/multiple_timestamps/expected.out create mode 100644 plugins/parsers/json_v2/testdata/multiple_timestamps/input.json create mode 100644 plugins/parsers/json_v2/testdata/multiple_timestamps/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/nested_and_nonnested_tags/expected.out create mode 100644 plugins/parsers/json_v2/testdata/nested_and_nonnested_tags/input.json create mode 100644 plugins/parsers/json_v2/testdata/nested_and_nonnested_tags/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/nested_array_of_objects/expected.out create mode 100644 plugins/parsers/json_v2/testdata/nested_array_of_objects/input.json create mode 100644 plugins/parsers/json_v2/testdata/nested_array_of_objects/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/nested_objects_optional/expected.out create mode 100644 plugins/parsers/json_v2/testdata/nested_objects_optional/nested_objects_nest.json create mode 100644 plugins/parsers/json_v2/testdata/nested_objects_optional/nested_objects_single.json create mode 100644 plugins/parsers/json_v2/testdata/nested_objects_optional/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/nested_tags/expected.out create mode 100644 plugins/parsers/json_v2/testdata/nested_tags/input.json create mode 100644 plugins/parsers/json_v2/testdata/nested_tags/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/nested_tags_complex/expected.out create mode 100644 plugins/parsers/json_v2/testdata/nested_tags_complex/input.json create mode 100644 plugins/parsers/json_v2/testdata/nested_tags_complex/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/null/expected.out create mode 100644 plugins/parsers/json_v2/testdata/null/input.json create mode 100644 plugins/parsers/json_v2/testdata/null/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/object/expected.out create mode 100644 plugins/parsers/json_v2/testdata/object/input.json create mode 100644 plugins/parsers/json_v2/testdata/object/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/object_multiple/expected.out create mode 100644 plugins/parsers/json_v2/testdata/object_multiple/input.json create mode 100644 plugins/parsers/json_v2/testdata/object_multiple/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/object_timestamp/expected.out create mode 100644 plugins/parsers/json_v2/testdata/object_timestamp/input.json create mode 100644 plugins/parsers/json_v2/testdata/object_timestamp/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/optional/expected.out create mode 100644 plugins/parsers/json_v2/testdata/optional/input.json create mode 100644 plugins/parsers/json_v2/testdata/optional/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/optional_objects/expected.out create mode 100644 plugins/parsers/json_v2/testdata/optional_objects/input_1.json create mode 100644 plugins/parsers/json_v2/testdata/optional_objects/input_2.json create mode 100644 plugins/parsers/json_v2/testdata/optional_objects/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/subfieldtag_in_object/expected.out create mode 100644 plugins/parsers/json_v2/testdata/subfieldtag_in_object/input.json create mode 100644 plugins/parsers/json_v2/testdata/subfieldtag_in_object/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/subfieldtag_in_object_2/expected.out create mode 100644 plugins/parsers/json_v2/testdata/subfieldtag_in_object_2/input.json create mode 100644 plugins/parsers/json_v2/testdata/subfieldtag_in_object_2/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/timestamp/expected.out create mode 100644 plugins/parsers/json_v2/testdata/timestamp/input.json create mode 100644 plugins/parsers/json_v2/testdata/timestamp/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/timestamp_ns/expected.out create mode 100644 plugins/parsers/json_v2/testdata/timestamp_ns/input.json create mode 100644 plugins/parsers/json_v2/testdata/timestamp_ns/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/timestamp_rfc3339/expected.out create mode 100644 plugins/parsers/json_v2/testdata/timestamp_rfc3339/input.json create mode 100644 plugins/parsers/json_v2/testdata/timestamp_rfc3339/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/types/expected.out create mode 100644 plugins/parsers/json_v2/testdata/types/input.json create mode 100644 plugins/parsers/json_v2/testdata/types/telegraf.conf create mode 100644 plugins/parsers/json_v2/testdata/wrong_path/expected.err create mode 100644 plugins/parsers/json_v2/testdata/wrong_path/expected.out create mode 100644 plugins/parsers/json_v2/testdata/wrong_path/input.json create mode 100644 plugins/parsers/json_v2/testdata/wrong_path/telegraf.conf create mode 100644 plugins/parsers/logfmt/README.md create mode 100644 plugins/parsers/logfmt/parser.go create mode 100644 plugins/parsers/logfmt/parser_test.go create mode 100644 plugins/parsers/nagios/README.md create mode 100644 plugins/parsers/nagios/parser.go create mode 100644 plugins/parsers/nagios/parser_test.go create mode 100644 plugins/parsers/openmetrics/README.md create mode 100644 plugins/parsers/openmetrics/metric_v1.go create mode 100644 plugins/parsers/openmetrics/metric_v2.go create mode 100644 plugins/parsers/openmetrics/openmetrics_data_model.pb.go create mode 100644 plugins/parsers/openmetrics/openmetrics_data_model.proto create mode 100644 plugins/parsers/openmetrics/parser.go create mode 100644 plugins/parsers/openmetrics/parser_test.go create mode 100644 plugins/parsers/openmetrics/testcases/dovecot/expected_v1.out create mode 100644 plugins/parsers/openmetrics/testcases/dovecot/expected_v2.out create mode 100644 plugins/parsers/openmetrics/testcases/dovecot/input.txt create mode 100644 plugins/parsers/openmetrics/testcases/dovecot/telegraf.conf create mode 100644 plugins/parsers/openmetrics/testcases/multiple/expected_v1.out create mode 100644 plugins/parsers/openmetrics/testcases/multiple/expected_v2.out create mode 100644 plugins/parsers/openmetrics/testcases/multiple/input.txt create mode 100644 plugins/parsers/openmetrics/testcases/multiple/telegraf.conf create mode 100644 plugins/parsers/openmetrics/testcases/protobuf/expected_v1.out create mode 100644 plugins/parsers/openmetrics/testcases/protobuf/expected_v2.out create mode 100644 plugins/parsers/openmetrics/testcases/protobuf/input.bin create mode 100644 plugins/parsers/openmetrics/testcases/protobuf/telegraf.conf create mode 100644 plugins/parsers/openmetrics/testcases/protobuf_infolabels/expected_v1.out create mode 100644 plugins/parsers/openmetrics/testcases/protobuf_infolabels/expected_v2.out create mode 100644 plugins/parsers/openmetrics/testcases/protobuf_infolabels/input.bin create mode 100644 plugins/parsers/openmetrics/testcases/protobuf_infolabels/telegraf.conf create mode 100644 plugins/parsers/openmetrics/testcases/valid_counter/expected_v1.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_counter/expected_v2.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_counter/input.txt create mode 100644 plugins/parsers/openmetrics/testcases/valid_counter/telegraf.conf create mode 100644 plugins/parsers/openmetrics/testcases/valid_gauge/expected_v1.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_gauge/expected_v2.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_gauge/input.txt create mode 100644 plugins/parsers/openmetrics/testcases/valid_gauge/telegraf.conf create mode 100644 plugins/parsers/openmetrics/testcases/valid_gaugehistogram/expected_v1.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_gaugehistogram/expected_v2.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_gaugehistogram/input.txt create mode 100644 plugins/parsers/openmetrics/testcases/valid_gaugehistogram/telegraf.conf create mode 100644 plugins/parsers/openmetrics/testcases/valid_histogram/expected_v1.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_histogram/expected_v2.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_histogram/input.txt create mode 100644 plugins/parsers/openmetrics/testcases/valid_histogram/telegraf.conf create mode 100644 plugins/parsers/openmetrics/testcases/valid_info/expected_v1.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_info/expected_v2.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_info/input.txt create mode 100644 plugins/parsers/openmetrics/testcases/valid_info/telegraf.conf create mode 100644 plugins/parsers/openmetrics/testcases/valid_stateset/expected_v1.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_stateset/expected_v2.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_stateset/input.txt create mode 100644 plugins/parsers/openmetrics/testcases/valid_stateset/telegraf.conf create mode 100644 plugins/parsers/openmetrics/testcases/valid_summary/expected_v1.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_summary/expected_v2.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_summary/input.txt create mode 100644 plugins/parsers/openmetrics/testcases/valid_summary/telegraf.conf create mode 100644 plugins/parsers/openmetrics/testcases/valid_unknown/expected_v1.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_unknown/expected_v2.out create mode 100644 plugins/parsers/openmetrics/testcases/valid_unknown/input.txt create mode 100644 plugins/parsers/openmetrics/testcases/valid_unknown/telegraf.conf create mode 100644 plugins/parsers/openmetrics/textparse.go create mode 100644 plugins/parsers/opentsdb/README.md create mode 100644 plugins/parsers/opentsdb/parser.go create mode 100644 plugins/parsers/opentsdb/parser_test.go create mode 100644 plugins/parsers/parquet/README.md create mode 100644 plugins/parsers/parquet/columns.go create mode 100644 plugins/parsers/parquet/parser.go create mode 100644 plugins/parsers/parquet/parser_test.go create mode 100644 plugins/parsers/parquet/testcases/benchmark/expected.out create mode 100644 plugins/parsers/parquet/testcases/benchmark/generate.py create mode 100644 plugins/parsers/parquet/testcases/benchmark/input.parquet create mode 100644 plugins/parsers/parquet/testcases/benchmark/telegraf.conf create mode 100644 plugins/parsers/parquet/testcases/datatypes/expected.out create mode 100644 plugins/parsers/parquet/testcases/datatypes/generate.py create mode 100644 plugins/parsers/parquet/testcases/datatypes/input.parquet create mode 100644 plugins/parsers/parquet/testcases/datatypes/telegraf.conf create mode 100644 plugins/parsers/parquet/testcases/dense/expected.out create mode 100644 plugins/parsers/parquet/testcases/dense/generate.py create mode 100644 plugins/parsers/parquet/testcases/dense/input.parquet create mode 100644 plugins/parsers/parquet/testcases/dense/telegraf.conf create mode 100644 plugins/parsers/parquet/testcases/empty/expected.out create mode 100644 plugins/parsers/parquet/testcases/empty/generate.py create mode 100644 plugins/parsers/parquet/testcases/empty/input.parquet create mode 100644 plugins/parsers/parquet/testcases/empty/telegraf.conf create mode 100644 plugins/parsers/parquet/testcases/multitable/expected.out create mode 100644 plugins/parsers/parquet/testcases/multitable/generate.py create mode 100644 plugins/parsers/parquet/testcases/multitable/input.parquet create mode 100644 plugins/parsers/parquet/testcases/multitable/telegraf.conf create mode 100644 plugins/parsers/parquet/testcases/sparse/expected.out create mode 100644 plugins/parsers/parquet/testcases/sparse/generate.py create mode 100644 plugins/parsers/parquet/testcases/sparse/input.parquet create mode 100644 plugins/parsers/parquet/testcases/sparse/telegraf.conf create mode 100644 plugins/parsers/parquet/testcases/timestamp/expected.out create mode 100644 plugins/parsers/parquet/testcases/timestamp/generate.py create mode 100644 plugins/parsers/parquet/testcases/timestamp/input.parquet create mode 100644 plugins/parsers/parquet/testcases/timestamp/telegraf.conf create mode 100644 plugins/parsers/prometheus/README.md create mode 100644 plugins/parsers/prometheus/common.go create mode 100644 plugins/parsers/prometheus/metric_v1.go create mode 100644 plugins/parsers/prometheus/metric_v2.go create mode 100644 plugins/parsers/prometheus/parser.go create mode 100644 plugins/parsers/prometheus/parser_test.go create mode 100644 plugins/parsers/prometheus/testcases/benchmark/expected_v1.out create mode 100644 plugins/parsers/prometheus/testcases/benchmark/expected_v2.out create mode 100644 plugins/parsers/prometheus/testcases/benchmark/input.txt create mode 100644 plugins/parsers/prometheus/testcases/benchmark/telegraf.conf create mode 100644 plugins/parsers/prometheus/testcases/default_tags/expected_v1.out create mode 100644 plugins/parsers/prometheus/testcases/default_tags/expected_v2.out create mode 100644 plugins/parsers/prometheus/testcases/default_tags/input.txt create mode 100644 plugins/parsers/prometheus/testcases/default_tags/telegraf.conf create mode 100644 plugins/parsers/prometheus/testcases/histogram_inf_bucket/expected_v1.out create mode 100644 plugins/parsers/prometheus/testcases/histogram_inf_bucket/expected_v2.out create mode 100644 plugins/parsers/prometheus/testcases/histogram_inf_bucket/input.bin create mode 100644 plugins/parsers/prometheus/testcases/histogram_inf_bucket/telegraf.conf create mode 100644 plugins/parsers/prometheus/testcases/ignore_timestamp/expected_v1.out create mode 100644 plugins/parsers/prometheus/testcases/ignore_timestamp/expected_v2.out create mode 100644 plugins/parsers/prometheus/testcases/ignore_timestamp/input.txt create mode 100644 plugins/parsers/prometheus/testcases/ignore_timestamp/telegraf.conf create mode 100644 plugins/parsers/prometheus/testcases/metric_with_timestamp/expected_v1.out create mode 100644 plugins/parsers/prometheus/testcases/metric_with_timestamp/expected_v2.out create mode 100644 plugins/parsers/prometheus/testcases/metric_with_timestamp/input.txt create mode 100644 plugins/parsers/prometheus/testcases/metric_with_timestamp/telegraf.conf create mode 100644 plugins/parsers/prometheus/testcases/protobuf/expected_v1.out create mode 100644 plugins/parsers/prometheus/testcases/protobuf/expected_v2.out create mode 100644 plugins/parsers/prometheus/testcases/protobuf/input.bin create mode 100644 plugins/parsers/prometheus/testcases/protobuf/telegraf.conf create mode 100644 plugins/parsers/prometheus/testcases/valid_counter/expected_v1.out create mode 100644 plugins/parsers/prometheus/testcases/valid_counter/expected_v2.out create mode 100644 plugins/parsers/prometheus/testcases/valid_counter/input.txt create mode 100644 plugins/parsers/prometheus/testcases/valid_counter/telegraf.conf create mode 100644 plugins/parsers/prometheus/testcases/valid_gauge/expected_v1.out create mode 100644 plugins/parsers/prometheus/testcases/valid_gauge/expected_v2.out create mode 100644 plugins/parsers/prometheus/testcases/valid_gauge/input.txt create mode 100644 plugins/parsers/prometheus/testcases/valid_gauge/telegraf.conf create mode 100644 plugins/parsers/prometheus/testcases/valid_histogram/expected_v1.out create mode 100644 plugins/parsers/prometheus/testcases/valid_histogram/expected_v2.out create mode 100644 plugins/parsers/prometheus/testcases/valid_histogram/input.txt create mode 100644 plugins/parsers/prometheus/testcases/valid_histogram/telegraf.conf create mode 100644 plugins/parsers/prometheus/testcases/valid_summary/expected_v1.out create mode 100644 plugins/parsers/prometheus/testcases/valid_summary/expected_v2.out create mode 100644 plugins/parsers/prometheus/testcases/valid_summary/input.txt create mode 100644 plugins/parsers/prometheus/testcases/valid_summary/telegraf.conf create mode 100644 plugins/parsers/prometheusremotewrite/README.md create mode 100644 plugins/parsers/prometheusremotewrite/metric_v1.go create mode 100644 plugins/parsers/prometheusremotewrite/metric_v2.go create mode 100644 plugins/parsers/prometheusremotewrite/parser.go create mode 100644 plugins/parsers/prometheusremotewrite/parser_test.go create mode 100644 plugins/parsers/prometheusremotewrite/testcases/benchmark/expected_v1.out create mode 100644 plugins/parsers/prometheusremotewrite/testcases/benchmark/expected_v2.out create mode 100644 plugins/parsers/prometheusremotewrite/testcases/benchmark/input.json create mode 100644 plugins/parsers/prometheusremotewrite/testcases/benchmark/telegraf.conf create mode 100644 plugins/parsers/prometheusremotewrite/testcases/default_tags/expected_v1.out create mode 100644 plugins/parsers/prometheusremotewrite/testcases/default_tags/expected_v2.out create mode 100644 plugins/parsers/prometheusremotewrite/testcases/default_tags/input.json create mode 100644 plugins/parsers/prometheusremotewrite/testcases/default_tags/telegraf.conf create mode 100644 plugins/parsers/prometheusremotewrite/testcases/float_histogram/expected_v1.out create mode 100644 plugins/parsers/prometheusremotewrite/testcases/float_histogram/expected_v2.out create mode 100644 plugins/parsers/prometheusremotewrite/testcases/float_histogram/input.json create mode 100644 plugins/parsers/prometheusremotewrite/testcases/float_histogram/telegraf.conf create mode 100644 plugins/parsers/prometheusremotewrite/testcases/int_histogram/expected_v1.out create mode 100644 plugins/parsers/prometheusremotewrite/testcases/int_histogram/expected_v2.out create mode 100644 plugins/parsers/prometheusremotewrite/testcases/int_histogram/input.json create mode 100644 plugins/parsers/prometheusremotewrite/testcases/int_histogram/telegraf.conf create mode 100644 plugins/parsers/prometheusremotewrite/testcases/simple/expected_v1.out create mode 100644 plugins/parsers/prometheusremotewrite/testcases/simple/expected_v2.out create mode 100644 plugins/parsers/prometheusremotewrite/testcases/simple/input.json create mode 100644 plugins/parsers/prometheusremotewrite/testcases/simple/telegraf.conf create mode 100644 plugins/parsers/registry.go create mode 100644 plugins/parsers/value/README.md create mode 100644 plugins/parsers/value/parser.go create mode 100644 plugins/parsers/value/parser_test.go create mode 100644 plugins/parsers/wavefront/README.md create mode 100644 plugins/parsers/wavefront/element.go create mode 100644 plugins/parsers/wavefront/parser.go create mode 100644 plugins/parsers/wavefront/parser_test.go create mode 100644 plugins/parsers/wavefront/scanner.go create mode 100644 plugins/parsers/wavefront/token.go create mode 100644 plugins/parsers/xpath/README.md create mode 100644 plugins/parsers/xpath/cbor_document.go create mode 100644 plugins/parsers/xpath/json_document.go create mode 100644 plugins/parsers/xpath/msgpack_document.go create mode 100644 plugins/parsers/xpath/parser.go create mode 100644 plugins/parsers/xpath/parser_test.go create mode 100644 plugins/parsers/xpath/protocolbuffer_document.go create mode 100644 plugins/parsers/xpath/testcases/addressbook.conf create mode 100644 plugins/parsers/xpath/testcases/addressbook.dat create mode 100644 plugins/parsers/xpath/testcases/cbor/addressbook.bin create mode 100644 plugins/parsers/xpath/testcases/cbor/expected.out create mode 100644 plugins/parsers/xpath/testcases/cbor/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/cbor_base64_encoding/data.bin create mode 100644 plugins/parsers/xpath/testcases/cbor_base64_encoding/expected.out create mode 100644 plugins/parsers/xpath/testcases/cbor_base64_encoding/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/cbor_benchmark/expected.out create mode 100644 plugins/parsers/xpath/testcases/cbor_benchmark/message.bin create mode 100644 plugins/parsers/xpath/testcases/cbor_benchmark/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/cbor_hex_encoding/data.bin create mode 100644 plugins/parsers/xpath/testcases/cbor_hex_encoding/expected.out create mode 100644 plugins/parsers/xpath/testcases/cbor_hex_encoding/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/cbor_hex_encoding_explicit/data.bin create mode 100644 plugins/parsers/xpath/testcases/cbor_hex_encoding_explicit/expected.out create mode 100644 plugins/parsers/xpath/testcases/cbor_hex_encoding_explicit/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/cbor_numeric_keys/data.bin create mode 100644 plugins/parsers/xpath/testcases/cbor_numeric_keys/expected.out create mode 100644 plugins/parsers/xpath/testcases/cbor_numeric_keys/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/earthquakes.conf create mode 100644 plugins/parsers/xpath/testcases/earthquakes.quakeml create mode 100644 plugins/parsers/xpath/testcases/field_tag_batch.conf create mode 100644 plugins/parsers/xpath/testcases/field_tag_batch.json create mode 100644 plugins/parsers/xpath/testcases/json_array_expand/expected.out create mode 100644 plugins/parsers/xpath/testcases/json_array_expand/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/json_array_expand/test.json create mode 100644 plugins/parsers/xpath/testcases/json_array_expand_simple_types/expected.out create mode 100644 plugins/parsers/xpath/testcases/json_array_expand_simple_types/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/json_array_expand_simple_types/test.json create mode 100644 plugins/parsers/xpath/testcases/json_array_simple_types/expected.out create mode 100644 plugins/parsers/xpath/testcases/json_array_simple_types/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/json_array_simple_types/test.json create mode 100644 plugins/parsers/xpath/testcases/json_explicit_precedence/expected.out create mode 100644 plugins/parsers/xpath/testcases/json_explicit_precedence/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/json_explicit_precedence/test.json create mode 100644 plugins/parsers/xpath/testcases/json_native_nonnested/expected.out create mode 100644 plugins/parsers/xpath/testcases/json_native_nonnested/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/json_native_nonnested/test.json create mode 100644 plugins/parsers/xpath/testcases/json_string_representation/expected.out create mode 100644 plugins/parsers/xpath/testcases/json_string_representation/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/json_string_representation/test.json create mode 100644 plugins/parsers/xpath/testcases/multisensor.xml create mode 100644 plugins/parsers/xpath/testcases/multisensor_explicit_basic.conf create mode 100644 plugins/parsers/xpath/testcases/multisensor_explicit_batch.conf create mode 100644 plugins/parsers/xpath/testcases/multisensor_selection_batch.conf create mode 100644 plugins/parsers/xpath/testcases/name_expansion/expected.out create mode 100644 plugins/parsers/xpath/testcases/name_expansion/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/name_expansion/test.json create mode 100644 plugins/parsers/xpath/testcases/native_types_cbor/addressbook.bin create mode 100644 plugins/parsers/xpath/testcases/native_types_cbor/expected.out create mode 100644 plugins/parsers/xpath/testcases/native_types_cbor/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/native_types_json/expected.out create mode 100644 plugins/parsers/xpath/testcases/native_types_json/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/native_types_json/test.json create mode 100644 plugins/parsers/xpath/testcases/native_types_msgpack/expected.out create mode 100644 plugins/parsers/xpath/testcases/native_types_msgpack/native_types_json/expected.out create mode 100644 plugins/parsers/xpath/testcases/native_types_msgpack/native_types_json/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/native_types_msgpack/native_types_json/test.json create mode 100644 plugins/parsers/xpath/testcases/native_types_msgpack/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/native_types_msgpack/test.msg create mode 100644 plugins/parsers/xpath/testcases/native_types_protobuf/expected.out create mode 100644 plugins/parsers/xpath/testcases/native_types_protobuf/message.proto create mode 100644 plugins/parsers/xpath/testcases/native_types_protobuf/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/native_types_protobuf/test.dat create mode 100644 plugins/parsers/xpath/testcases/openweathermap_5d.json create mode 100644 plugins/parsers/xpath/testcases/openweathermap_5d.xml create mode 100644 plugins/parsers/xpath/testcases/openweathermap_json.conf create mode 100644 plugins/parsers/xpath/testcases/openweathermap_xml.conf create mode 100644 plugins/parsers/xpath/testcases/protobuf_benchmark/benchmark.proto create mode 100644 plugins/parsers/xpath/testcases/protobuf_benchmark/expected.out create mode 100644 plugins/parsers/xpath/testcases/protobuf_benchmark/message.bin create mode 100644 plugins/parsers/xpath/testcases/protobuf_benchmark/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/protobuf_issue_13715/expected.out create mode 100644 plugins/parsers/xpath/testcases/protobuf_issue_13715/issue.proto create mode 100644 plugins/parsers/xpath/testcases/protobuf_issue_13715/message.bin create mode 100644 plugins/parsers/xpath/testcases/protobuf_issue_13715/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/protobuf_issue_15571/data.json create mode 100644 plugins/parsers/xpath/testcases/protobuf_issue_15571/expected.out create mode 100644 plugins/parsers/xpath/testcases/protobuf_issue_15571/message.bin create mode 100644 plugins/parsers/xpath/testcases/protobuf_issue_15571/port.proto create mode 100644 plugins/parsers/xpath/testcases/protobuf_issue_15571/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/protobuf_issue_15571/telemetry_top.proto create mode 100644 plugins/parsers/xpath/testcases/protobuf_noskip_bytes_grpc/expected.err create mode 100644 plugins/parsers/xpath/testcases/protobuf_noskip_bytes_grpc/message.proto create mode 100644 plugins/parsers/xpath/testcases/protobuf_noskip_bytes_grpc/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/protobuf_noskip_bytes_grpc/test.dat create mode 100644 plugins/parsers/xpath/testcases/protobuf_powerdns_hex/expected.out create mode 100644 plugins/parsers/xpath/testcases/protobuf_powerdns_hex/powerdns_message.bin create mode 100644 plugins/parsers/xpath/testcases/protobuf_powerdns_hex/powerdns_message.proto create mode 100644 plugins/parsers/xpath/testcases/protobuf_powerdns_hex/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/protobuf_skip_bytes_grpc/expected.out create mode 100644 plugins/parsers/xpath/testcases/protobuf_skip_bytes_grpc/message.proto create mode 100644 plugins/parsers/xpath/testcases/protobuf_skip_bytes_grpc/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/protobuf_skip_bytes_grpc/test.dat create mode 100644 plugins/parsers/xpath/testcases/protos/addressbook.proto create mode 100644 plugins/parsers/xpath/testcases/protos/person.proto create mode 100644 plugins/parsers/xpath/testcases/protos/phonenumber.proto create mode 100644 plugins/parsers/xpath/testcases/string_join/expected.out create mode 100644 plugins/parsers/xpath/testcases/string_join/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/string_join/test.json create mode 100644 plugins/parsers/xpath/testcases/time_float_exponential/expected.out create mode 100644 plugins/parsers/xpath/testcases/time_float_exponential/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/time_float_exponential/test.json create mode 100644 plugins/parsers/xpath/testcases/time_timezone_Berlin/expected.out create mode 100644 plugins/parsers/xpath/testcases/time_timezone_Berlin/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/time_timezone_Berlin/test.json create mode 100644 plugins/parsers/xpath/testcases/time_timezone_CEST/expected.out create mode 100644 plugins/parsers/xpath/testcases/time_timezone_CEST/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/time_timezone_CEST/test.json create mode 100644 plugins/parsers/xpath/testcases/time_timezone_MST/expected.out create mode 100644 plugins/parsers/xpath/testcases/time_timezone_MST/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/time_timezone_MST/test.json create mode 100644 plugins/parsers/xpath/testcases/time_timezone_utc/expected.out create mode 100644 plugins/parsers/xpath/testcases/time_timezone_utc/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/time_timezone_utc/test.json create mode 100644 plugins/parsers/xpath/testcases/time_timezone_with_offset/expected.out create mode 100644 plugins/parsers/xpath/testcases/time_timezone_with_offset/telegraf.conf create mode 100644 plugins/parsers/xpath/testcases/time_timezone_with_offset/test.json create mode 100644 plugins/parsers/xpath/testcases/tracker.msg create mode 100644 plugins/parsers/xpath/testcases/tracker_msgpack.conf create mode 100644 plugins/parsers/xpath/xml_document.go create mode 100644 plugins/processors/all/all.go create mode 100644 plugins/processors/all/aws_ec2.go create mode 100644 plugins/processors/all/batch.go create mode 100644 plugins/processors/all/clone.go create mode 100644 plugins/processors/all/converter.go create mode 100644 plugins/processors/all/date.go create mode 100644 plugins/processors/all/dedup.go create mode 100644 plugins/processors/all/defaults.go create mode 100644 plugins/processors/all/enum.go create mode 100644 plugins/processors/all/execd.go create mode 100644 plugins/processors/all/filepath.go create mode 100644 plugins/processors/all/filter.go create mode 100644 plugins/processors/all/ifname.go create mode 100644 plugins/processors/all/lookup.go create mode 100644 plugins/processors/all/noise.go create mode 100644 plugins/processors/all/override.go create mode 100644 plugins/processors/all/parser.go create mode 100644 plugins/processors/all/pivot.go create mode 100644 plugins/processors/all/port_name.go create mode 100644 plugins/processors/all/printer.go create mode 100644 plugins/processors/all/processors.go create mode 100644 plugins/processors/all/regex.go create mode 100644 plugins/processors/all/rename.go create mode 100644 plugins/processors/all/reverse_dns.go create mode 100644 plugins/processors/all/s2geo.go create mode 100644 plugins/processors/all/scale.go create mode 100644 plugins/processors/all/snmp_lookup.go create mode 100644 plugins/processors/all/split.go create mode 100644 plugins/processors/all/starlark.go create mode 100644 plugins/processors/all/strings.go create mode 100644 plugins/processors/all/tag_limit.go create mode 100644 plugins/processors/all/template.go create mode 100644 plugins/processors/all/topk.go create mode 100644 plugins/processors/all/unpivot.go create mode 100644 plugins/processors/aws_ec2/README.md create mode 100644 plugins/processors/aws_ec2/ec2.go create mode 100644 plugins/processors/aws_ec2/ec2_test.go create mode 100644 plugins/processors/aws_ec2/sample.conf create mode 100644 plugins/processors/batch/README.md create mode 100644 plugins/processors/batch/batch.go create mode 100644 plugins/processors/batch/batch_test.go create mode 100644 plugins/processors/batch/sample.conf create mode 100644 plugins/processors/clone/README.md create mode 100644 plugins/processors/clone/clone.go create mode 100644 plugins/processors/clone/clone_test.go create mode 100644 plugins/processors/clone/sample.conf create mode 100644 plugins/processors/converter/README.md create mode 100644 plugins/processors/converter/converter.go create mode 100644 plugins/processors/converter/converter_test.go create mode 100644 plugins/processors/converter/sample.conf create mode 100644 plugins/processors/date/README.md create mode 100644 plugins/processors/date/date.go create mode 100644 plugins/processors/date/date_test.go create mode 100644 plugins/processors/date/sample.conf create mode 100644 plugins/processors/dedup/README.md create mode 100644 plugins/processors/dedup/dedup.go create mode 100644 plugins/processors/dedup/dedup_test.go create mode 100644 plugins/processors/dedup/sample.conf create mode 100644 plugins/processors/defaults/README.md create mode 100644 plugins/processors/defaults/defaults.go create mode 100644 plugins/processors/defaults/defaults_test.go create mode 100644 plugins/processors/defaults/sample.conf create mode 100644 plugins/processors/deprecations.go create mode 100644 plugins/processors/enum/README.md create mode 100644 plugins/processors/enum/enum.go create mode 100644 plugins/processors/enum/enum_test.go create mode 100644 plugins/processors/enum/sample.conf create mode 100644 plugins/processors/execd/README.md create mode 100644 plugins/processors/execd/examples/multiplier_line_protocol/multiplier.conf create mode 100644 plugins/processors/execd/examples/multiplier_line_protocol/multiplier_line_protocol.rb create mode 100644 plugins/processors/execd/execd.go create mode 100644 plugins/processors/execd/execd_test.go create mode 100644 plugins/processors/execd/sample.conf create mode 100644 plugins/processors/execd/testcases/dataformat-influx/expected.out create mode 100644 plugins/processors/execd/testcases/dataformat-influx/input.influx create mode 100644 plugins/processors/execd/testcases/dataformat-influx/telegraf.conf create mode 100644 plugins/processors/execd/testcases/dataformat-json/expected.out create mode 100644 plugins/processors/execd/testcases/dataformat-json/input.influx create mode 100644 plugins/processors/execd/testcases/dataformat-json/telegraf.conf create mode 100644 plugins/processors/execd/testcases/defaults/expected.out create mode 100644 plugins/processors/execd/testcases/defaults/input.influx create mode 100644 plugins/processors/execd/testcases/defaults/telegraf.conf create mode 100644 plugins/processors/execd/testcases/pass-through.go create mode 100644 plugins/processors/filepath/README.md create mode 100644 plugins/processors/filepath/filepath.go create mode 100644 plugins/processors/filepath/filepath_test.go create mode 100644 plugins/processors/filepath/filepath_test_helpers.go create mode 100644 plugins/processors/filepath/filepath_windows_test.go create mode 100644 plugins/processors/filepath/sample.conf create mode 100644 plugins/processors/filter/README.md create mode 100644 plugins/processors/filter/filter.go create mode 100644 plugins/processors/filter/filter_test.go create mode 100644 plugins/processors/filter/rule.go create mode 100644 plugins/processors/filter/sample.conf create mode 100644 plugins/processors/ifname/README.md create mode 100644 plugins/processors/ifname/cache.go create mode 100644 plugins/processors/ifname/cache_test.go create mode 100644 plugins/processors/ifname/ifname.go create mode 100644 plugins/processors/ifname/ifname_test.go create mode 100644 plugins/processors/ifname/sample.conf create mode 100644 plugins/processors/ifname/ttl_cache.go create mode 100644 plugins/processors/ifname/ttl_cache_test.go create mode 100644 plugins/processors/lookup/README.md create mode 100644 plugins/processors/lookup/lookup.go create mode 100644 plugins/processors/lookup/lookup_test.go create mode 100644 plugins/processors/lookup/sample.conf create mode 100644 plugins/processors/lookup/testcases/multiple_files_json/expected.out create mode 100644 plugins/processors/lookup/testcases/multiple_files_json/input.influx create mode 100644 plugins/processors/lookup/testcases/multiple_files_json/lut_hugin.json create mode 100644 plugins/processors/lookup/testcases/multiple_files_json/lut_munin.json create mode 100644 plugins/processors/lookup/testcases/multiple_files_json/lut_thor.json create mode 100644 plugins/processors/lookup/testcases/multiple_files_json/telegraf.conf create mode 100644 plugins/processors/lookup/testcases/non_existing_tag/expected.out create mode 100644 plugins/processors/lookup/testcases/non_existing_tag/input.influx create mode 100644 plugins/processors/lookup/testcases/non_existing_tag/lut.json create mode 100644 plugins/processors/lookup/testcases/non_existing_tag/telegraf.conf create mode 100644 plugins/processors/lookup/testcases/normal_lookup_csv_key_name_value/expected.out create mode 100644 plugins/processors/lookup/testcases/normal_lookup_csv_key_name_value/input.influx create mode 100644 plugins/processors/lookup/testcases/normal_lookup_csv_key_name_value/lut.csv create mode 100644 plugins/processors/lookup/testcases/normal_lookup_csv_key_name_value/telegraf.conf create mode 100644 plugins/processors/lookup/testcases/normal_lookup_csv_key_values/expected.out create mode 100644 plugins/processors/lookup/testcases/normal_lookup_csv_key_values/input.influx create mode 100644 plugins/processors/lookup/testcases/normal_lookup_csv_key_values/lut.csv create mode 100644 plugins/processors/lookup/testcases/normal_lookup_csv_key_values/telegraf.conf create mode 100644 plugins/processors/lookup/testcases/normal_lookup_json/expected.out create mode 100644 plugins/processors/lookup/testcases/normal_lookup_json/input.influx create mode 100644 plugins/processors/lookup/testcases/normal_lookup_json/lut.json create mode 100644 plugins/processors/lookup/testcases/normal_lookup_json/telegraf.conf create mode 100644 plugins/processors/noise/README.md create mode 100644 plugins/processors/noise/noise.go create mode 100644 plugins/processors/noise/noise_test.go create mode 100644 plugins/processors/noise/sample.conf create mode 100644 plugins/processors/override/README.md create mode 100644 plugins/processors/override/override.go create mode 100644 plugins/processors/override/override_test.go create mode 100644 plugins/processors/override/sample.conf create mode 100644 plugins/processors/parser/README.md create mode 100644 plugins/processors/parser/parser.go create mode 100644 plugins/processors/parser/parser_test.go create mode 100644 plugins/processors/parser/sample.conf create mode 100644 plugins/processors/pivot/README.md create mode 100644 plugins/processors/pivot/pivot.go create mode 100644 plugins/processors/pivot/pivot_test.go create mode 100644 plugins/processors/pivot/sample.conf create mode 100644 plugins/processors/port_name/README.md create mode 100644 plugins/processors/port_name/port_name.go create mode 100644 plugins/processors/port_name/port_name_test.go create mode 100644 plugins/processors/port_name/sample.conf create mode 100644 plugins/processors/port_name/services_path.go create mode 100644 plugins/processors/port_name/services_path_notwindows.go create mode 100644 plugins/processors/printer/README.md create mode 100644 plugins/processors/printer/printer.go create mode 100644 plugins/processors/printer/printer_test.go create mode 100644 plugins/processors/printer/sample.conf create mode 100644 plugins/processors/regex/README.md create mode 100644 plugins/processors/regex/converter.go create mode 100644 plugins/processors/regex/regex.go create mode 100644 plugins/processors/regex/regex_test.go create mode 100644 plugins/processors/regex/sample.conf create mode 100644 plugins/processors/registry.go create mode 100644 plugins/processors/rename/README.md create mode 100644 plugins/processors/rename/rename.go create mode 100644 plugins/processors/rename/rename_test.go create mode 100644 plugins/processors/rename/sample.conf create mode 100644 plugins/processors/reverse_dns/README.md create mode 100644 plugins/processors/reverse_dns/rdnscache.go create mode 100644 plugins/processors/reverse_dns/rdnscache_test.go create mode 100644 plugins/processors/reverse_dns/reverse_dns.go create mode 100644 plugins/processors/reverse_dns/reverse_dns_test.go create mode 100644 plugins/processors/reverse_dns/sample.conf create mode 100644 plugins/processors/s2geo/README.md create mode 100644 plugins/processors/s2geo/s2geo.go create mode 100644 plugins/processors/s2geo/s2geo_test.go create mode 100644 plugins/processors/s2geo/sample.conf create mode 100644 plugins/processors/scale/README.md create mode 100644 plugins/processors/scale/sample.conf create mode 100644 plugins/processors/scale/scale.go create mode 100644 plugins/processors/scale/scale_test.go create mode 100644 plugins/processors/snmp_lookup/README.md create mode 100644 plugins/processors/snmp_lookup/backlog.go create mode 100644 plugins/processors/snmp_lookup/lookup.go create mode 100644 plugins/processors/snmp_lookup/lookup_test.go create mode 100644 plugins/processors/snmp_lookup/sample.conf create mode 100644 plugins/processors/snmp_lookup/store.go create mode 100644 plugins/processors/snmp_lookup/store_test.go create mode 100644 plugins/processors/split/README.md create mode 100644 plugins/processors/split/sample.conf create mode 100644 plugins/processors/split/split.go create mode 100644 plugins/processors/split/split_test.go create mode 100644 plugins/processors/split/testcases/drop_original/config.toml create mode 100644 plugins/processors/split/testcases/drop_original/expected.out create mode 100644 plugins/processors/split/testcases/drop_original/input.influx create mode 100644 plugins/processors/split/testcases/globs/config.toml create mode 100644 plugins/processors/split/testcases/globs/expected.out create mode 100644 plugins/processors/split/testcases/globs/input.influx create mode 100644 plugins/processors/split/testcases/nomatches/config.toml create mode 100644 plugins/processors/split/testcases/nomatches/expected.out create mode 100644 plugins/processors/split/testcases/nomatches/input.influx create mode 100644 plugins/processors/split/testcases/singlemetric/config.toml create mode 100644 plugins/processors/split/testcases/singlemetric/expected.out create mode 100644 plugins/processors/split/testcases/singlemetric/input.influx create mode 100644 plugins/processors/split/testcases/tags/config.toml create mode 100644 plugins/processors/split/testcases/tags/expected.out create mode 100644 plugins/processors/split/testcases/tags/input.influx create mode 100644 plugins/processors/starlark/README.md create mode 100644 plugins/processors/starlark/sample.conf create mode 100644 plugins/processors/starlark/starlark.go create mode 100644 plugins/processors/starlark/starlark_test.go create mode 100644 plugins/processors/starlark/testdata/compare_metrics.star create mode 100644 plugins/processors/starlark/testdata/drop_fields_with_unexpected_type.star create mode 100644 plugins/processors/starlark/testdata/drop_string_fields.star create mode 100644 plugins/processors/starlark/testdata/fail.star create mode 100644 plugins/processors/starlark/testdata/iops.star create mode 100644 plugins/processors/starlark/testdata/json.star create mode 100644 plugins/processors/starlark/testdata/json_nested.star create mode 100644 plugins/processors/starlark/testdata/logging.star create mode 100644 plugins/processors/starlark/testdata/math.star create mode 100644 plugins/processors/starlark/testdata/multiple_metrics.star create mode 100644 plugins/processors/starlark/testdata/multiple_metrics_with_json.star create mode 100644 plugins/processors/starlark/testdata/number_logic.star create mode 100644 plugins/processors/starlark/testdata/pivot.star create mode 100644 plugins/processors/starlark/testdata/ratio.star create mode 100644 plugins/processors/starlark/testdata/rename.star create mode 100644 plugins/processors/starlark/testdata/rename_prometheus_remote_write.star create mode 100644 plugins/processors/starlark/testdata/scale.star create mode 100644 plugins/processors/starlark/testdata/schema_sizing.star create mode 100644 plugins/processors/starlark/testdata/sparkplug.star create mode 100644 plugins/processors/starlark/testdata/time_date.star create mode 100644 plugins/processors/starlark/testdata/time_duration.star create mode 100644 plugins/processors/starlark/testdata/time_set_timestamp.star create mode 100644 plugins/processors/starlark/testdata/time_timestamp.star create mode 100644 plugins/processors/starlark/testdata/time_timestamp_nanos.star create mode 100644 plugins/processors/starlark/testdata/value_filter.star create mode 100644 plugins/processors/streamingprocessor.go create mode 100644 plugins/processors/strings/README.md create mode 100644 plugins/processors/strings/sample.conf create mode 100644 plugins/processors/strings/strings.go create mode 100644 plugins/processors/strings/strings_test.go create mode 100644 plugins/processors/tag_limit/README.md create mode 100644 plugins/processors/tag_limit/sample.conf create mode 100644 plugins/processors/tag_limit/tag_limit.go create mode 100644 plugins/processors/tag_limit/tag_limit_test.go create mode 100644 plugins/processors/template/README.md create mode 100644 plugins/processors/template/sample.conf create mode 100644 plugins/processors/template/template.go create mode 100644 plugins/processors/template/template_metric.go create mode 100644 plugins/processors/template/template_test.go create mode 100644 plugins/processors/timestamp/README.md create mode 100644 plugins/processors/timestamp/sample.conf create mode 100644 plugins/processors/timestamp/timestamp.go create mode 100644 plugins/processors/timestamp/timestamp_test.go create mode 100644 plugins/processors/topk/README.md create mode 100644 plugins/processors/topk/sample.conf create mode 100644 plugins/processors/topk/test_sets.go create mode 100644 plugins/processors/topk/topk.go create mode 100644 plugins/processors/topk/topk_test.go create mode 100644 plugins/processors/unpivot/README.md create mode 100644 plugins/processors/unpivot/sample.conf create mode 100644 plugins/processors/unpivot/unpivot.go create mode 100644 plugins/processors/unpivot/unpivot_test.go create mode 100644 plugins/secretstores/README.md create mode 100644 plugins/secretstores/all/all.go create mode 100644 plugins/secretstores/all/docker.go create mode 100644 plugins/secretstores/all/http.go create mode 100644 plugins/secretstores/all/jose.go create mode 100644 plugins/secretstores/all/oauth2.go create mode 100644 plugins/secretstores/all/os.go create mode 100644 plugins/secretstores/all/systemd.go create mode 100644 plugins/secretstores/deprecations.go create mode 100644 plugins/secretstores/docker/README.md create mode 100644 plugins/secretstores/docker/docker.go create mode 100644 plugins/secretstores/docker/docker_test.go create mode 100644 plugins/secretstores/docker/sample.conf create mode 100644 plugins/secretstores/docker/testdata/secret-file-1 create mode 100644 plugins/secretstores/docker/testdata/secretFile create mode 100644 plugins/secretstores/docker/testdata/secret_file_2 create mode 100644 plugins/secretstores/http/README.md create mode 100644 plugins/secretstores/http/aes.go create mode 100644 plugins/secretstores/http/aes_test.go create mode 100644 plugins/secretstores/http/decryption.go create mode 100644 plugins/secretstores/http/decryption_test.go create mode 100644 plugins/secretstores/http/http.go create mode 100644 plugins/secretstores/http/http_test.go create mode 100644 plugins/secretstores/http/key_derivation.go create mode 100644 plugins/secretstores/http/key_derivation_test.go create mode 100644 plugins/secretstores/http/sample.conf create mode 100644 plugins/secretstores/http/testcases/aes-cbc-kdf/expected.json create mode 100644 plugins/secretstores/http/testcases/aes-cbc-kdf/secrets.json create mode 100644 plugins/secretstores/http/testcases/aes-cbc-kdf/telegraf.conf create mode 100644 plugins/secretstores/http/testcases/aes-cbc-key/expected.json create mode 100644 plugins/secretstores/http/testcases/aes-cbc-key/secrets.json create mode 100644 plugins/secretstores/http/testcases/aes-cbc-key/telegraf.conf create mode 100644 plugins/secretstores/http/testcases/mixed/expected.json create mode 100644 plugins/secretstores/http/testcases/mixed/secrets.json create mode 100644 plugins/secretstores/http/testcases/mixed/telegraf.conf create mode 100644 plugins/secretstores/http/testcases/plain-list-complex/expected.json create mode 100644 plugins/secretstores/http/testcases/plain-list-complex/secrets.json create mode 100644 plugins/secretstores/http/testcases/plain-list-complex/telegraf.conf create mode 100644 plugins/secretstores/http/testcases/plain-list-simple/expected.json create mode 100644 plugins/secretstores/http/testcases/plain-list-simple/secrets.json create mode 100644 plugins/secretstores/http/testcases/plain-list-simple/telegraf.conf create mode 100644 plugins/secretstores/http/testcases/plain-no-transform/expected.json create mode 100644 plugins/secretstores/http/testcases/plain-no-transform/secrets.json create mode 100644 plugins/secretstores/http/testcases/plain-no-transform/telegraf.conf create mode 100644 plugins/secretstores/jose/README.md create mode 100644 plugins/secretstores/jose/jose.go create mode 100644 plugins/secretstores/jose/jose_test.go create mode 100644 plugins/secretstores/jose/sample.conf create mode 100644 plugins/secretstores/oauth2/README.md create mode 100644 plugins/secretstores/oauth2/oauth2.go create mode 100644 plugins/secretstores/oauth2/oauth2_test.go create mode 100644 plugins/secretstores/oauth2/sample.conf create mode 100644 plugins/secretstores/os/README.md create mode 100644 plugins/secretstores/os/os.go create mode 100644 plugins/secretstores/os/os_darwin.go create mode 100644 plugins/secretstores/os/os_linux.go create mode 100644 plugins/secretstores/os/os_test.go create mode 100644 plugins/secretstores/os/os_unsupported.go create mode 100644 plugins/secretstores/os/os_windows.go create mode 100644 plugins/secretstores/os/sample.conf create mode 100644 plugins/secretstores/registry.go create mode 100644 plugins/secretstores/systemd/README.md create mode 100644 plugins/secretstores/systemd/sample.conf create mode 100644 plugins/secretstores/systemd/systemd.go create mode 100644 plugins/secretstores/systemd/systemd_nonlinux.go create mode 100644 plugins/secretstores/systemd/systemd_test.go create mode 100644 plugins/secretstores/systemd/testdata/secret-file-1 create mode 100644 plugins/secretstores/systemd/testdata/secretFile create mode 100644 plugins/secretstores/systemd/testdata/secret_file_2 create mode 100644 plugins/serializers/EXAMPLE_README.md create mode 100644 plugins/serializers/all/all.go create mode 100644 plugins/serializers/all/binary.go create mode 100644 plugins/serializers/all/carbon2.go create mode 100644 plugins/serializers/all/cloudevents.go create mode 100644 plugins/serializers/all/csv.go create mode 100644 plugins/serializers/all/graphite.go create mode 100644 plugins/serializers/all/influx.go create mode 100644 plugins/serializers/all/json.go create mode 100644 plugins/serializers/all/msgpack.go create mode 100644 plugins/serializers/all/nowmetric.go create mode 100644 plugins/serializers/all/prometheus.go create mode 100644 plugins/serializers/all/prometheusremotewrite.go create mode 100644 plugins/serializers/all/splunkmetric.go create mode 100644 plugins/serializers/all/template.go create mode 100644 plugins/serializers/all/wavefront.go create mode 100644 plugins/serializers/binary/README.md create mode 100644 plugins/serializers/binary/binary.go create mode 100644 plugins/serializers/binary/binary_test.go create mode 100644 plugins/serializers/binary/entry.go create mode 100644 plugins/serializers/binary/entry_test.go create mode 100644 plugins/serializers/binary/type_conversions.go create mode 100644 plugins/serializers/carbon2/README.md create mode 100644 plugins/serializers/carbon2/carbon2.go create mode 100644 plugins/serializers/carbon2/carbon2_test.go create mode 100644 plugins/serializers/cloudevents/README.md create mode 100644 plugins/serializers/cloudevents/cloudevents.go create mode 100644 plugins/serializers/cloudevents/cloudevents_test.go create mode 100644 plugins/serializers/cloudevents/testcases/batch-events/expected.json create mode 100644 plugins/serializers/cloudevents/testcases/batch-events/input.influx create mode 100644 plugins/serializers/cloudevents/testcases/batch-events/telegraf.conf create mode 100644 plugins/serializers/cloudevents/testcases/batch-metrics/expected.json create mode 100644 plugins/serializers/cloudevents/testcases/batch-metrics/input.influx create mode 100644 plugins/serializers/cloudevents/testcases/batch-metrics/telegraf.conf create mode 100644 plugins/serializers/cloudevents/testcases/cloudevents-v0.3-schema.json create mode 100644 plugins/serializers/cloudevents/testcases/cloudevents-v1.0-schema.json create mode 100644 plugins/serializers/cloudevents/testcases/single-multiple/expected.json create mode 100644 plugins/serializers/cloudevents/testcases/single-multiple/input.influx create mode 100644 plugins/serializers/cloudevents/testcases/single-multiple/telegraf.conf create mode 100644 plugins/serializers/cloudevents/testcases/single-source-overwrite/expected.json create mode 100644 plugins/serializers/cloudevents/testcases/single-source-overwrite/input.influx create mode 100644 plugins/serializers/cloudevents/testcases/single-source-overwrite/telegraf.conf create mode 100644 plugins/serializers/cloudevents/testcases/single-sourcetag-overwrite/expected.json create mode 100644 plugins/serializers/cloudevents/testcases/single-sourcetag-overwrite/input.influx create mode 100644 plugins/serializers/cloudevents/testcases/single-sourcetag-overwrite/telegraf.conf create mode 100644 plugins/serializers/cloudevents/testcases/single/expected.json create mode 100644 plugins/serializers/cloudevents/testcases/single/input.influx create mode 100644 plugins/serializers/cloudevents/testcases/single/telegraf.conf create mode 100644 plugins/serializers/csv/README.md create mode 100644 plugins/serializers/csv/csv.go create mode 100644 plugins/serializers/csv/csv_test.go create mode 100644 plugins/serializers/csv/testcases/basic.conf create mode 100644 plugins/serializers/csv/testcases/basic.csv create mode 100644 plugins/serializers/csv/testcases/header.conf create mode 100644 plugins/serializers/csv/testcases/header.csv create mode 100644 plugins/serializers/csv/testcases/nanoseconds.conf create mode 100644 plugins/serializers/csv/testcases/nanoseconds.csv create mode 100644 plugins/serializers/csv/testcases/ordered.conf create mode 100644 plugins/serializers/csv/testcases/ordered.csv create mode 100644 plugins/serializers/csv/testcases/ordered_not_exist.conf create mode 100644 plugins/serializers/csv/testcases/ordered_not_exist.csv create mode 100644 plugins/serializers/csv/testcases/ordered_with_header.conf create mode 100644 plugins/serializers/csv/testcases/ordered_with_header.csv create mode 100644 plugins/serializers/csv/testcases/ordered_with_header_prefix.conf create mode 100644 plugins/serializers/csv/testcases/ordered_with_header_prefix.csv create mode 100644 plugins/serializers/csv/testcases/prefix.conf create mode 100644 plugins/serializers/csv/testcases/prefix.csv create mode 100644 plugins/serializers/csv/testcases/rfc3339.conf create mode 100644 plugins/serializers/csv/testcases/rfc3339.csv create mode 100644 plugins/serializers/csv/testcases/semicolon.conf create mode 100644 plugins/serializers/csv/testcases/semicolon.csv create mode 100644 plugins/serializers/deprecations.go create mode 100644 plugins/serializers/graphite/README.md create mode 100644 plugins/serializers/graphite/graphite.go create mode 100644 plugins/serializers/graphite/graphite_test.go create mode 100644 plugins/serializers/influx/README.md create mode 100644 plugins/serializers/influx/escape.go create mode 100644 plugins/serializers/influx/influx.go create mode 100644 plugins/serializers/influx/influx_test.go create mode 100644 plugins/serializers/influx/reader.go create mode 100644 plugins/serializers/influx/reader_test.go create mode 100644 plugins/serializers/json/README.md create mode 100644 plugins/serializers/json/json.go create mode 100644 plugins/serializers/json/json_test.go create mode 100644 plugins/serializers/json/testcases/nested_fields_exclude.conf create mode 100644 plugins/serializers/json/testcases/nested_fields_include.conf create mode 100644 plugins/serializers/json/testcases/nested_fields_out.json create mode 100644 plugins/serializers/json/testcases/transformation_batch.conf create mode 100644 plugins/serializers/json/testcases/transformation_batch_out.json create mode 100644 plugins/serializers/json/testcases/transformation_single.conf create mode 100644 plugins/serializers/json/testcases/transformation_single_out.json create mode 100644 plugins/serializers/msgpack/README.md create mode 100644 plugins/serializers/msgpack/metric.go create mode 100644 plugins/serializers/msgpack/metric_gen.go create mode 100644 plugins/serializers/msgpack/metric_gen_test.go create mode 100644 plugins/serializers/msgpack/metric_test.go create mode 100644 plugins/serializers/msgpack/msgpack.go create mode 100644 plugins/serializers/msgpack/msgpack_test.go create mode 100644 plugins/serializers/nowmetric/README.md create mode 100644 plugins/serializers/nowmetric/nowmetric.go create mode 100644 plugins/serializers/nowmetric/nowmetric_test.go create mode 100644 plugins/serializers/prometheus/README.md create mode 100644 plugins/serializers/prometheus/collection.go create mode 100644 plugins/serializers/prometheus/collection_test.go create mode 100644 plugins/serializers/prometheus/convert.go create mode 100644 plugins/serializers/prometheus/prometheus.go create mode 100644 plugins/serializers/prometheus/prometheus_test.go create mode 100644 plugins/serializers/prometheusremotewrite/README.md create mode 100644 plugins/serializers/prometheusremotewrite/prometheusremotewrite.go create mode 100644 plugins/serializers/prometheusremotewrite/prometheusremotewrite_test.go create mode 100644 plugins/serializers/registry.go create mode 100644 plugins/serializers/splunkmetric/README.md create mode 100644 plugins/serializers/splunkmetric/splunkmetric.go create mode 100644 plugins/serializers/splunkmetric/splunkmetric_test.go create mode 100644 plugins/serializers/template/README.md create mode 100644 plugins/serializers/template/template.go create mode 100644 plugins/serializers/template/template_test.go create mode 100644 plugins/serializers/test_benchmark.go create mode 100644 plugins/serializers/wavefront/README.md create mode 100644 plugins/serializers/wavefront/replacers.go create mode 100644 plugins/serializers/wavefront/wavefront.go create mode 100644 plugins/serializers/wavefront/wavefront_test.go create mode 100644 processor.go create mode 100755 scripts/check-deps.sh create mode 100755 scripts/check-file-changes.sh create mode 100755 scripts/check-plugin-doc-embedding.sh create mode 100644 scripts/ci.docker create mode 100644 scripts/deb/post-install.sh create mode 100644 scripts/deb/post-remove.sh create mode 100644 scripts/deb/pre-install.sh create mode 100644 scripts/deb/pre-remove.sh create mode 100755 scripts/init.sh create mode 100755 scripts/install_gotestsum.sh create mode 100755 scripts/install_incus.sh create mode 100644 scripts/installgo_linux.sh create mode 100644 scripts/installgo_mac.sh create mode 100644 scripts/installgo_windows.sh create mode 100755 scripts/local_circleci.sh create mode 100644 scripts/mac-signing.sh create mode 100755 scripts/make_docs.sh create mode 100644 scripts/rpm/post-install.sh create mode 100644 scripts/rpm/post-remove.sh create mode 100644 scripts/rpm/pre-install.sh create mode 100755 scripts/sign-windows.sh create mode 100644 scripts/telegraf.service create mode 100644 scripts/telegraf_entry_mac create mode 100755 scripts/windows-gen-syso.sh create mode 100644 secretstore.go create mode 100644 selfstat/selfstat.go create mode 100644 selfstat/selfstat_test.go create mode 100644 selfstat/stat.go create mode 100644 selfstat/timingStat.go create mode 100644 serializer.go create mode 100644 testutil/accumulator.go create mode 100644 testutil/capturelog.go create mode 100644 testutil/container.go create mode 100644 testutil/container_test.go create mode 100644 testutil/file.go create mode 100644 testutil/log.go create mode 100644 testutil/metric.go create mode 100644 testutil/metric_test.go create mode 100644 testutil/pki/cacert.pem create mode 100644 testutil/pki/cakey.pem create mode 100644 testutil/pki/client.pem create mode 100644 testutil/pki/clientcert.pem create mode 100644 testutil/pki/clientenc.pem create mode 100644 testutil/pki/clientenckey.pem create mode 100644 testutil/pki/clientenckey.pkcs8.pem create mode 100644 testutil/pki/clientkey.pem create mode 100644 testutil/pki/clientkey.pkcs8.pem create mode 100644 testutil/pki/server.pem create mode 100644 testutil/pki/servercert.pem create mode 100644 testutil/pki/serverkey.pem create mode 100644 testutil/pki/tls-certs.sh create mode 100644 testutil/plugin_input/plugin.go create mode 100644 testutil/plugin_input/sample.conf create mode 100644 testutil/socket.go create mode 100644 testutil/testutil.go create mode 100644 testutil/testutil_test.go create mode 100644 testutil/tls.go create mode 100644 tools/config_includer/generator.go create mode 100644 tools/custom_builder/README.md create mode 100644 tools/custom_builder/config.go create mode 100644 tools/custom_builder/main.go create mode 100644 tools/custom_builder/main_test.go create mode 100644 tools/custom_builder/packages.go create mode 100644 tools/custom_builder/testcases/issue_13592/expected.tags create mode 100644 tools/custom_builder/testcases/issue_13592/telegraf.conf create mode 100644 tools/custom_builder/testcases/issue_15627/expected.tags create mode 100644 tools/custom_builder/testcases/issue_15627/telegraf.conf create mode 100644 tools/license_checker/README.md create mode 100644 tools/license_checker/data/spdx_mapping.json create mode 100644 tools/license_checker/data/whitelist create mode 100644 tools/license_checker/main.go create mode 100644 tools/license_checker/package.go create mode 100644 tools/license_checker/whitelist.go create mode 100644 tools/package_incus_test/README.md create mode 100644 tools/package_incus_test/container.go create mode 100644 tools/package_incus_test/incus.go create mode 100644 tools/package_incus_test/main.go create mode 100644 tools/readme_config_includer/generator.go create mode 100644 tools/readme_linter/README.md create mode 100644 tools/readme_linter/assert.go create mode 100644 tools/readme_linter/main.go create mode 100644 tools/readme_linter/plugin.go create mode 100644 tools/readme_linter/rules.go create mode 100644 tools/readme_linter/set.go create mode 100644 tools/update_goversion/README.md create mode 100644 tools/update_goversion/main.go create mode 100644 tools/update_goversion/main_test.go create mode 100644 tools/update_goversion/testdata/godev_minor.html create mode 100644 tools/update_goversion/testdata/godev_patch.html diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..2439e98 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,885 @@ +version: 2.1 +orbs: + win: circleci/windows@5.0.0 + aws-cli: circleci/aws-cli@3.1.1 + +executors: + telegraf-ci: + working_directory: '/go/src/github.com/influxdata/telegraf' + resource_class: large + docker: + - image: 'quay.io/influxdb/telegraf-ci:1.24.3' + environment: + GOFLAGS: -p=4 + mac: + working_directory: '~/go/src/github.com/influxdata/telegraf' + resource_class: macos.m1.medium.gen1 + macos: + xcode: 15.4.0 + environment: + HOMEBREW_NO_AUTO_UPDATE: 1 + GOFLAGS: -p=4 + +commands: + check-changed-files-or-halt: + steps: + - run: ./scripts/check-file-changes.sh + test-go: + parameters: + os: + type: string + default: "linux" + arch: + type: string + default: "amd64" + gotestsum: + type: string + default: "gotestsum" + steps: + - run: ./scripts/install_gotestsum.sh << parameters.os >> << parameters.gotestsum >> + - unless: + condition: + equal: [ "386", << parameters.arch >> ] + steps: + - run: echo 'export RACE="-race"' >> $BASH_ENV + - when: + condition: + equal: [ windows, << parameters.os >> ] + steps: + - run: echo 'export CGO_ENABLED=1' >> $BASH_ENV + - when: + condition: + equal: [ darwin, << parameters.os >> ] + steps: + - run: echo 'export RACE="$RACE -ldflags=-extldflags=-Wl,-ld_classic"' >> $BASH_ENV + - run: | + GOARCH=<< parameters.arch >> ./<< parameters.gotestsum >> -- ${RACE} -short ./... + package-build: + parameters: + type: + type: string + default: "" + nightly: + type: boolean + default: false + steps: + - checkout + - check-changed-files-or-halt + - attach_workspace: + at: '/go' + - when: + condition: + equal: [ windows, << parameters.type >> ] + steps: + - run: go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@v1.4.0 + - when: + condition: << parameters.nightly >> + steps: + - run: + command: 'NIGHTLY=1 make package include_packages="$(make << parameters.type >>)"' + no_output_timeout: 30m + - unless: + condition: + or: + - << parameters.nightly >> + steps: + - run: + command: 'make package include_packages="$(make << parameters.type >>)"' + no_output_timeout: 30m + - store_artifacts: + path: './build/dist' + destination: 'build/dist' + - persist_to_workspace: + root: './build' + paths: + - 'dist' +jobs: + lint-linux: + executor: telegraf-ci + steps: + - checkout + - run: ./scripts/make_docs.sh + - check-changed-files-or-halt + - run: 'make deps' + - run: 'make tidy' + - run: 'make check' + - run: 'make check-deps' + - run: + name: "Install golangci-lint" + command: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.2 + - run: + name: "golangci-lint/Linux" + # There are only 4 vCPUs available for this executor, so use only 4 instead of the default number + # (the OS may report the number of CPUs on the host instead of the number of CPUs available to the guest). + command: GOGC=80 GOMEMLIMIT=6144MiB /go/bin/golangci-lint run --verbose --timeout=30m --concurrency 4 + no_output_timeout: 30m + lint-macos: + executor: telegraf-ci + steps: + - checkout + - check-changed-files-or-halt + - run: + name: "Install golangci-lint" + command: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.2 + - run: + name: "golangci-lint/macOS" + # There are only 4 vCPUs available for this executor, so use only 4 instead of the default number + # (the OS may report the number of CPUs on the host instead of the number of CPUs available to the guest). + command: GOGC=80 GOMEMLIMIT=6144MiB GOOS=darwin /go/bin/golangci-lint run --verbose --timeout=30m --concurrency 4 + no_output_timeout: 30m + lint-windows: + executor: telegraf-ci + steps: + - checkout + - check-changed-files-or-halt + - run: + name: "Install golangci-lint" + command: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.2 + - run: + name: "golangci-lint/Windows" + # There are only 4 vCPUs available for this executor, so use only 4 instead of the default number + # (the OS may report the number of CPUs on the host instead of the number of CPUs available to the guest). + command: GOGC=80 GOMEMLIMIT=6144MiB GOOS=windows /go/bin/golangci-lint run --verbose --timeout=30m --concurrency 4 + no_output_timeout: 30m + test-go-linux: + executor: telegraf-ci + steps: + - checkout + - check-changed-files-or-halt + - test-go + test-go-linux-386: + executor: telegraf-ci + steps: + - checkout + - check-changed-files-or-halt + - run: 'GOARCH=386 make deps' + - run: 'GOARCH=386 make tidy' + - run: 'GOARCH=386 make check' + - test-go: + arch: "386" + test-integration: + machine: + image: ubuntu-2204:current + resource_class: large + steps: + - checkout + - check-changed-files-or-halt + - run: 'sh ./scripts/installgo_linux.sh' + - run: 'make deps' + - run: + name: "Run integration tests" + command: make test-integration + environment: + AZURE_EVENT_HUBS_EMULATOR_ACCEPT_EULA: yes + test-go-mac: + executor: mac + steps: + - checkout + - check-changed-files-or-halt + - run: 'sh ./scripts/installgo_mac.sh' + - test-go: + os: darwin + arch: arm64 + test-go-windows: + executor: + name: win/default + shell: bash.exe + size: large + steps: + - checkout + - check-changed-files-or-halt + - run: git config --system core.longpaths true + - run: choco feature enable -n allowGlobalConfirmation + - run: 'sh ./scripts/installgo_windows.sh' + - run: choco install mingw + - run: echo 'export PATH="$PATH:/c/ProgramData/mingw64/mingw64/bin"' >> $BASH_ENV + - test-go: + os: windows + gotestsum: "gotestsum.exe" + test-licenses: + executor: telegraf-ci + steps: + - checkout + - check-changed-files-or-halt + - run: 'make build_tools' + - run: './tools/license_checker/license_checker -whitelist ./tools/license_checker/data/whitelist' + windows-package: + parameters: + nightly: + type: boolean + default: false + executor: telegraf-ci + steps: + - package-build: + type: windows + nightly: << parameters.nightly >> + darwin-amd64-package: + parameters: + nightly: + type: boolean + default: false + executor: telegraf-ci + steps: + - package-build: + type: darwin-amd64 + nightly: << parameters.nightly >> + darwin-arm64-package: + parameters: + nightly: + type: boolean + default: false + executor: telegraf-ci + steps: + - package-build: + type: darwin-arm64 + nightly: << parameters.nightly >> + i386-package: + parameters: + nightly: + type: boolean + default: false + executor: telegraf-ci + steps: + - package-build: + type: i386 + nightly: << parameters.nightly >> + ppc64le-package: + parameters: + nightly: + type: boolean + default: false + executor: telegraf-ci + steps: + - package-build: + type: ppc64le + nightly: << parameters.nightly >> + riscv64-package: + parameters: + nightly: + type: boolean + default: false + executor: telegraf-ci + steps: + - package-build: + type: riscv64 + nightly: << parameters.nightly >> + loong64-package: + parameters: + nightly: + type: boolean + default: false + executor: telegraf-ci + steps: + - package-build: + type: loong64 + nightly: << parameters.nightly >> + s390x-package: + parameters: + nightly: + type: boolean + default: false + executor: telegraf-ci + steps: + - package-build: + type: s390x + nightly: << parameters.nightly >> + armel-package: + parameters: + nightly: + type: boolean + default: false + executor: telegraf-ci + steps: + - package-build: + type: armel + nightly: << parameters.nightly >> + amd64-package: + parameters: + nightly: + type: boolean + default: false + executor: telegraf-ci + steps: + - package-build: + type: amd64 + nightly: << parameters.nightly >> + arm64-package: + parameters: + nightly: + type: boolean + default: false + executor: telegraf-ci + steps: + - package-build: + type: arm64 + nightly: << parameters.nightly >> + mipsel-package: + parameters: + nightly: + type: boolean + default: false + executor: telegraf-ci + steps: + - package-build: + type: mipsel + nightly: << parameters.nightly >> + mips-package: + parameters: + nightly: + type: boolean + default: false + executor: telegraf-ci + steps: + - package-build: + type: mips + nightly: << parameters.nightly >> + armhf-package: + parameters: + nightly: + type: boolean + default: false + executor: telegraf-ci + steps: + - package-build: + type: armhf + nightly: << parameters.nightly >> + nightly: + executor: telegraf-ci + steps: + - attach_workspace: + at: '/build' + - run: + command: | + aws s3 sync /build/dist s3://dl.influxdata.com/telegraf/nightlies/ \ + --exclude "*" \ + --include "*.tar.gz" \ + --include "*.deb" \ + --include "*.rpm" \ + --include "*.zip" \ + --acl public-read + release: + executor: telegraf-ci + steps: + - attach_workspace: + at: '/build' + - run: + command: | + aws s3 sync /build/dist s3://dl.influxdata.com/telegraf/releases/ \ + --exclude "*" \ + --include "telegraf*.DIGESTS" \ + --include "telegraf*.digests" \ + --include "telegraf*.asc" \ + --include "telegraf*.deb" \ + --include "telegraf*.dmg" \ + --include "telegraf*.rpm" \ + --include "telegraf*.tar.gz" \ + --include "telegraf*.zip" \ + --acl public-read + docker-nightly: + machine: + image: ubuntu-2204:current + steps: + - run: + name: login to quay.io + command: docker login --username="${QUAY_USER}" --password="${QUAY_PASS}" quay.io + - run: + name: clone influxdata/influxdata-docker + command: git clone https://github.com/influxdata/influxdata-docker + - run: + name: build and push telegraf:nightly + command: | + cd influxdata-docker/telegraf/nightly + docker build -t telegraf . + docker tag telegraf quay.io/influxdb/telegraf-nightly:latest + docker image ls + docker push quay.io/influxdb/telegraf-nightly:latest + - run: + name: build and push telegraf:nightly-alpine + command: | + cd influxdata-docker/telegraf/nightly/alpine + docker build -t telegraf-alpine . + docker tag telegraf-alpine quay.io/influxdb/telegraf-nightly:alpine + docker image ls + docker push quay.io/influxdb/telegraf-nightly:alpine + amd64-package-test-nightly: + machine: + image: ubuntu-2204:current + steps: + - checkout + - attach_workspace: + at: '.' + - run: sh ./scripts/installgo_linux.sh + - run: ./scripts/install_incus.sh + - run: cd tools/package_incus_test && go build + - run: sudo ./tools/package_incus_test/package_incus_test --package $(find ./dist -name "*_amd64.deb") + - run: sudo ./tools/package_incus_test/package_incus_test --package $(find ./dist -name "*.x86_64.rpm") + package-sign-windows: + machine: + image: ubuntu-2204:current + resource_class: medium + steps: + - checkout + - check-changed-files-or-halt + - attach_workspace: + at: '.' + - run: + name: "Sign Windows Executables" + command: ./scripts/sign-windows.sh + - persist_to_workspace: + root: '.' + paths: + - 'dist' + package-sign-mac: + executor: mac + working_directory: /Users/distiller/project + environment: + FL_OUTPUT_DIR: output + FASTLANE_LANE: test + shell: /bin/bash --login -o pipefail + steps: + - checkout + - check-changed-files-or-halt + - attach_workspace: + at: '.' + - run: + command: | + sh ./scripts/mac-signing.sh + - persist_to_workspace: + root: './build' + paths: + - 'dist' + package-consolidate: + docker: + - image: alpine + steps: + - attach_workspace: + at: '.' + - run: + command: | + cd dist && find . -type f -name '._*' -delete + - store_artifacts: + path: './dist' + destination: 'build/dist' + - run: + command: | + echo "This job contains all the final artifacts." + share-artifacts: + executor: aws-cli/default + steps: + - checkout + - check-changed-files-or-halt + - run: + command: | + PR=${CIRCLE_PULL_REQUEST##*/} + printf -v payload '{ "pullRequestNumber": "%s" }' "$PR" + curl -X POST "https://182c7jdgog.execute-api.us-east-1.amazonaws.com/prod/shareArtifacts" --data "$payload" + package-sign: + circleci_ip_ranges: true + docker: + - image: quay.io/influxdb/rsign:latest + auth: + username: $QUAY_RSIGN_USERNAME + password: $QUAY_RSIGN_PASSWORD + steps: + - add_ssh_keys: + fingerprints: + - 3b:c0:fe:a0:8a:93:33:69:de:22:ac:20:a6:ed:6b:e5 + - attach_workspace: + at: . + - run: | + cd dist + + # Generate the *.DIGESTS files. This must be done before the signing + # step so that the *.DIGEST files are also signed. + for target in * + do + sha256sum "${target}" > "${target}.DIGESTS" + done + + for target in * + do + case "${target}" + in + # rsign is shipped on Alpine Linux which uses "busybox ash" instead + # of bash. ash is somewhat more posix compliant and is missing some + # extensions and niceties from bash. + *.deb|*.dmg|*.rpm|*.tar.gz|*.zip|*.DIGESTS) + rsign "${target}" + ;; + esac + done + + for target in * + do + case "${target}" + in + *.deb|*.dmg|*.rpm|*.tar.gz|*.zip) + # Print sha256 hash and target for artifacts all in one file + # for use later during the release. + cat "${target}.DIGESTS" >> "telegraf-${CIRCLE_TAG}.DIGESTS" + ;; + esac + done + - persist_to_workspace: + root: ./ + paths: + - dist + - store_artifacts: + path: ./dist + +workflows: + version: 2 + check: + when: + not: + equal: [ scheduled_pipeline, << pipeline.trigger_source >> ] + jobs: + - 'lint-linux': + filters: + tags: + only: /.*/ + - 'lint-macos': + filters: + tags: + only: /.*/ + - 'lint-windows': + filters: + tags: + only: /.*/ + - 'test-go-linux': + filters: + tags: + only: /.*/ + - 'test-go-linux-386': + filters: + tags: + only: /.*/ + - 'test-go-mac': + filters: + tags: # only runs on tags if you specify this filter + only: /.*/ + - 'test-go-windows': + filters: + tags: + only: /.*/ + - 'test-integration': + filters: + tags: + only: /.*/ + - 'windows-package': + requires: + - 'test-go-linux' + filters: + tags: + only: /.*/ + - 'darwin-amd64-package': + requires: + - 'test-go-mac' + filters: + tags: + only: /.*/ + - 'darwin-arm64-package': + requires: + - 'test-go-mac' + filters: + branches: + ignore: + - master + tags: + only: /.*/ + - 'i386-package': + requires: + - 'test-go-linux-386' + filters: + branches: + ignore: + - master + tags: + only: /.*/ + - 'ppc64le-package': + requires: + - 'test-go-linux' + filters: + branches: + ignore: + - master + tags: + only: /.*/ + - 'riscv64-package': + requires: + - 'test-go-linux' + filters: + branches: + ignore: + - master + tags: + only: /.*/ + - 'loong64-package': + requires: + - 'test-go-linux' + filters: + branches: + ignore: + - /.*/ + tags: + only: /.*/ + - 's390x-package': + requires: + - 'test-go-linux' + filters: + branches: + ignore: + - master + tags: + only: /.*/ + - 'armel-package': + requires: + - 'test-go-linux' + filters: + branches: + ignore: + - master + tags: + only: /.*/ + - 'amd64-package': + requires: + - 'test-go-linux' + filters: + tags: + only: /.*/ + - 'arm64-package': + requires: + - 'test-go-linux' + filters: + branches: + ignore: + - master + tags: + only: /.*/ + - 'armhf-package': + requires: + - 'test-go-linux' + filters: + branches: + ignore: + - master + tags: + only: /.*/ + - 'mipsel-package': + requires: + - 'test-go-linux' + filters: + branches: + ignore: + - master + tags: + only: /.*/ + - 'mips-package': + requires: + - 'test-go-linux' + filters: + branches: + ignore: + - master + tags: + only: /.*/ + - 'share-artifacts': + requires: + - 'i386-package' + - 'ppc64le-package' + - 'riscv64-package' + - 's390x-package' + - 'armel-package' + - 'amd64-package' + - 'mipsel-package' + - 'mips-package' + - 'loong64-package' + - 'darwin-amd64-package' + - 'darwin-arm64-package' + - 'windows-package' + - 'arm64-package' + - 'armhf-package' + filters: + branches: + ignore: + - master + - release.* + tags: + ignore: /.*/ + - 'package-sign-windows': + requires: + - 'windows-package' + filters: + tags: + only: /.*/ + branches: + ignore: /.*/ + - 'package-sign-mac': + requires: + - 'darwin-amd64-package' + - 'darwin-arm64-package' + filters: + tags: + only: /.*/ + branches: + ignore: /.*/ + - 'package-sign': + requires: + - 'i386-package' + - 'ppc64le-package' + - 'riscv64-package' + - 's390x-package' + - 'armel-package' + - 'amd64-package' + - 'mipsel-package' + - 'mips-package' + - 'loong64-package' + - 'arm64-package' + - 'armhf-package' + - 'package-sign-mac' + - 'package-sign-windows' + filters: + tags: + only: /.*/ + branches: + ignore: /.*/ + - 'package-consolidate': + requires: + - 'i386-package' + - 'ppc64le-package' + - 's390x-package' + - 'armel-package' + - 'amd64-package' + - 'mipsel-package' + - 'mips-package' + - 'arm64-package' + - 'armhf-package' + - 'riscv64-package' + - 'loong64-package' + - 'package-sign-mac' + - 'package-sign-windows' + - 'package-sign' + filters: + tags: + only: /.*/ + branches: + ignore: /.*/ + - 'release': + requires: + - 'package-consolidate' + filters: + tags: + only: /.*/ + branches: + ignore: /.*/ + nightly: + when: + equal: [ scheduled_pipeline, << pipeline.trigger_source >> ] + jobs: + - 'lint-linux' + - 'lint-macos' + - 'lint-windows' + - 'test-go-linux' + - 'test-go-linux-386' + - 'test-go-mac' + - 'test-go-windows' + - 'test-licenses' + - 'windows-package': + name: 'windows-package-nightly' + nightly: true + requires: + - 'test-go-windows' + - 'darwin-amd64-package': + name: 'darwin-amd64-package-nightly' + nightly: true + requires: + - 'test-go-mac' + - 'darwin-arm64-package': + name: 'darwin-arm64-package-nightly' + nightly: true + requires: + - 'test-go-mac' + - 'i386-package': + name: 'i386-package-nightly' + nightly: true + requires: + - 'test-go-linux-386' + - 'ppc64le-package': + name: 'ppc64le-package-nightly' + nightly: true + requires: + - 'test-go-linux' + - 'riscv64-package': + name: 'riscv64-package-nightly' + nightly: true + requires: + - 'test-go-linux' + - 'loong64-package': + name: 'loong64-package-nightly' + nightly: true + requires: + - 'test-go-linux' + - 's390x-package': + name: 's390x-package-nightly' + nightly: true + requires: + - 'test-go-linux' + - 'armel-package': + name: 'armel-package-nightly' + nightly: true + requires: + - 'test-go-linux' + - 'amd64-package': + name: 'amd64-package-nightly' + nightly: true + requires: + - 'test-go-linux' + - 'arm64-package': + name: 'arm64-package-nightly' + nightly: true + requires: + - 'test-go-linux' + - 'armhf-package': + name: 'armhf-package-nightly' + nightly: true + requires: + - 'test-go-linux' + - 'mipsel-package': + name: 'mipsel-package-nightly' + nightly: true + requires: + - 'test-go-linux' + - 'mips-package': + name: 'mips-package-nightly' + nightly: true + requires: + - 'test-go-linux' + - 'package-sign-windows': + requires: + - 'windows-package-nightly' + - 'package-sign-mac': + requires: + - 'darwin-amd64-package-nightly' + - 'darwin-arm64-package-nightly' + - nightly: + requires: + - 'amd64-package-test-nightly' + - 'arm64-package-nightly' + - 'armel-package-nightly' + - 'armhf-package-nightly' + - 'darwin-amd64-package-nightly' + - 'darwin-arm64-package-nightly' + - 'i386-package-nightly' + - 'mips-package-nightly' + - 'mipsel-package-nightly' + - 'loong64-package-nightly' + - 'ppc64le-package-nightly' + - 'riscv64-package-nightly' + - 's390x-package-nightly' + - 'windows-package-nightly' + - docker-nightly: + requires: + - 'nightly' + - amd64-package-test-nightly: + requires: + - 'amd64-package-nightly' diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..965a146 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +CHANGELOG.md merge=union +README.md merge=union +go.sum merge=union +plugins/inputs/all/all.go merge=union +plugins/outputs/all/all.go merge=union + +# Always check-out / check-in files with LF line endings. +* text=auto eol=lf diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml new file mode 100644 index 0000000..a5f0233 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml @@ -0,0 +1,74 @@ +name: Bug Report +description: Create a bug report to help us improve +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Thanks for taking time to fill out this bug report! We reserve Telegraf issues for bugs for reproducible problems. + Please redirect any questions about Telegraf usage to our [Community Slack](https://influxdata.com/slack) or [Community Page](https://community.influxdata.com/) we have a lot of talented community members there who could help answer your question more quickly. + - type: textarea + id: config + attributes: + label: Relevant telegraf.conf + description: Place config in the toml code section. This will be automatically formatted into toml, so no need for backticks. + render: toml + validations: + required: true + - type: textarea + id: logs + attributes: + label: Logs from Telegraf + description: Please include the Telegraf logs, ideally with `--debug` used. + render: text + validations: + required: true + - type: input + id: system-info + attributes: + label: System info + description: Include Telegraf version, operating system, and other relevant details + placeholder: ex. Telegraf 1.20.0, Ubuntu 20.04, Docker 20.10.8 + validations: + required: true + - type: textarea + id: docker + attributes: + label: Docker + description: If your bug involves third party dependencies or services, it can be very helpful to provide a Dockerfile or docker-compose.yml that reproduces the environment you're testing against. + validations: + required: false + - type: textarea + id: reproduce + attributes: + label: Steps to reproduce + description: Describe the steps to reproduce the bug. + value: | + 1. + 2. + 3. + ... + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: Expected behavior + description: Describe what you expected to happen when you performed the above steps. + validations: + required: true + - type: textarea + id: actual-behavior + attributes: + label: Actual behavior + description: Describe what actually happened when you performed the above steps. + validations: + required: true + - type: textarea + id: additional-info + attributes: + label: Additional info + description: Include gist of relevant config, logs, etc. + validations: + required: false + diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml new file mode 100644 index 0000000..d9f9b2c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml @@ -0,0 +1,37 @@ +name: Feature request +description: Create a feature request to make Telegraf more awesome +labels: ["feature request"] +body: + - type: markdown + attributes: + value: | + Thanks for taking time to share with us this feature request! Please describe why you would like this feature to be added to Telegraf and how you plan to use it to make your life better. + - type: textarea + id: use-case + attributes: + label: Use Case + description: Describe how you plan to use this feature. + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: Expected behavior + description: Describe what you expected to happen when you performed the above steps. + validations: + required: true + - type: textarea + id: actual-behavior + attributes: + label: Actual behavior + description: Describe what actually happened when you performed the above steps. + validations: + required: true + - type: textarea + id: additional-info + attributes: + label: Additional info + description: Include gist of relevant config, logs, etc. + validations: + required: false + diff --git a/.github/ISSUE_TEMPLATE/SUPPORT.yml b/.github/ISSUE_TEMPLATE/SUPPORT.yml new file mode 100644 index 0000000..9e1c343 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/SUPPORT.yml @@ -0,0 +1,22 @@ +name: Support request +description: Open a support request +labels: ["support"] +body: + - type: markdown + attributes: + value: | + WOAH, hold up. This isn't the best place for support questions. + You can get a faster response on slack or forums: + + Please redirect any QUESTIONS about Telegraf usage to + - InfluxData Slack Channel: https://www.influxdata.com/slack + - InfluxData Community Site: https://community.influxdata.com + + Check the documentation for the related plugin including the troubleshooting + section if available. + + https://docs.influxdata.com/telegraf + https://github.com/influxdata/telegraf/tree/master/docs + - type: textarea + attributes: + label: "Please direct all support questions to Slack or the forums. Thank you." diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..65b7218 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,18 @@ +## Summary + + +## Checklist + + +- [ ] No AI generated code was used in this PR + +## Related issues + + +resolves # diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..9c9e87e --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,20 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 25 + labels: + - "dependencies" + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 25 + ignore: + # Dependabot isn't able to update this packages that do not match the + # source, so anything with a version + - dependency-name: "*.v*" + labels: + - "dependencies" diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 0000000..54c7e8a --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,65 @@ +--- +################################# +################################# +## Super Linter GitHub Actions ## +################################# +################################# +name: Lint Code Base + +# +# Documentation: +# https://help.github.com/en/articles/workflow-syntax-for-github-actions +# + +############################# +# Start the job on all push # +############################# +on: + push: + branches-ignore: [master, main] + # Remove the line above to run when pushing to master + pull_request: + branches: [master, main] + +############### +# Set the Job # +############### +permissions: {} + +jobs: + build: + # Name the Job + permissions: + contents: read # to fetch code (actions/checkout) + statuses: write # to mark status of each linter run (github/super-linter) + + name: Lint Code Base + # Set the agent to run on + runs-on: ubuntu-latest + + ################## + # Load all steps # + ################## + steps: + ########################## + # Checkout the code base # + ########################## + - name: Checkout Code + uses: actions/checkout@v4 + with: + # Full git history is needed to get a proper list of changed files within `super-linter` + fetch-depth: 0 + + ################################ + # Run Linter against code base # + ################################ + - name: Lint Code Base + uses: super-linter/super-linter@v7.3.0 + env: + VALIDATE_ALL_CODEBASE: false + DEFAULT_BRANCH: master + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LINTER_RULES_PATH: '.' + MARKDOWN_CONFIG_FILE: .markdownlint.yml + VALIDATE_MARKDOWN: true + VALIDATE_BASH: true diff --git a/.github/workflows/milestones.yml b/.github/workflows/milestones.yml new file mode 100644 index 0000000..88b2c43 --- /dev/null +++ b/.github/workflows/milestones.yml @@ -0,0 +1,29 @@ +name: Milestones +on: + pull_request_target: + types: + - closed + +permissions: + issues: write + pull-requests: write + +jobs: + milestone_job: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + name: Assign milestones to PRs + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Assign milestone to PR + uses: srebhan/label-milestone-action@v1.0.1 + id: assign-milestone + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + bugfix-labels: 'fix,chore,docs,test' + minor-labels: 'feat' + major-labels: 'breaking change' + fallback: 'minor' + - name: Show milestone + run: echo "Assigned milestone is ${{ steps.assign-milestone.outputs.milestone }}" diff --git a/.github/workflows/pr-target-branch.yml b/.github/workflows/pr-target-branch.yml new file mode 100644 index 0000000..9a67f93 --- /dev/null +++ b/.github/workflows/pr-target-branch.yml @@ -0,0 +1,24 @@ +name: Target Branch +on: + pull_request: + types: + - opened + - reopened + - synchronize + - edited + +jobs: + check-target-master: + name: master + runs-on: ubuntu-latest + steps: + - name: debug + run: echo Target is ${{ github.event.pull_request.base.ref }} + - name: success + if: github.event.pull_request.base.ref == 'master' + run: exit 0 + - name: error + if: github.event.pull_request.base.ref != 'master' + run: | + echo "Pull-request is not based on master, please rebase" + exit 1 diff --git a/.github/workflows/readme-linter.yml b/.github/workflows/readme-linter.yml new file mode 100644 index 0000000..cb14130 --- /dev/null +++ b/.github/workflows/readme-linter.yml @@ -0,0 +1,26 @@ +name: Lint plugin readmes +on: +# push: +# branches-ignore: master + pull_request: + branches: # Names of target branches, not source branches + - master +jobs: + run-readme-linter: + runs-on: ubuntu-latest + steps: + - uses: actions/setup-go@v5 + with: + go-version: '1.24.3' + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5 + with: + base_sha: ${{ github.event.pull_request.base.sha }} + files: ./plugins/**/README.md + - name: Run readme linter on changed files + if: steps.changed-files.outputs.any_changed == 'true' + run: go run ./tools/readme_linter ${{ steps.changed-files.outputs.all_changed_files }} diff --git a/.github/workflows/semantic.yml b/.github/workflows/semantic.yml new file mode 100644 index 0000000..ea869d9 --- /dev/null +++ b/.github/workflows/semantic.yml @@ -0,0 +1,15 @@ +--- +name: "Semantic PR and Commit Messages" + +on: + pull_request: + types: [opened, reopened, synchronize, edited] + branches: + - master + +jobs: + semantic: + uses: influxdata/validate-semantic-github-messages/.github/workflows/semantic.yml@main + with: + COMMITS_HISTORY: 0 + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cfb58ea --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +/.idea +/build +/etc/telegraf.conf +/telegraf +/telegraf.exe +/telegraf.gz +/tools/package_lxd_test/package_lxd_test +/tools/license_checker/license_checker* +/tools/readme_config_includer/generator +/tools/readme_config_includer/generator.exe +/tools/config_includer/generator +/tools/config_includer/generator.exe +/tools/readme_linter/readme_linter* +/tools/custom_builder/custom_builder* +/vendor +.DS_Store +process.yml +/.vscode +/*.toml +/*.conf +resource.syso +versioninfo.json +.uuid diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..85a9cd1 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,638 @@ +version: "2" + +linters: + # Default set of linters. + # The value can be: `standard`, `all`, `none`, or `fast`. + # Default: standard + default: none + + # Enable specific linter. + # https://golangci-lint.run/usage/linters/#enabled-by-default + enable: + - asasalint + - asciicheck + - bidichk + - bodyclose + - copyloopvar + - depguard + - dogsled + - errcheck + - errname + - errorlint + - gocheckcompilerdirectives + - gocritic + - goprintffuncname + - gosec + - govet + - ineffassign + - interfacebloat + - lll + - makezero + - mirror + - nakedret + - nilerr + - nolintlint + - perfsprint + - prealloc + - predeclared + - revive + - sqlclosecheck + - staticcheck + - testifylint + - tparallel + - unconvert + - unparam + - unused + - usetesting + + settings: + depguard: + # Rules to apply. + # + # Variables: + # - File Variables + # Use an exclamation mark `!` to negate a variable. + # Example: `!$test` matches any file that is not a go test file. + # + # `$all` - matches all go files + # `$test` - matches all go test files + # + # - Package Variables + # + # `$gostd` - matches all of go's standard library (Pulled from `GOROOT`) + # + # Default (applies if no custom rules are defined): Only allow $gostd in all files. + rules: + # Name of a rule. + main: + # List of file globs that will match this list of settings to compare against. + # By default, if a path is relative, it is relative to the directory where the golangci-lint command is executed. + # The placeholder '${base-path}' is substituted with a path relative to the mode defined with `run.relative-path-mode`. + # The placeholder '${config-path}' is substituted with a path relative to the configuration file. + # Default: $all + files: + - '!**/agent/**' + - '!**/cmd/**' + - '!**/config/**' + - '!**/filter/**' + - '!**/internal/**' + - '!**/logger/**' + - '!**/metric/**' + - '!**/models/**' + - '!**/plugins/serializers/**' + - '!**/scripts/**' + - '!**/selfstat/**' + - '!**/testutil/**' + - '!**/tools/**' + - '!**/*_test.go' + # List of packages that are not allowed. + # Entries can be a variable (starting with $), a string prefix, or an exact match (if ending with $). + # Default: [] + deny: + - pkg: log + desc: 'Use injected telegraf.Logger instead' + + errcheck: + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`. + # Such cases aren't reported by default. + # Default: false + check-blank: true + + # List of functions to exclude from checking, where each entry is a single function to exclude. + # See https://github.com/kisielk/errcheck#excluding-functions for details. + exclude-functions: + - '(*hash/maphash.Hash).Write' + - '(*hash/maphash.Hash).WriteByte' + - '(*hash/maphash.Hash).WriteString' + - '(*github.com/influxdata/telegraf/plugins/outputs/postgresql/sqltemplate.Template).UnmarshalText' + + gocritic: + # Disable all checks. + # Default: false + disable-all: true + # Which checks should be enabled in addition to default checks; can't be combined with 'disabled-checks'. + # By default, list of stable checks is used (https://go-critic.com/overview#checks-overview). + # To see which checks are enabled run `GL_DEBUG=gocritic golangci-lint run --enable=gocritic`. + enabled-checks: + # diagnostic + - argOrder + - badCall + - badCond + - badLock + - badRegexp + - badSorting + - badSyncOnceFunc + - builtinShadowDecl + - caseOrder + - codegenComment + - commentedOutCode + - deferInLoop + - deprecatedComment + - dupArg + - dupBranchBody + - dupCase + - dupSubExpr + - dynamicFmtString + - emptyDecl + - evalOrder + - exitAfterDefer + - externalErrorReassign + - filepathJoin + - flagName + - mapKey + - nilValReturn + - offBy1 + - regexpPattern + - sloppyLen + - sloppyReassign + - sloppyTypeAssert + - sortSlice + - sprintfQuotedString + - sqlQuery + - syncMapLoadAndDelete + - truncateCmp + - uncheckedInlineErr + - unnecessaryDefer + - weakCond + # performance + - appendCombine + - equalFold + - hugeParam + - indexAlloc + - preferDecodeRune + - preferFprint + - preferStringWriter + - preferWriteByte + - rangeExprCopy + - rangeValCopy + - sliceClear + - stringXbytes + + # Settings passed to gocritic. + # The settings key is the name of a supported gocritic checker. + # The list of supported checkers can be found at https://go-critic.com/overview. + settings: + hugeParam: + # Size in bytes that makes the warning trigger. + # Default: 80 + sizeThreshold: 512 + rangeValCopy: + # Size in bytes that makes the warning trigger. + # Default: 128 + sizeThreshold: 512 + + gosec: + # To select a subset of rules to run. + # Available rules: https://github.com/securego/gosec#available-rules + # Default: [] - means include all rules + includes: + - G101 # Look for hard coded credentials + - G102 # Bind to all interfaces + - G103 # Audit the use of unsafe block + - G106 # Audit the use of ssh.InsecureIgnoreHostKey + - G107 # Url provided to HTTP request as taint input + - G108 # Profiling endpoint automatically exposed on /debug/pprof + - G109 # Potential Integer overflow made by strconv.Atoi result conversion to int16/32 + - G110 # Potential DoS vulnerability via decompression bomb + - G111 # Potential directory traversal + - G112 # Potential slowloris attack + - G114 # Use of net/http serve function that has no support for setting timeouts + - G201 # SQL query construction using format string + - G202 # SQL query construction using string concatenation + - G203 # Use of unescaped data in HTML templates + - G301 # Poor file permissions used when creating a directory + - G302 # Poor file permissions used with chmod + - G303 # Creating tempfile using a predictable path + - G305 # File traversal when extracting zip/tar archive + - G306 # Poor file permissions used when writing to a new file + - G401 # Detect the usage of MD5 or SHA1 + - G403 # Ensure minimum RSA key length of 2048 bits + - G404 # Insecure random number source (rand) + - G405 # Detect the usage of DES or RC4 + - G406 # Detect the usage of MD4 or RIPEMD160 + - G501 # Import blocklist: crypto/md5 + - G502 # Import blocklist: crypto/des + - G503 # Import blocklist: crypto/rc4 + - G505 # Import blocklist: crypto/sha1 + - G506 # Import blocklist: golang.org/x/crypto/md4 + - G507 # Import blocklist: golang.org/x/crypto/ripemd160 + - G601 # Implicit memory aliasing of items from a range statement + - G602 # Slice access out of bounds + # G104, G105, G113, G204, G304, G307, G402, G504 were not enabled intentionally + # TODO: review G115 when reporting false positives is fixed (https://github.com/securego/gosec/issues/1212) + + # To specify the configuration of rules. + config: + # Maximum allowed permissions mode for os.OpenFile and os.Chmod + # Default: "0600" + G302: "0640" + # Maximum allowed permissions mode for os.WriteFile and ioutil.WriteFile + # Default: "0600" + G306: "0640" + + govet: + # Settings per analyzer. + settings: + # Analyzer name, run `go tool vet help` to see all analyzers. + printf: + # Comma-separated list of print function names to check (in addition to default, see `go tool vet help printf`). + # Default: [] + funcs: + - (github.com/influxdata/telegraf.Logger).Tracef + - (github.com/influxdata/telegraf.Logger).Debugf + - (github.com/influxdata/telegraf.Logger).Infof + - (github.com/influxdata/telegraf.Logger).Warnf + - (github.com/influxdata/telegraf.Logger).Errorf + - (github.com/influxdata/telegraf.Logger).Trace + - (github.com/influxdata/telegraf.Logger).Debug + - (github.com/influxdata/telegraf.Logger).Info + - (github.com/influxdata/telegraf.Logger).Warn + - (github.com/influxdata/telegraf.Logger).Error + + lll: + # Max line length, lines longer will be reported. + # '\t' is counted as 1 character by default, and can be changed with the tab-width option. + # Default: 120. + line-length: 160 + # Tab width in spaces. + # Default: 1 + tab-width: 4 + + nakedret: + # Make an issue if func has more lines of code than this setting, and it has naked returns. + # Default: 30 + max-func-lines: 1 + + nolintlint: + # Enable to require an explanation of nonzero length after each nolint directive. + # Default: false + require-explanation: true + # Enable to require nolint directives to mention the specific linter being suppressed. + # Default: false + require-specific: true + + prealloc: + # Report pre-allocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them. + # Default: true + simple: false + + revive: + # Sets the default severity. + # See https://github.com/mgechev/revive#configuration + # Default: warning + severity: error + + # Run `GL_DEBUG=revive golangci-lint run --enable-only=revive` to see default, all available rules, and enabled rules. + rules: + - name: argument-limit + arguments: [ 6 ] + - name: atomic + - name: bare-return + - name: blank-imports + - name: bool-literal-in-expr + - name: call-to-gc + - name: comment-spacings + - name: confusing-naming + - name: confusing-results + - name: constant-logical-expr + - name: context-as-argument + - name: context-keys-type + - name: datarace + - name: deep-exit + - name: defer + - name: dot-imports + - name: duplicated-imports + - name: early-return + - name: empty-block + - name: empty-lines + - name: enforce-map-style + exclude: [ "TEST" ] + arguments: + - "make" + - name: enforce-repeated-arg-type-style + arguments: + - "short" + - name: enforce-slice-style + arguments: + - "make" + - name: error-naming + - name: error-return + - name: error-strings + - name: errorf + - name: exported + exclude: + - "**/accumulator.go" + - "**/agent/**" + - "**/cmd/**" + - "**/config/**" + - "**/filter/**" + - "**/internal/**" + - "**/logger/**" + - "**/logger.go" + - "**/metric/**" + - "**/metric.go" + - "**/migrations/**" + - "**/models/**" + - "**/persister/**" + - "**/metric.go" + - "**/parser.go" + - "**/plugin.go" + - "**/plugins/aggregators/**" + - "**/plugins/common/**" + - "**/plugins/outputs/**" + - "**/plugins/parsers/**" + - "**/plugins/processors/**" + - "**/plugins/secretstores/**" + - "**/plugins/serializers/**" + - "**/selfstat/**" + - "**/serializer.go" + - "**/testutil/**" + - "**/tools/**" + arguments: + - "check-private-receivers" + - "say-repetitive-instead-of-stutters" + - "check-public-interface" + - "disable-checks-on-types" + - name: function-result-limit + arguments: [ 3 ] + - name: get-return + - name: identical-branches + - name: if-return + - name: import-alias-naming + arguments: + - "^[a-z][a-z0-9_]*[a-z0-9]+$" + - name: import-shadowing + - name: increment-decrement + - name: indent-error-flow + - name: max-public-structs + arguments: [ 5 ] + exclude: [ "TEST" ] + - name: modifies-parameter + - name: modifies-value-receiver + - name: optimize-operands-order + - name: package-comments + - name: range + - name: range-val-address + - name: range-val-in-closure + - name: receiver-naming + - name: redefines-builtin-id + - name: redundant-import-alias + - name: string-format + arguments: + - - 'fmt.Errorf[0],errors.New[0]' + - '/^([^A-Z]|$)/' + - 'Error string must not start with a capital letter.' + - - 'fmt.Errorf[0],errors.New[0]' + - '/(^|[^\.!?])$/' + - 'Error string must not end in punctuation.' + - - 'panic' + - '/^[^\n]*$/' + - 'Must not contain line breaks.' + - name: string-of-int + - name: struct-tag + - name: superfluous-else + - name: time-equal + - name: time-naming + - name: unconditional-recursion + - name: unexported-naming + - name: unnecessary-stmt + - name: unreachable-code + - name: unused-parameter + - name: unused-receiver + - name: var-declaration + - name: var-naming + arguments: + - [ ] # AllowList + - [ "ID", "DB", "TS" ] # DenyList + - name: waitgroup-by-value + + staticcheck: + # SAxxxx checks in https://staticcheck.dev/docs/configuration/options/#checks + # Example (to disable some checks): [ "all", "-SA1000", "-SA1001"] + # Default: ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022"] + checks: + - all + # Poorly chosen identifier. + # https://staticcheck.dev/docs/checks/#ST1003 + - -ST1003 + # The documentation of an exported function should start with the function's name. + # https://staticcheck.dev/docs/checks/#ST1020 + - -ST1020 + # The documentation of an exported type should start with type's name. + # https://staticcheck.dev/docs/checks/#ST1021 + - -ST1021 + # The documentation of an exported variable or constant should start with variable's name. + # https://staticcheck.dev/docs/checks/#ST1022 + - -ST1022 + # Apply De Morgan's law. + # https://staticcheck.dev/docs/checks/#QF1001 + - -QF1001 + # Convert if/else-if chain to tagged switch. + # https://staticcheck.dev/docs/checks/#QF1003 + - -QF1003 + # Use 'strings.ReplaceAll' instead of 'strings.Replace' with 'n == -1'. + # https://staticcheck.dev/docs/checks/#QF1004 + - -QF1004 + # Lift 'if'+'break' into loop condition. + # https://staticcheck.dev/docs/checks/#QF1006 + - -QF1006 + # Merge conditional assignment into variable declaration. + # https://staticcheck.dev/docs/checks/#QF1007 + - -QF1007 + # Omit embedded fields from selector expression. + # https://staticcheck.dev/docs/checks/#QF1008 + - -QF1008 + # Use 'time.Time.Equal' instead of '==' operator. + # https://staticcheck.dev/docs/checks/#QF1009 + - -QF1009 + + testifylint: + # Disable all checkers (https://github.com/Antonboom/testifylint#checkers). + # Default: false + disable-all: true + # Enable checkers by name + enable: + - blank-import + - bool-compare + - compares + - contains + - empty + - encoded-compare + - error-is-as + - error-nil + - expected-actual + - float-compare + - formatter + - go-require + - len + - negative-positive + - nil-compare + - regexp + - require-error + - suite-broken-parallel + - suite-dont-use-pkg + - suite-extra-assert-call + - suite-subtest-run + - suite-thelper + - useless-assert + + usetesting: + # Enable/disable `os.TempDir()` detections. + # Default: false + os-temp-dir: true + + # Defines a set of rules to ignore issues. + # It does not skip the analysis, and so does not ignore "typecheck" errors. + exclusions: + # Mode of the generated files analysis. + # + # - `strict`: sources are excluded by strictly following the Go generated file convention. + # Source files that have lines matching only the following regular expression will be excluded: `^// Code generated .* DO NOT EDIT\.$` + # This line must appear before the first non-comment, non-blank text in the file. + # https://go.dev/s/generatedcode + # - `lax`: sources are excluded if they contain lines like `autogenerated file`, `code generated`, `do not edit`, etc. + # - `disable`: disable the generated files exclusion. + # + # Default: strict + generated: lax + + # Excluding configuration per-path, per-linter, per-text and per-source. + rules: + # errcheck + - path: cmd/telegraf/(main|printer|cmd_plugins).go + text: "Error return value of `outputBuffer.Write` is not checked" + + - path: plugins/inputs/win_perf_counters/pdh.go + linters: + - errcheck + + # gosec:G101 + - path: _test\.go + text: "Potential hardcoded credentials" + + # gosec:G404 + - path: _test\.go + text: "Use of weak random number generator" + + # revive:max-public-structs + - path-except: ^plugins/(aggregators|inputs|outputs|parsers|processors|serializers)/... + text: "max-public-structs: you have exceeded the maximum number" + + # revive:var-naming + - path: (.+)\.go$ + text: don't use an underscore in package name + + # revive:exported + - path: (.+)\.go$ + text: exported method .*\.(Init |SampleConfig |Gather |Start |Stop |GetState |SetState |SetParser |SetParserFunc |SetTranslator |Probe )should have comment or be unexported + + # EXC0001 errcheck: Almost all programs ignore errors on these functions, and in most cases it's ok + - path: (.+)\.go$ + text: Error return value of .((os\.)?std(out|err)\..*|.*Close.*|.*close.*|.*Flush|.*Disconnect|.*disconnect|.*Clear|os\.Remove(All)?|.*print(f|ln)?|os\.Setenv|os\.Unsetenv). is not checked + + # EXC0013 revive: Annoying issue about not having a comment. The rare codebase has such comments + - path: (.+)\.go$ + text: package comment should be of the form "(.+)... + + # EXC0015 revive: Annoying issue about not having a comment. The rare codebase has such comments + - path: (.+)\.go$ + text: should have a package comment + + # Which file paths to exclude: they will be analyzed, but issues from them won't be reported. + # "/" will be replaced by the current OS file path separator to properly work on Windows. + # Default: [] + paths: + - plugins/parsers/influx/machine.go* + +formatters: + # Enable specific formatter. + # Default: [] (uses standard Go formatting) + enable: + - gci + + # Formatters settings. + settings: + gci: + # Section configuration to compare against. + # Section names are case-insensitive and may contain parameters in (). + # The default order of sections is `standard > default > custom > blank > dot > alias > localmodule`. + # If `custom-order` is `true`, it follows the order of `sections` option. + # Default: ["standard", "default"] + sections: + - standard # Standard section: captures all standard packages. + - default # Default section: contains all imports that could not be matched to another section type. + - localmodule # Local module section: contains all local packages. This section is not present unless explicitly enabled. + + exclusions: + # Mode of the generated files analysis. + # + # - `strict`: sources are excluded by strictly following the Go generated file convention. + # Source files that have lines matching only the following regular expression will be excluded: `^// Code generated .* DO NOT EDIT\.$` + # This line must appear before the first non-comment, non-blank text in the file. + # https://go.dev/s/generatedcode + # - `lax`: sources are excluded if they contain lines like `autogenerated file`, `code generated`, `do not edit`, etc. + # - `disable`: disable the generated files exclusion. + # + # Default: lax + generated: lax + +issues: + # Maximum issues count per one linter. + # Set to 0 to disable. + # Default: 50 + max-issues-per-linter: 0 + + # Maximum count of issues with the same text. + # Set to 0 to disable. + # Default: 3 + max-same-issues: 0 + + # Make issues output unique by line. + # Default: true + uniq-by-line: false + +# Output configuration options. +output: + # The formats used to render issues. + formats: + # Prints issues in columns representation separated by tabulations. + tab: + # Output path can be either `stdout`, `stderr` or path to the file to write to. + # Default: stdout + path: stdout + + # Order to use when sorting results. + # Possible values: `file`, `linter`, and `severity`. + # + # If the severity values are inside the following list, they are ordered in this order: + # 1. error + # 2. warning + # 3. high + # 4. medium + # 5. low + # Either they are sorted alphabetically. + # + # Default: ["linter", "file"] + sort-order: + - file # filepath, line, and column. + - linter + + # Show statistics per linter. + # Default: true + show-stats: true + +severity: + # Set the default severity for issues. + # + # If severity rules are defined and the issues do not match or no severity is provided to the rule + # this will be the default severity applied. + # Severities should match the supported severity names of the selected out format. + # - Code climate: https://docs.codeclimate.com/docs/issues#issue-severity + # - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#SeverityLevel + # - GitHub: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message + # - TeamCity: https://www.jetbrains.com/help/teamcity/service-messages.html#Inspection+Instance + # + # `@linter` can be used as severity value to keep the severity from linters (e.g. revive, gosec, ...) + # + # Default: "" + default: error diff --git a/.markdownlint.yml b/.markdownlint.yml new file mode 100644 index 0000000..8931794 --- /dev/null +++ b/.markdownlint.yml @@ -0,0 +1,6 @@ +{ + "MD013": false, + "MD033": { + "allowed_elements": ["br"] + } +} diff --git a/.markdownlintignore b/.markdownlintignore new file mode 100644 index 0000000..513ed4e --- /dev/null +++ b/.markdownlintignore @@ -0,0 +1,2 @@ +.github/PULL_REQUEST_TEMPLATE.md +docs/includes/* diff --git a/CHANGELOG-1.13.md b/CHANGELOG-1.13.md new file mode 100644 index 0000000..a55e02e --- /dev/null +++ b/CHANGELOG-1.13.md @@ -0,0 +1,2795 @@ + +# Changelog v1.13 and Earlier + +## v1.13.4 [2020-02-25] + +### Release Notes + +- Official packages now built with Go 1.13.8. + +### Bug Fixes + +- [#6988](https://github.com/influxdata/telegraf/issues/6988): Parse NaN values from summary types in prometheus input. +- [#6820](https://github.com/influxdata/telegraf/issues/6820): Fix pgbouncer input when used with newer pgbouncer versions. +- [#6913](https://github.com/influxdata/telegraf/issues/6913): Support up to 8192 stats in the ethtool input. +- [#7060](https://github.com/influxdata/telegraf/issues/7060): Fix perf counters collection on named instances in sqlserver input. +- [#6926](https://github.com/influxdata/telegraf/issues/6926): Use add time for prometheus expiration calculation. +- [#7057](https://github.com/influxdata/telegraf/issues/7057): Fix inconsistency with input error counting in internal input. +- [#7063](https://github.com/influxdata/telegraf/pull/7063): Use the same timestamp per call if no time is provided in prometheus input. + +## v1.13.3 [2020-02-04] + +### Bug Fixes + +- [#5744](https://github.com/influxdata/telegraf/issues/5744): Fix kibana input with Kibana versions greater than 6.4. +- [#6960](https://github.com/influxdata/telegraf/issues/6960): Fix duplicate TrackingIDs can be returned in queue consumer plugins. +- [#6913](https://github.com/influxdata/telegraf/issues/6913): Support up to 4096 stats in the ethtool input. +- [#6973](https://github.com/influxdata/telegraf/issues/6973): Expire metrics on query in addition to on add. + +## v1.13.2 [2020-01-21] + +### Bug Fixes + +- [#2652](https://github.com/influxdata/telegraf/issues/2652): Warn without error when processes input is started on Windows. +- [#6890](https://github.com/influxdata/telegraf/issues/6890): Only parse certificate blocks in x509_cert input. +- [#6883](https://github.com/influxdata/telegraf/issues/6883): Add custom attributes for all resource types in vsphere input. +- [#6899](https://github.com/influxdata/telegraf/pull/6899): Fix URL agent address form with udp in snmp input. +- [#6619](https://github.com/influxdata/telegraf/issues/6619): Change logic to allow recording of device fields when attributes is false. +- [#6903](https://github.com/influxdata/telegraf/issues/6903): Do not add invalid timestamps to kafka messages. +- [#6906](https://github.com/influxdata/telegraf/issues/6906): Fix json_strict option and set default of true. + +## v1.13.1 [2020-01-08] + +### Bug Fixes + +- [#6788](https://github.com/influxdata/telegraf/issues/6788): Fix ServerProperty query stops working on Azure after failover. +- [#6803](https://github.com/influxdata/telegraf/pull/6803): Add leading period to OID in SNMP v1 generic traps. +- [#6823](https://github.com/influxdata/telegraf/pull/6823): Fix missing config fields in prometheus serializer. +- [#6694](https://github.com/influxdata/telegraf/issues/6694): Fix panic on connection loss with undelivered messages in mqtt_consumer. +- [#6679](https://github.com/influxdata/telegraf/issues/6679): Encode query hash fields as hex strings in sqlserver input. +- [#6345](https://github.com/influxdata/telegraf/issues/6345): Invalidate diskio cache if the metadata mtime has changed. +- [#6800](https://github.com/influxdata/telegraf/issues/6800): Show platform not supported warning only on plugin creation. +- [#6814](https://github.com/influxdata/telegraf/issues/6814): Fix rabbitmq cannot complete gather after request error. +- [#6846](https://github.com/influxdata/telegraf/issues/6846): Fix /sbin/init --version executed on Telegraf startup. +- [#6847](https://github.com/influxdata/telegraf/issues/6847): Use last path element as field key if path fully specified in cisco_telemetry_gnmi input. + +## v1.13 [2019-12-12] + +### Release Notes + +- Official packages built with Go 1.13.5. This affects the minimum supported + version on several platforms, most notably requiring Windows 7 (2008 R2) or + later. For details, check the release notes for Go + [ports](https://golang.org/doc/go1.13#ports). +- The `prometheus` input and `prometheus_client` output have a new mapping to + and from Telegraf metrics, which can be enabled by setting `metric_version = 2`. + The original mapping is deprecated. When both plugins have the same setting, + passthrough metrics will be unchanged. Refer to the `prometheus` input for + details about the mapping. + +### New Inputs + +- [azure_storage_queue](/plugins/inputs/azure_storage_queue/README.md) - Contributed by @mjiderhamn +- [ethtool](/plugins/inputs/ethtool/README.md) - Contributed by @philippreston +- [snmp_trap](/plugins/inputs/snmp_trap/README.md) - Contributed by @influxdata +- [suricata](/plugins/inputs/suricata/README.md) - Contributed by @satta +- [synproxy](/plugins/inputs/synproxy/README.md) - Contributed by @rfrenayworldstream +- [systemd_units](/plugins/inputs/systemd_units/README.md) - Contributed by @benschweizer + +### New Processors + +- [clone](/plugins/processors/clone/README.md) - Contributed by @adrianlzt + +### New Aggregators + +- [merge](/plugins/aggregators/merge/README.md) - Contributed by @influxdata + +### Features + +- [#6326](https://github.com/influxdata/telegraf/pull/5842): Add per node memory stats to rabbitmq input. +- [#6361](https://github.com/influxdata/telegraf/pull/6361): Add ability to read query from file to postgresql_extensible input. +- [#5921](https://github.com/influxdata/telegraf/pull/5921): Add replication metrics to the redis input. +- [#6177](https://github.com/influxdata/telegraf/pull/6177): Support NX-OS telemetry extensions in cisco_telemetry_mdt. +- [#6415](https://github.com/influxdata/telegraf/pull/6415): Allow graphite parser to create Inf and NaN values. +- [#6434](https://github.com/influxdata/telegraf/pull/6434): Use prefix base detection for ints in grok parser. +- [#6465](https://github.com/influxdata/telegraf/pull/6465): Add more performance counter metrics to sqlserver input. +- [#6476](https://github.com/influxdata/telegraf/pull/6476): Add millisecond unix time support to grok parser. +- [#6473](https://github.com/influxdata/telegraf/pull/6473): Add container id as optional source tag to docker and docker_log input. +- [#6504](https://github.com/influxdata/telegraf/pull/6504): Add lang parameter to OpenWeathermap input plugin. +- [#6540](https://github.com/influxdata/telegraf/pull/6540): Log file open errors at debug level in tail input. +- [#6553](https://github.com/influxdata/telegraf/pull/6553): Add timeout option to cloudwatch input. +- [#6549](https://github.com/influxdata/telegraf/pull/6549): Support custom success codes in http input. +- [#6530](https://github.com/influxdata/telegraf/pull/6530): Improve ipvs input error strings and logging. +- [#6532](https://github.com/influxdata/telegraf/pull/6532): Add strict mode to JSON parser that can be disable to ignore invalid items. +- [#6543](https://github.com/influxdata/telegraf/pull/6543): Add support for Kubernetes 1.16 and remove deprecated API usage. +- [#6283](https://github.com/influxdata/telegraf/pull/6283): Add gathering of RabbitMQ federation link metrics. +- [#6356](https://github.com/influxdata/telegraf/pull/6356): Add bearer token defaults for Kubernetes plugins. +- [#5870](https://github.com/influxdata/telegraf/pull/5870): Add support for SNMP over TCP. +- [#6603](https://github.com/influxdata/telegraf/pull/6603): Add support for per output flush jitter. +- [#6650](https://github.com/influxdata/telegraf/pull/6650): Add a nameable file tag to file input plugin. +- [#6640](https://github.com/influxdata/telegraf/pull/6640): Add Splunk MultiMetric support. +- [#6680](https://github.com/influxdata/telegraf/pull/6668): Add support for sending HTTP Basic Auth in influxdb input +- [#5767](https://github.com/influxdata/telegraf/pull/5767): Add ability to configure the url tag in the prometheus input. +- [#5767](https://github.com/influxdata/telegraf/pull/5767): Add prometheus metric_version=2 mapping to internal metrics/line protocol. +- [#6703](https://github.com/influxdata/telegraf/pull/6703): Add prometheus metric_version=2 support to prometheus_client output. +- [#6660](https://github.com/influxdata/telegraf/pull/6660): Add content_encoding compression support to socket_listener. +- [#6689](https://github.com/influxdata/telegraf/pull/6689): Add high resolution metrics support to CloudWatch output. +- [#6716](https://github.com/influxdata/telegraf/pull/6716): Add SReclaimable and SUnreclaim to mem input. +- [#6695](https://github.com/influxdata/telegraf/pull/6695): Allow multiple certificates per file in x509_cert input. +- [#6686](https://github.com/influxdata/telegraf/pull/6686): Add additional tags to the x509 input. +- [#6703](https://github.com/influxdata/telegraf/pull/6703): Add batch data format support to file output. +- [#6688](https://github.com/influxdata/telegraf/pull/6688): Support partition assignment strategy configuration in kafka_consumer. +- [#6731](https://github.com/influxdata/telegraf/pull/6731): Add node type tag to mongodb input. +- [#6669](https://github.com/influxdata/telegraf/pull/6669): Add uptime_ns field to mongodb input. +- [#6735](https://github.com/influxdata/telegraf/pull/6735): Support resolution of symlinks in filecount input. +- [#6746](https://github.com/influxdata/telegraf/pull/6746): Set message timestamp to the metric time in kafka output. +- [#6740](https://github.com/influxdata/telegraf/pull/6740): Add base64decode operation to string processor. +- [#6790](https://github.com/influxdata/telegraf/pull/6790): Add option to control collecting global variables to mysql input. + +### Bug Fixes + +- [#6484](https://github.com/influxdata/telegraf/issues/6484): Show correct default settings in mysql sample config. +- [#6583](https://github.com/influxdata/telegraf/issues/6583): Use 1h or 3h rain values as appropriate in openweathermap input. +- [#6573](https://github.com/influxdata/telegraf/issues/6573): Fix not a valid field error in Windows with nvidia input. +- [#6614](https://github.com/influxdata/telegraf/issues/6614): Fix influxdb output serialization on connection closed. +- [#6690](https://github.com/influxdata/telegraf/issues/6690): Fix ping skips remaining hosts after dns lookup error. +- [#6684](https://github.com/influxdata/telegraf/issues/6684): Log mongodb oplog auth errors at debug level. +- [#6705](https://github.com/influxdata/telegraf/issues/6705): Remove trailing underscore trimming from json flattener. +- [#6421](https://github.com/influxdata/telegraf/issues/6421): Revert change causing cpu usage to be capped at 100 percent. +- [#6523](https://github.com/influxdata/telegraf/issues/6523): Accept any media type in the prometheus input. +- [#6769](https://github.com/influxdata/telegraf/issues/6769): Fix unix socket dial arguments in uwsgi input. +- [#6757](https://github.com/influxdata/telegraf/issues/6757): Replace colon chars in prometheus output labels with metric_version=1. +- [#6773](https://github.com/influxdata/telegraf/issues/6773): Set TrimLeadingSpace when TrimSpace is on in csv parser. + +## v1.12.6 [2019-11-19] + +### Bug Fixes + +- [#6666](https://github.com/influxdata/telegraf/issues/6666): Fix many plugin errors are logged at debug logging level. +- [#6652](https://github.com/influxdata/telegraf/issues/6652): Use nanosecond precision in docker_log input. +- [#6642](https://github.com/influxdata/telegraf/issues/6642): Fix interface option with method = native in ping input. +- [#6680](https://github.com/influxdata/telegraf/pull/6680): Fix panic in mongodb input if shard connection pool stats are unreadable. + +## v1.12.5 [2019-11-12] + +### Bug Fixes + +- [#6576](https://github.com/influxdata/telegraf/issues/6576): Fix incorrect results in ping input plugin. +- [#6610](https://github.com/influxdata/telegraf/pull/6610): Add missing character replacement to sql_instance tag. +- [#6337](https://github.com/influxdata/telegraf/issues/6337): Change no metric error message to debug level in cloudwatch input. +- [#6602](https://github.com/influxdata/telegraf/issues/6602): Add missing ServerProperties query to sqlserver input docs. +- [#6643](https://github.com/influxdata/telegraf/pull/6643): Fix mongodb connections_total_created field loading. +- [#6627](https://github.com/influxdata/telegraf/issues/6578): Fix metric creation when node is offline in jenkins input. +- [#6649](https://github.com/influxdata/telegraf/issues/6615): Fix docker uptime_ns calculation when container has been restarted. +- [#6647](https://github.com/influxdata/telegraf/issues/6646): Fix mysql field type conflict in conversion of gtid_mode to an integer. +- [#5529](https://github.com/influxdata/telegraf/issues/5529): Fix mysql field type conflict with ssl_verify_depth and ssl_ctx_verify_depth. + +## v1.12.4 [2019-10-23] + +### Release Notes + +- Official packages built with Go 1.12.12. + +### Bug Fixes + +- [#6521](https://github.com/influxdata/telegraf/issues/6521): Fix metric generation with ping input native method. +- [#6541](https://github.com/influxdata/telegraf/issues/6541): Exclude alias tag if unset from plugin internal stats. +- [#6564](https://github.com/influxdata/telegraf/issues/6564): Fix socket_mode option in powerdns_recursor input. + +## v1.12.3 [2019-10-07] + +### Bug Fixes + +- [#6445](https://github.com/influxdata/telegraf/issues/6445): Use batch serialization format in exec output. +- [#6455](https://github.com/influxdata/telegraf/issues/6455): Build official packages with Go 1.12.10. +- [#6464](https://github.com/influxdata/telegraf/pull/6464): Use case insensitive serial number match in smart input. +- [#6469](https://github.com/influxdata/telegraf/pull/6469): Add auth header only when env var is set. +- [#6468](https://github.com/influxdata/telegraf/pull/6468): Fix running multiple mysql and sqlserver plugin instances. +- [#6471](https://github.com/influxdata/telegraf/issues/6471): Fix database routing on retry with exclude_database_tag. +- [#6488](https://github.com/influxdata/telegraf/issues/6488): Fix logging panic in exec input with nagios data format. + +## v1.12.2 [2019-09-24] + +### Bug Fixes + +- [#6386](https://github.com/influxdata/telegraf/issues/6386): Fix detection of layout timestamps in csv and json parser. +- [#6394](https://github.com/influxdata/telegraf/issues/6394): Fix parsing of BATTDATE in apcupsd input. +- [#6398](https://github.com/influxdata/telegraf/issues/6398): Keep boolean values listed in json_string_fields. +- [#6393](https://github.com/influxdata/telegraf/issues/6393): Disable Go plugin support in official builds. +- [#6391](https://github.com/influxdata/telegraf/issues/6391): Fix path handling issues in cisco_telemetry_gnmi. + +## v1.12.1 [2019-09-10] + +### Bug Fixes + +- [#6344](https://github.com/influxdata/telegraf/issues/6344): Fix depends on GLIBC_2.14 symbol version. +- [#6329](https://github.com/influxdata/telegraf/issues/6329): Fix filecount for paths with trailing slash. +- [#6331](https://github.com/influxdata/telegraf/issues/6331): Convert check state to an integer in icinga2 input. +- [#6354](https://github.com/influxdata/telegraf/issues/6354): Fix could not mark message delivered error in kafka_consumer. +- [#6362](https://github.com/influxdata/telegraf/issues/6362): Skip collection stats when disabled in mongodb input. +- [#6366](https://github.com/influxdata/telegraf/issues/6366): Fix error reading closed response body on redirect in http_response. +- [#6373](https://github.com/influxdata/telegraf/issues/6373): Fix apcupsd documentation to reflect plugin. +- [#6375](https://github.com/influxdata/telegraf/issues/6375): Display retry log message only when retry after is received. + +## v1.12 [2019-09-03] + +### Release Notes + +- The cluster health related fields in the elasticsearch input have been split + out from the `elasticsearch_indices` measurement into the new + `elasticsearch_cluster_health_indices` measurement as they were originally + combined by error. + +### New Inputs + +- [apcupsd](/plugins/inputs/apcupsd/README.md) - Contributed by @jonaz +- [docker_log](/plugins/inputs/docker_log/README.md) - Contributed by @prashanthjbabu +- [fireboard](/plugins/inputs/fireboard/README.md) - Contributed by @ronnocol +- [logstash](/plugins/inputs/logstash/README.md) - Contributed by @lkmcs @dmitryilyin @arkady-emelyanov +- [marklogic](/plugins/inputs/marklogic/README.md) - Contributed by @influxdata +- [openntpd](/plugins/inputs/openntpd/README.md) - Contributed by @aromeyer +- [uwsgi](/plugins/inputs/uwsgi/README.md) - Contributed by @blaggacao + +### New Parsers + +- [form_urlencoded](/plugins/parsers/form_urlencoded/README.md) - Contributed by @byonchev + +### New Processors + +- [date](/plugins/processors/date/README.md) - Contributed by @influxdata +- [pivot](/plugins/processors/pivot/README.md) - Contributed by @influxdata +- [tag_limit](/plugins/processors/tag_limit/README.md) - Contributed by @memory +- [unpivot](/plugins/processors/unpivot/README.md) - Contributed by @influxdata + +### New Outputs + +- [exec](/plugins/outputs/exec/README.md) - Contributed by @Jaeyo + +### Features + +- [#5842](https://github.com/influxdata/telegraf/pull/5842): Improve performance of wavefront serializer. +- [#5863](https://github.com/influxdata/telegraf/pull/5863): Allow regex processor to append tag values. +- [#5997](https://github.com/influxdata/telegraf/pull/5997): Add starttime field to phpfpm input. +- [#5998](https://github.com/influxdata/telegraf/pull/5998): Add cluster name tag to elasticsearch indices. +- [#6006](https://github.com/influxdata/telegraf/pull/6006): Add support for interface field in http_response input plugin. +- [#5996](https://github.com/influxdata/telegraf/pull/5996): Add container uptime_ns in docker input plugin. +- [#6016](https://github.com/influxdata/telegraf/pull/6016): Add better user-facing errors for API timeouts in docker input. +- [#6027](https://github.com/influxdata/telegraf/pull/6027): Add TLS mutual auth support to jti_openconfig_telemetry input. +- [#6053](https://github.com/influxdata/telegraf/pull/6053): Add support for ES 7.x to elasticsearch output. +- [#6062](https://github.com/influxdata/telegraf/pull/6062): Add basic auth to prometheus input plugin. +- [#6064](https://github.com/influxdata/telegraf/pull/6064): Add node roles tag to elasticsearch input. +- [#5572](https://github.com/influxdata/telegraf/pull/5572): Support floats in statsd percentiles. +- [#6050](https://github.com/influxdata/telegraf/pull/6050): Add native Go ping method to ping input plugin. +- [#6074](https://github.com/influxdata/telegraf/pull/6074): Resume from last known offset in tail inputwhen reloading Telegraf. +- [#6111](https://github.com/influxdata/telegraf/pull/6111): Add improved support for Azure SQL Database to sqlserver input. +- [#6079](https://github.com/influxdata/telegraf/pull/6079): Add extra attributes for NVMe devices to smart input. +- [#6084](https://github.com/influxdata/telegraf/pull/6084): Add docker_devicemapper measurement to docker input plugin. +- [#6122](https://github.com/influxdata/telegraf/pull/6122): Add basic auth support to elasticsearch input. +- [#6102](https://github.com/influxdata/telegraf/pull/6102): Support string field glob matching in json parser. +- [#6101](https://github.com/influxdata/telegraf/pull/6101): Update gjson to allow multipath syntax in json parser. +- [#6144](https://github.com/influxdata/telegraf/pull/6144): Add support for collecting SQL Requests to identify waits and blocking to sqlserver input. +- [#6105](https://github.com/influxdata/telegraf/pull/6105): Collect k8s endpoints, ingress, and services in kube_inventory plugin. +- [#6129](https://github.com/influxdata/telegraf/pull/6129): Add support for field/tag keys to strings processor. +- [#6143](https://github.com/influxdata/telegraf/pull/6143): Add certificate verification status to x509_cert input. +- [#6163](https://github.com/influxdata/telegraf/pull/6163): Support percentage value parsing in redis input. +- [#6024](https://github.com/influxdata/telegraf/pull/6024): Load external Go plugins from --plugin-directory. +- [#6184](https://github.com/influxdata/telegraf/pull/6184): Add ability to exclude db/bucket tag from influxdb outputs. +- [#6137](https://github.com/influxdata/telegraf/pull/6137): Gather per collections stats in mongodb input plugin. +- [#6195](https://github.com/influxdata/telegraf/pull/6195): Add TLS & credentials configuration for nats_consumer input plugin. +- [#6194](https://github.com/influxdata/telegraf/pull/6194): Add support for enterprise repos to github plugin. +- [#6060](https://github.com/influxdata/telegraf/pull/6060): Add Indices stats to elasticsearch input. +- [#6189](https://github.com/influxdata/telegraf/pull/6189): Add left function to string processor. +- [#6049](https://github.com/influxdata/telegraf/pull/6049): Add grace period for metrics late for aggregation. +- [#4435](https://github.com/influxdata/telegraf/pull/4435): Add diff and non_negative_diff to basicstats aggregator. +- [#6201](https://github.com/influxdata/telegraf/pull/6201): Add device tags to smart_attributes. +- [#5719](https://github.com/influxdata/telegraf/pull/5719): Collect framework_offers and allocator metrics in mesos input. +- [#6216](https://github.com/influxdata/telegraf/pull/6216): Add telegraf and go version to the internal input plugin. +- [#6214](https://github.com/influxdata/telegraf/pull/6214): Update the number of logical CPUs dynamically in system plugin. +- [#6259](https://github.com/influxdata/telegraf/pull/6259): Add darwin (macOS) builds to the release. +- [#6241](https://github.com/influxdata/telegraf/pull/6241): Add configurable timeout setting to smart input. +- [#6249](https://github.com/influxdata/telegraf/pull/6249): Add memory_usage field to procstat input plugin. +- [#5971](https://github.com/influxdata/telegraf/pull/5971): Add support for custom attributes to vsphere input. +- [#5926](https://github.com/influxdata/telegraf/pull/5926): Add cmdstat metrics to redis input. +- [#6261](https://github.com/influxdata/telegraf/pull/6261): Add content_length metric to http_response input plugin. +- [#6257](https://github.com/influxdata/telegraf/pull/6257): Add database_tag option to influxdb_listener to add database from query string. +- [#6246](https://github.com/influxdata/telegraf/pull/6246): Add capability to limit TLS versions and cipher suites. +- [#6266](https://github.com/influxdata/telegraf/pull/6266): Add topic_tag option to mqtt_consumer. +- [#6207](https://github.com/influxdata/telegraf/pull/6207): Add ability to label inputs for logging. +- [#6300](https://github.com/influxdata/telegraf/pull/6300): Add TLS support to nginx_plus, nginx_plus_api and nginx_vts. + +### Bug Fixes + +- [#5692](https://github.com/influxdata/telegraf/issues/5692): Fix sensor read error stops reporting of all sensors in temp input. +- [#4356](https://github.com/influxdata/telegraf/issues/4356): Fix double pct replacement in sysstat input. +- [#6004](https://github.com/influxdata/telegraf/issues/6004): Fix race in master node detection in elasticsearch input. +- [#6100](https://github.com/influxdata/telegraf/issues/6100): Fix SSPI authentication not working in sqlserver input. +- [#6142](https://github.com/influxdata/telegraf/issues/6142): Fix memory error panic in mqtt input. +- [#6136](https://github.com/influxdata/telegraf/issues/6136): Support Kafka 2.3.0 consumer groups. +- [#6232](https://github.com/influxdata/telegraf/issues/6232): Fix persistent session in mqtt_consumer. +- [#6235](https://github.com/influxdata/telegraf/issues/6235): Fix finder inconsistencies in vsphere input. +- [#6138](https://github.com/influxdata/telegraf/issues/6138): Fix parsing multiple metrics on the first line of tailed file. +- [#2526](https://github.com/influxdata/telegraf/issues/2526): Send TERM to exec processes before sending KILL signal. +- [#5326](https://github.com/influxdata/telegraf/issues/5326): Query oplog only when connected to a replica set. +- [#6317](https://github.com/influxdata/telegraf/pull/6317): Use environment variables to locate Program Files on Windows. + +## v1.11.5 [2019-08-27] + +### Bug Fixes + +- [#6250](https://github.com/influxdata/telegraf/pull/6250): Update go-sql-driver/mysql driver to 1.4.1 to address auth issues. +- [#6279](https://github.com/influxdata/telegraf/issues/6279): Return error status from --test if input plugins produce an error. +- [#6309](https://github.com/influxdata/telegraf/issues/6309): Fix with multiple instances only last configuration is used in smart input. +- [#6303](https://github.com/influxdata/telegraf/pull/6303): Build official packages with Go 1.12.9. +- [#6234](https://github.com/influxdata/telegraf/issues/6234): Split out -w argument in iptables input. +- [#6270](https://github.com/influxdata/telegraf/issues/6270): Add support for parked process state on Linux. +- [#6287](https://github.com/influxdata/telegraf/issues/6287): Remove leading slash from rcon command. +- [#6313](https://github.com/influxdata/telegraf/pull/6313): Allow jobs with dashes in the name in lustre2 input. + +## v1.11.4 [2019-08-06] + +### Bug Fixes + +- [#6200](https://github.com/influxdata/telegraf/pull/6200): Correct typo in kubernetes logsfs_available_bytes field. +- [#6191](https://github.com/influxdata/telegraf/issues/6191): Skip floats that are NaN or Inf in Datadog output. +- [#6209](https://github.com/influxdata/telegraf/issues/6209): Fix reload panic in socket_listener input plugin. + +## v1.11.3 [2019-07-23] + +### Bug Fixes + +- [#6054](https://github.com/influxdata/telegraf/issues/6054): Fix unable to reconnect after vCenter reboot in vsphere input. +- [#6073](https://github.com/influxdata/telegraf/issues/6073): Handle unknown error in nvidia-smi output. +- [#6121](https://github.com/influxdata/telegraf/pull/6121): Fix panic in statd input when processing datadog events. +- [#6125](https://github.com/influxdata/telegraf/issues/6125): Treat empty array as successful parse in json parser. +- [#6094](https://github.com/influxdata/telegraf/issues/6094): Add missing rcode and zonestat to bind input. +- [#6114](https://github.com/influxdata/telegraf/issues/6114): Fix lustre2 input plugin config parse regression. +- [#5894](https://github.com/influxdata/telegraf/issues/5894): Fix template pattern partial wildcard matching. +- [#6151](https://github.com/influxdata/telegraf/issues/6151): Fix panic in github input. + +## v1.11.2 [2019-07-09] + +### Bug Fixes + +- [#6056](https://github.com/influxdata/telegraf/pull/6056): Fix source address ping flag on BSD. +- [#6059](https://github.com/influxdata/telegraf/issues/6059): Fix value out of range error on 32-bit systems in bind input. +- [#3573](https://github.com/influxdata/telegraf/issues/3573): Fix tail and logparser stop working after reload. +- [#6077](https://github.com/influxdata/telegraf/pull/6077): Fix filecount path separator handling in Windows. +- [#6075](https://github.com/influxdata/telegraf/issues/6075): Fix panic with empty datadog tag string. +- [#6069](https://github.com/influxdata/telegraf/issues/6069): Apply topic filter to partition metrics in burrow input. + +## v1.11.1 [2019-06-25] + +### Bug Fixes + +- [#5980](https://github.com/influxdata/telegraf/issues/5980): Cannot set mount_points option in disk input. +- [#5983](https://github.com/influxdata/telegraf/issues/5983): Omit keys when creating measurement names for GNMI telemetry. +- [#5972](https://github.com/influxdata/telegraf/issues/5972): Don't consider pid of 0 when using systemd lookup in procstat. +- [#5807](https://github.com/influxdata/telegraf/issues/5807): Skip 404 error reporting in nginx_plus_api input. +- [#5999](https://github.com/influxdata/telegraf/issues/5999): Fix panic if pool_mode column does not exist. +- [#6019](https://github.com/influxdata/telegraf/issues/6019): Add missing container_id field to docker_container_status metrics. +- [#5742](https://github.com/influxdata/telegraf/issues/5742): Ignore error when utmp is missing in system input. +- [#6032](https://github.com/influxdata/telegraf/issues/6032): Add device, serial_no, and wwn tags to synthetic attributes. +- [#6012](https://github.com/influxdata/telegraf/issues/6012): Fix parsing of remote tcp address in statsd input. + +## v1.11 [2019-06-11] + +### Release Notes + +- The `uptime_format` field in the system input has been deprecated, use the + `uptime` field instead. +- The `cloudwatch` input has been updated to use a more efficient API, it now + requires `GetMetricData` permissions instead of `GetMetricStatistics`. The + `units` tag is not available from this API and is no longer collected. + +### New Inputs + +- [bind](/plugins/inputs/bind/README.md) - Contributed by @dswarbrick & @danielllek +- [cisco_telemetry_gnmi](/plugins/inputs/cisco_telemetry_gnmi/README.md) - Contributed by @sbyx +- [cisco_telemetry_mdt](/plugins/inputs/cisco_telemetry_mdt/README.md) - Contributed by @sbyx +- [ecs](/plugins/inputs/ecs/README.md) - Contributed by @rbtr +- [github](/plugins/inputs/github/README.md) - Contributed by @influxdata +- [openweathermap](/plugins/inputs/openweathermap/README.md) - Contributed by @regel +- [powerdns_recursor](/plugins/inputs/powerdns_recursor/README.md) - Contributed by @dupondje + +### New Aggregators + +- [final](/plugins/aggregators/final/README.md) - Contributed by @oplehto + +### New Outputs + +- [syslog](/plugins/outputs/syslog/README.md) - Contributed by @javicrespo +- [health](/plugins/outputs/health/README.md) - Contributed by @influxdata + +### New Serializers + +- [wavefront](/plugins/serializers/wavefront/README.md) - Contributed by @puckpuck + +### Features + +- [#5556](https://github.com/influxdata/telegraf/pull/5556): Add TTL field to ping input. +- [#5569](https://github.com/influxdata/telegraf/pull/5569): Add hexadecimal string to integer conversion to converter processor. +- [#5601](https://github.com/influxdata/telegraf/pull/5601): Add support for multiple line text and perfdata to nagios parser. +- [#5648](https://github.com/influxdata/telegraf/pull/5648): Allow env vars ${} expansion syntax in configuration file. +- [#5641](https://github.com/influxdata/telegraf/pull/5641): Add option to reset buckets on flush to histogram aggregator. +- [#5664](https://github.com/influxdata/telegraf/pull/5664): Add option to use strict sanitization rules to wavefront output. +- [#5697](https://github.com/influxdata/telegraf/pull/5697): Add namespace restriction to prometheus input plugin. +- [#5681](https://github.com/influxdata/telegraf/pull/5681): Add cmdline tag to procstat input. +- [#5704](https://github.com/influxdata/telegraf/pull/5704): Support verbose query param in ping endpoint of influxdb_listener. +- [#5713](https://github.com/influxdata/telegraf/pull/5713): Enhance HTTP connection options for phpfpm input plugin. +- [#5544](https://github.com/influxdata/telegraf/pull/5544): Use more efficient GetMetricData API to collect cloudwatch metrics. +- [#5544](https://github.com/influxdata/telegraf/pull/5544): Allow selection of collected statistic types in cloudwatch input. +- [#5757](https://github.com/influxdata/telegraf/pull/5757): Speed up interface stat collection in net input. +- [#5769](https://github.com/influxdata/telegraf/pull/5769): Add pagefault data to procstat input plugin. +- [#5760](https://github.com/influxdata/telegraf/pull/5760): Add option to set permissions for unix domain sockets to socket_listener. +- [#5585](https://github.com/influxdata/telegraf/pull/5585): Add cli support for outputting sections of the config. +- [#5770](https://github.com/influxdata/telegraf/pull/5770): Add service-display-name option for use with Windows service. +- [#5778](https://github.com/influxdata/telegraf/pull/5778): Add support for log rotation. +- [#5765](https://github.com/influxdata/telegraf/pull/5765): Support more drive types in smart input. +- [#5829](https://github.com/influxdata/telegraf/pull/5829): Add support for HTTP basic auth to solr input. +- [#5791](https://github.com/influxdata/telegraf/pull/5791): Add support for datadog events to statsd input. +- [#5817](https://github.com/influxdata/telegraf/pull/5817): Allow devices option to match against devlinks. +- [#5855](https://github.com/influxdata/telegraf/pull/5855): Support tags in enum processor. +- [#5830](https://github.com/influxdata/telegraf/pull/5830): Add support for gzip compression to amqp plugins. +- [#5831](https://github.com/influxdata/telegraf/pull/5831): Support passive queue declaration in amqp_consumer. +- [#5901](https://github.com/influxdata/telegraf/pull/5901): Set user agent in stackdriver output. +- [#5885](https://github.com/influxdata/telegraf/pull/5885): Extend metrics collected from Nvidia GPUs. +- [#5547](https://github.com/influxdata/telegraf/pull/5547): Add file rotation support to the file output. +- [#5955](https://github.com/influxdata/telegraf/pull/5955): Add source tag to hddtemp plugin. + +### Bug Fixes + +- [#5692](https://github.com/influxdata/telegraf/pull/5692): Temperature input plugin stops working when WiFi is turned off. +- [#5631](https://github.com/influxdata/telegraf/pull/5631): Create Windows service only when specified or in service manager. +- [#5730](https://github.com/influxdata/telegraf/pull/5730): Don't start telegraf when stale pidfile found. +- [#5477](https://github.com/influxdata/telegraf/pull/5477): Support Minecraft server 1.13 and newer in minecraft input. +- [#4098](https://github.com/influxdata/telegraf/issues/4098): Fix inline table support in configuration file. +- [#1598](https://github.com/influxdata/telegraf/issues/1598): Fix multi-line basic strings support in configuration file. +- [#5746](https://github.com/influxdata/telegraf/issues/5746): Verify a process passed by pid_file exists in procstat input. +- [#5455](https://github.com/influxdata/telegraf/issues/5455): Fix unsupported pkt type error in pgbouncer. +- [#5771](https://github.com/influxdata/telegraf/pull/5771): Fix only one job per storage target reported in lustre2 input. +- [#5796](https://github.com/influxdata/telegraf/issues/5796): Set default timeout of 5s in fibaro input. +- [#5835](https://github.com/influxdata/telegraf/issues/5835): Fix docker input does not parse image name correctly. +- [#5661](https://github.com/influxdata/telegraf/issues/5661): Fix direct exchange routing key in amqp output. +- [#5819](https://github.com/influxdata/telegraf/issues/5819): Fix scale set resource id with azure_monitor output. +- [#5883](https://github.com/influxdata/telegraf/issues/5883): Skip invalid power times in apex_neptune input. +- [#3485](https://github.com/influxdata/telegraf/issues/3485): Fix sqlserver connection closing on error. +- [#5917](https://github.com/influxdata/telegraf/issues/5917): Fix toml option name in nginx_upstream_check. +- [#5920](https://github.com/influxdata/telegraf/issues/5920): Fixed datastore name mapping in vsphere input. +- [#5879](https://github.com/influxdata/telegraf/issues/5879): Fix multiple SIGHUP causes Telegraf to shutdown. +- [#5891](https://github.com/influxdata/telegraf/issues/5891): Fix connection leak in influxdb outputs on reload. +- [#5858](https://github.com/influxdata/telegraf/issues/5858): Fix batch fails when single metric is unserializable. +- [#5536](https://github.com/influxdata/telegraf/issues/5536): Log a warning on write if the metric buffer has overflowed. + +## v1.10.4 [2019-05-14] + +### Bug Fixes + +- [#5764](https://github.com/influxdata/telegraf/pull/5764): Fix race condition in the Wavefront parser. +- [#5783](https://github.com/influxdata/telegraf/pull/5783): Create telegraf user in pre-install rpm scriptlet. +- [#5792](https://github.com/influxdata/telegraf/pull/5792): Don't discard metrics on forbidden error in influxdb_v2 output. +- [#5803](https://github.com/influxdata/telegraf/issues/5803): Fix http output cannot set Host header. +- [#5619](https://github.com/influxdata/telegraf/issues/5619): Fix interval estimation in vsphere input. +- [#5782](https://github.com/influxdata/telegraf/pull/5782): Skip lines with missing refid in ntpq input. +- [#5755](https://github.com/influxdata/telegraf/issues/5755): Add support for hex values to ipmi_sensor input. +- [#5824](https://github.com/influxdata/telegraf/issues/5824): Fix parse of unix timestamp with more than ns precision. +- [#5836](https://github.com/influxdata/telegraf/issues/5836): Restore field name case in interrupts input. + +## v1.10.3 [2019-04-16] + +### Bug Fixes + +- [#5680](https://github.com/influxdata/telegraf/pull/5680): Allow colons in metric names in prometheus_client output. +- [#5716](https://github.com/influxdata/telegraf/pull/5716): Set log directory attributes in rpm spec. + +## v1.10.2 [2019-04-02] + +### Release Notes + +- String fields no longer have leading and trailing quotation marks removed in + the grok parser. If you are capturing quoted strings you may need to update + the patterns. + +### Bug Fixes + +- [#5612](https://github.com/influxdata/telegraf/pull/5612): Fix deadlock when Telegraf is aligning aggregators. +- [#5523](https://github.com/influxdata/telegraf/issues/5523): Fix missing cluster stats in ceph input. +- [#5566](https://github.com/influxdata/telegraf/pull/5566): Fix reading major and minor block devices identifiers in diskio input. +- [#5607](https://github.com/influxdata/telegraf/pull/5607): Add owned directories to rpm package spec. +- [#4998](https://github.com/influxdata/telegraf/issues/4998): Fix last character removed from string field in grok parser. +- [#5632](https://github.com/influxdata/telegraf/pull/5632): Fix drop tracking of metrics removed with aggregator drop_original. +- [#5540](https://github.com/influxdata/telegraf/pull/5540): Fix open file error handling in file output. +- [#5626](https://github.com/influxdata/telegraf/issues/5626): Fix plugin name in influxdb_v2 output logging. +- [#5621](https://github.com/influxdata/telegraf/issues/5621): Fix basedir check and parent dir extraction in filecount input. +- [#5618](https://github.com/influxdata/telegraf/issues/5618): Listen before leaving start in statsd. +- [#5595](https://github.com/influxdata/telegraf/issues/5595): Fix aggregator window alignment. +- [#5637](https://github.com/influxdata/telegraf/issues/5637): Fix panic during shutdown of multiple aggregators. +- [#5642](https://github.com/influxdata/telegraf/issues/5642): Fix parsing of kube config certificate-authority-data in prometheus input. +- [#5636](https://github.com/influxdata/telegraf/issues/5636): Fix tags applied to wrong metric on parse error. +- [#5522](https://github.com/influxdata/telegraf/issues/5522): Remove tags that would create invalid label names in prometheus output. + +## v1.10.1 [2019-03-19] + +### Bug Fixes + +- [#5448](https://github.com/influxdata/telegraf/issues/5448): Show error when TLS configuration cannot be loaded. +- [#5543](https://github.com/influxdata/telegraf/pull/5543): Add Base64-encoding/decoding for Google Cloud PubSub plugins. +- [#5565](https://github.com/influxdata/telegraf/issues/5565): Fix type compatibility in vsphere plugin with use_int_samples option. +- [#5492](https://github.com/influxdata/telegraf/issues/5492): Fix vsphere input shows failed task in vCenter. +- [#5530](https://github.com/influxdata/telegraf/issues/5530): Fix invalid measurement name and skip column in csv parser. +- [#5589](https://github.com/influxdata/telegraf/issues/5589): Fix system input causing high cpu usage on Raspbian. +- [#5575](https://github.com/influxdata/telegraf/issues/5575): Don't add empty healthcheck tags to consul input. + +## v1.10 [2019-03-05] + +### New Inputs + +- [cloud_pubsub](/plugins/inputs/cloud_pubsub/README.md) - Contributed by @emilymye +- [cloud_pubsub_push](/plugins/inputs/cloud_pubsub_push/README.md) - Contributed by @influxdata +- [kinesis_consumer](/plugins/inputs/kinesis_consumer/README.md) - Contributed by @influxdata +- [kube_inventory](/plugins/inputs/kube_inventory/README.md) - Contributed by @influxdata +- [neptune_apex](/plugins/inputs/neptune_apex/README.md) - Contributed by @MaxRenaud +- [nginx_upstream_check](/plugins/inputs/nginx_upstream_check/README.md) - Contributed by @dmitryilyin +- [multifile](/plugins/inputs/multifile/README.md) - Contributed by @martin2250 +- [stackdriver](/plugins/inputs/stackdriver/README.md) - Contributed by @WuHan0608 + +### New Outputs + +- [cloud_pubsub](/plugins/outputs/cloud_pubsub/README.md) - Contributed by @emilymye + +### New Serializers + +- [nowmetric](/plugins/serializers/nowmetric/README.md) - Contributed by @JefMuller +- [carbon2](/plugins/serializers/carbon2/README.md) - Contributed by @frankreno + +### Features + +- [#4345](https://github.com/influxdata/telegraf/pull/4345): Allow for force gathering ES cluster stats. +- [#5047](https://github.com/influxdata/telegraf/pull/5047): Add support for unix and unix_ms timestamps to csv parser. +- [#5038](https://github.com/influxdata/telegraf/pull/5038): Add ability to tag metrics with topic in kafka_consumer. +- [#5024](https://github.com/influxdata/telegraf/pull/5024): Add option to store cpu as a tag in interrupts input. +- [#5074](https://github.com/influxdata/telegraf/pull/5074): Add support for sending a request body to http input. +- [#5069](https://github.com/influxdata/telegraf/pull/5069): Add running field to procstat_lookup. +- [#5116](https://github.com/influxdata/telegraf/pull/5116): Include DEVLINKS in available diskio udev properties. +- [#5149](https://github.com/influxdata/telegraf/pull/5149): Add micro and nanosecond unix timestamp support to JSON parser. +- [#5160](https://github.com/influxdata/telegraf/pull/5160): Add support for basic auth to couchdb input. +- [#5161](https://github.com/influxdata/telegraf/pull/5161): Add support in wavefront output for the Wavefront Direct Ingestion API. +- [#5168](https://github.com/influxdata/telegraf/pull/5168): Allow counting float values in valuecounter aggregator. +- [#5177](https://github.com/influxdata/telegraf/pull/5177): Add log send and redo queue fields to sqlserver input. +- [#5113](https://github.com/influxdata/telegraf/pull/5113): Improve scalability of vsphere input. +- [#5210](https://github.com/influxdata/telegraf/pull/5210): Add read and write op per second fields to ceph input. +- [#5214](https://github.com/influxdata/telegraf/pull/5214): Add configurable timeout to varnish input. +- [#5273](https://github.com/influxdata/telegraf/pull/5273): Add flush_total_time_ns and additional wired tiger fields to mongodb input. +- [#5295](https://github.com/influxdata/telegraf/pull/5295): Support passing bearer token directly in k8s input. +- [#5294](https://github.com/influxdata/telegraf/pull/5294): Support passing bearer token directly in prometheus input. +- [#5292](https://github.com/influxdata/telegraf/pull/5292): Add option to report input timestamp in prometheus output. +- [#5234](https://github.com/influxdata/telegraf/pull/5234): Add Linux mipsle packages. +- [#5382](https://github.com/influxdata/telegraf/pull/5382): Support unix_us and unix_ns timestamp format in csv parser. +- [#5391](https://github.com/influxdata/telegraf/pull/5391): Add resource type and resource label support to stackdriver output. +- [#5396](https://github.com/influxdata/telegraf/pull/5396): Add internal metric for line too long in influxdb_listener. +- [#4892](https://github.com/influxdata/telegraf/pull/4892): Add option to set retain flag on messages to mqtt output. +- [#5165](https://github.com/influxdata/telegraf/pull/5165): Add resource path based filtering to vsphere input. +- [#5417](https://github.com/influxdata/telegraf/pull/5417): Add rcode tag and field to dns_query input. +- [#5453](https://github.com/influxdata/telegraf/pull/5453): Support Azure Sovereign Environments with endpoint_url option. +- [#5472](https://github.com/influxdata/telegraf/pull/5472): Support configuring a default timezone in JSON parser. +- [#5482](https://github.com/influxdata/telegraf/pull/5482): Add ceph_health metrics to ceph input. +- [#5488](https://github.com/influxdata/telegraf/pull/5488): Add option to disable unique timestamp adjustment in grok parser. +- [#5473](https://github.com/influxdata/telegraf/pull/5473): Add mutual TLS support to prometheus_client output. +- [#4308](https://github.com/influxdata/telegraf/pull/4308): Add additional metrics to rabbitmq input. +- [#5388](https://github.com/influxdata/telegraf/pull/5388): Add multicast support to socket_listener input. +- [#5490](https://github.com/influxdata/telegraf/pull/5490): Add tag based routing in influxdb/influxdb_v2 outputs. +- [#5533](https://github.com/influxdata/telegraf/pull/5533): Allow grok parser to produce metrics with no fields. + +### Bug Fixes + +- [#4610](https://github.com/influxdata/telegraf/pull/4610): Fix initscript removes pidfile of restarted Telegraf process. +- [#5320](https://github.com/influxdata/telegraf/pull/5320): Use datacenter option spelling in consul input. +- [#5316](https://github.com/influxdata/telegraf/pull/5316): Remove auth from /ping route in influxdb_listener. +- [#5304](https://github.com/influxdata/telegraf/issues/5304): Fix x509_cert input stops checking certs after first error. +- [#5404](https://github.com/influxdata/telegraf/issues/5404): Group stackdriver requests to send one point per timeseries. +- [#5449](https://github.com/influxdata/telegraf/issues/5449): Log permission error and ignore in filecount input. +- [#5497](https://github.com/influxdata/telegraf/pull/5497): Create log file in append mode. +- [#5325](https://github.com/influxdata/telegraf/issues/5325): Ignore tracking for metrics added to aggregator. +- [#5514](https://github.com/influxdata/telegraf/issues/5514): Fix panic when rejecting empty batch. +- [#5518](https://github.com/influxdata/telegraf/pull/5518): Fix conversion from string float to integer. +- [#5431](https://github.com/influxdata/telegraf/pull/5431): Sort metrics by timestamp in prometheus output. + +## v1.9.5 [2019-02-26] + +### Bug Fixes + +- [#5315](https://github.com/influxdata/telegraf/issues/5315): Skip string fields when writing to stackdriver output. +- [#5364](https://github.com/influxdata/telegraf/issues/5364): Send metrics in ascending time order in stackdriver output. +- [#5117](https://github.com/influxdata/telegraf/issues/5117): Use systemd in Amazon Linux 2 rpm. +- [#4988](https://github.com/influxdata/telegraf/issues/4988): Set deadlock priority in sqlserver input. +- [#5403](https://github.com/influxdata/telegraf/issues/5403): Remove error log when snmp6 directory does not exists with nstat input. +- [#5437](https://github.com/influxdata/telegraf/issues/5437): Host not added when using custom arguments in ping plugin. +- [#5438](https://github.com/influxdata/telegraf/issues/5438): Fix InfluxDB output UDP line splitting. +- [#5456](https://github.com/influxdata/telegraf/issues/5456): Disable results by row in azuredb query. +- [#5277](https://github.com/influxdata/telegraf/issues/5277): Add backwards compatibility fields in ceph usage and pool stats. + +## v1.9.4 [2019-02-05] + +### Bug Fixes + +- [#5334](https://github.com/influxdata/telegraf/issues/5334): Fix skip_rows and skip_columns options in csv parser. +- [#5181](https://github.com/influxdata/telegraf/issues/5181): Always send basic auth in jenkins input. +- [#5346](https://github.com/influxdata/telegraf/pull/5346): Build official packages with Go 1.11.5. +- [#5368](https://github.com/influxdata/telegraf/issues/5368): Fix definition of multiple syslog plugins. + +## v1.9.3 [2019-01-22] + +### Bug Fixes + +- [#5261](https://github.com/influxdata/telegraf/pull/5261): Fix arithmetic overflow in sqlserver input. +- [#5194](https://github.com/influxdata/telegraf/issues/5194): Fix latest metrics not sent first when output fails. +- [#5285](https://github.com/influxdata/telegraf/issues/5285): Fix amqp_consumer stops consuming when it receives unparsable messages. +- [#5281](https://github.com/influxdata/telegraf/issues/5281): Fix prometheus input not detecting added and removed pods. +- [#5215](https://github.com/influxdata/telegraf/issues/5215): Remove userinfo from cluster tag in couchbase. +- [#5298](https://github.com/influxdata/telegraf/issues/5298): Fix internal_write buffer_size not reset on timed writes. + +## v1.9.2 [2019-01-08] + +### Bug Fixes + +- [#5130](https://github.com/influxdata/telegraf/pull/5130): Increase varnishstat timeout. +- [#5135](https://github.com/influxdata/telegraf/pull/5135): Remove storage calculation for non Azure managed instances and add server version. +- [#5083](https://github.com/influxdata/telegraf/pull/5083): Fix error sending empty tag value in azure_monitor output. +- [#5143](https://github.com/influxdata/telegraf/issues/5143): Fix panic with prometheus input plugin on shutdown. +- [#4482](https://github.com/influxdata/telegraf/issues/4482): Support non-transparent framing of syslog messages. +- [#5151](https://github.com/influxdata/telegraf/issues/5151): Apply global and plugin level metric modifications before filtering. +- [#5167](https://github.com/influxdata/telegraf/pull/5167): Fix num_remapped_pgs field in ceph plugin. +- [#5179](https://github.com/influxdata/telegraf/issues/5179): Add PDH_NO_DATA to known counter error codes in win_perf_counters. +- [#5170](https://github.com/influxdata/telegraf/issues/5170): Fix amqp_consumer stops consuming on empty message. +- [#4906](https://github.com/influxdata/telegraf/issues/4906): Fix multiple replace tables not working in strings processor. +- [#5219](https://github.com/influxdata/telegraf/issues/5219): Allow non local udp connections in net_response. +- [#5218](https://github.com/influxdata/telegraf/issues/5218): Fix toml option names in parser processor. +- [#5225](https://github.com/influxdata/telegraf/issues/5225): Fix panic in docker input with bad endpoint. +- [#5209](https://github.com/influxdata/telegraf/issues/5209): Fix original metric modified by aggregator filters. + +## v1.9.1 [2018-12-11] + +### Bug Fixes + +- [#5006](https://github.com/influxdata/telegraf/issues/5006): Fix boolean handling in splunkmetric serializer. +- [#5046](https://github.com/influxdata/telegraf/issues/5046): Set default config values in jenkins input. +- [#4664](https://github.com/influxdata/telegraf/issues/4664): Fix server connection and document stats in mongodb input. +- [#5010](https://github.com/influxdata/telegraf/issues/5010): Add X-Requested-By header to graylog input. +- [#5052](https://github.com/influxdata/telegraf/issues/5052): Fix metric memory not freed from the metric buffer on write. +- [#3817](https://github.com/influxdata/telegraf/issues/3817): Add support for client tls certificates in postgresql inputs. +- [#5082](https://github.com/influxdata/telegraf/issues/5082): Prevent panic when marking the offset in kafka_consumer. +- [#5084](https://github.com/influxdata/telegraf/issues/5084): Add early metrics to aggregator and honor drop_original setting. +- [#5112](https://github.com/influxdata/telegraf/pull/5112): Use -W flag on bsd variants in ping input. +- [#5114](https://github.com/influxdata/telegraf/issues/5114): Allow delta metrics in wavefront parser. + +## v1.9 [2018-11-20] + +### Release Notes + +- The `http_listener` input plugin has been renamed to `influxdb_listener` and + use of the original name is deprecated. The new name better describes the + intended use of the plugin as a InfluxDB relay. For general purpose + transfer of metrics in any format via HTTP, it is recommended to use + `http_listener_v2` instead. + +- Input plugins are no longer limited from adding metrics when the output is + writing, and new metrics will move into the metric buffer as needed. This + will provide more robust degradation and recovery when writing to a slow + output at high throughput. + + To avoid over consumption when reading from queue consumers: `kafka_consumer`, + `amqp_consumer`, `mqtt_consumer`, `nats_consumer`, and `nsq_consumer` use + the new option `max_undelivered_messages` to limit the number of outstanding + unwritten metrics. + +### New Inputs + +- [http_listener_v2](/plugins/inputs/http_listener_v2/README.md) - Contributed by @jul1u5 +- [ipvs](/plugins/inputs/ipvs/README.md) - Contributed by @amoghe +- [jenkins](/plugins/inputs/jenkins/README.md) - Contributed by @influxdata & @lpic10 +- [nginx_plus_api](/plugins/inputs/nginx_plus_api/README.md) - Contributed by @Bugagazavr +- [nginx_vts](/plugins/inputs/nginx_vts/README.md) - Contributed by @monder +- [wireless](/plugins/inputs/wireless/README.md) - Contributed by @jamesmaidment + +### New Outputs + +- [stackdriver](/plugins/outputs/stackdriver/README.md) - Contributed by @jamesmaidment + +### Features + +- [#4686](https://github.com/influxdata/telegraf/pull/4686): Add replace function to strings processor. +- [#4754](https://github.com/influxdata/telegraf/pull/4754): Query servers in parallel in dns_query input. +- [#4753](https://github.com/influxdata/telegraf/pull/4753): Add ability to define a custom service name when installing as a Windows service. +- [#4703](https://github.com/influxdata/telegraf/pull/4703): Add support for IPv6 in the ping plugin. +- [#4781](https://github.com/influxdata/telegraf/pull/4781): Add new config for csv column explicit type conversion. +- [#4800](https://github.com/influxdata/telegraf/pull/4800): Add an option to specify a custom datadog URL. +- [#4803](https://github.com/influxdata/telegraf/pull/4803): Use non-allocating field and tag accessors in datadog output. +- [#4752](https://github.com/influxdata/telegraf/pull/4752): Add per-directory file counts in the filecount input. +- [#4811](https://github.com/influxdata/telegraf/pull/4811): Add windows service name lookup to procstat input. +- [#4807](https://github.com/influxdata/telegraf/pull/4807): Add entity-body compression to http output. +- [#4838](https://github.com/influxdata/telegraf/pull/4838): Add telegraf version to User-Agent header. +- [#4864](https://github.com/influxdata/telegraf/pull/4864): Use DescribeStreamSummary in place of ListStreams in kinesis output. +- [#4852](https://github.com/influxdata/telegraf/pull/4852): Add ability to specify bytes options as strings with units. +- [#3903](https://github.com/influxdata/telegraf/pull/3903): Add support for TLS configuration in NSQ input. +- [#4914](https://github.com/influxdata/telegraf/pull/4914): Collect additional stats in memcached input. +- [#3847](https://github.com/influxdata/telegraf/pull/3847): Add wireless input plugin. +- [#4934](https://github.com/influxdata/telegraf/pull/4934): Add LUN to datasource translation in vsphere input. +- [#4798](https://github.com/influxdata/telegraf/pull/4798): Allow connecting to prometheus via unix socket. +- [#4920](https://github.com/influxdata/telegraf/pull/4920): Add scraping for Prometheus endpoint in Kubernetes. +- [#4938](https://github.com/influxdata/telegraf/pull/4938): Add per output flush_interval, metric_buffer_limit and metric_batch_size. + +### Bug Fixes + +- [#4950](https://github.com/influxdata/telegraf/pull/4950): Remove the time_key from the field values in JSON parser. +- [#3968](https://github.com/influxdata/telegraf/issues/3968): Fix input time rounding when using a custom interval. +- [#4938](https://github.com/influxdata/telegraf/pull/4938): Fix potential deadlock or leaked resources on restart/reload. +- [#2919](https://github.com/influxdata/telegraf/pull/2919): Fix outputs block inputs when batch size is reached. +- [#4789](https://github.com/influxdata/telegraf/issues/4789): Fix potential missing datastore metrics in vSphere plugin. +- [#4982](https://github.com/influxdata/telegraf/issues/4982): Log warning when wireless plugin is used on unsupported platform. +- [#4965](https://github.com/influxdata/telegraf/issues/4965): Handle non-tls columns for mysql input. +- [#4983](https://github.com/influxdata/telegraf/issues/4983): Fix panic in influxdb_listener when using gzip encoding. + +## v1.8.3 [2018-10-30] + +### Bug Fixes + +- [#4873](https://github.com/influxdata/telegraf/pull/4873): Add DN attributes as tags in x509_cert input to avoid series overwrite. +- [#4921](https://github.com/influxdata/telegraf/issues/4921): Prevent connection leak by closing unused connections in amqp output. +- [#4904](https://github.com/influxdata/telegraf/issues/4904): Use default partition key when tag does not exist in kinesis output. +- [#4901](https://github.com/influxdata/telegraf/pull/4901): Log the correct error in jti_openconfig. +- [#4937](https://github.com/influxdata/telegraf/pull/4937): Handle panic when ipmi_sensor input gets bad input. +- [#4930](https://github.com/influxdata/telegraf/pull/4930): Don't add unserializable fields to jolokia2 input. +- [#4866](https://github.com/influxdata/telegraf/pull/4866): Fix version check in postgresql_extensible. + +## v1.8.2 [2018-10-17] + +### Bug Fixes + +- [#4844](https://github.com/influxdata/telegraf/pull/4844): Update write path to match updated InfluxDB v2 API. +- [#4840](https://github.com/influxdata/telegraf/pull/4840): Fix missing timeouts in vsphere input. +- [#4851](https://github.com/influxdata/telegraf/pull/4851): Support uint fields in aerospike input. +- [#4854](https://github.com/influxdata/telegraf/pull/4854): Use container name from list if no name in container stats. +- [#4850](https://github.com/influxdata/telegraf/pull/4850): Prevent panic in filecount input on error in file stat. +- [#4846](https://github.com/influxdata/telegraf/pull/4846): Fix mqtt_consumer connect and reconnect. +- [#4849](https://github.com/influxdata/telegraf/pull/4849): Fix panic in logparser input. +- [#4869](https://github.com/influxdata/telegraf/pull/4869): Lower authorization errors to debug level in mongodb input. +- [#4875](https://github.com/influxdata/telegraf/pull/4875): Return correct response code on ping input. +- [#4874](https://github.com/influxdata/telegraf/pull/4874): Fix segfault in x509_cert input. + +## v1.8.1 [2018-10-03] + +### Bug Fixes + +- [#4750](https://github.com/influxdata/telegraf/pull/4750): Fix hardware_type may be truncated in sqlserver input. +- [#4723](https://github.com/influxdata/telegraf/issues/4723): Improve performance in basicstats aggregator. +- [#4747](https://github.com/influxdata/telegraf/pull/4747): Add hostname to TLS config for SNI support. +- [#4675](https://github.com/influxdata/telegraf/issues/4675): Don't add tags with empty values to opentsdb output. +- [#4765](https://github.com/influxdata/telegraf/pull/4765): Fix panic during network error in vsphere input. +- [#4766](https://github.com/influxdata/telegraf/pull/4766): Unify http_listener error response with InfluxDB. +- [#4769](https://github.com/influxdata/telegraf/pull/4769): Add UUID to VMs in vSphere input. +- [#4758](https://github.com/influxdata/telegraf/issues/4758): Skip tags with empty values in cloudwatch output. +- [#4783](https://github.com/influxdata/telegraf/issues/4783): Fix missing non-realtime samples in vSphere input. +- [#4799](https://github.com/influxdata/telegraf/pull/4799): Fix case of timezone/grok_timezone options. + +## v1.8 [2018-09-21] + +### New Inputs + +- [activemq](./plugins/inputs/activemq/README.md) - Contributed by @mlabouardy +- [beanstalkd](./plugins/inputs/beanstalkd/README.md) - Contributed by @44px +- [filecount](./plugins/inputs/filecount/README.md) - Contributed by @sometimesfood +- [file](./plugins/inputs/file/README.md) - Contributed by @maxunt +- [icinga2](./plugins/inputs/icinga2/README.md) - Contributed by @mlabouardy +- [kibana](./plugins/inputs/kibana/README.md) - Contributed by @lpic10 +- [pgbouncer](./plugins/inputs/pgbouncer/README.md) - Contributed by @nerzhul +- [temp](./plugins/inputs/temp/README.md) - Contributed by @pytimer +- [tengine](./plugins/inputs/tengine/README.md) - Contributed by @ertaoxu +- [vsphere](./plugins/inputs/vsphere/README.md) - Contributed by @prydin +- [x509_cert](./plugins/inputs/x509_cert/README.md) - Contributed by @jtyr + +### New Processors + +- [enum](./plugins/processors/enum/README.md) - Contributed by @KarstenSchnitter +- [parser](./plugins/processors/parser/README.md) - Contributed by @Ayrdrie & @maxunt +- [rename](./plugins/processors/rename/README.md) - Contributed by @goldibex +- [strings](./plugins/processors/strings/README.md) - Contributed by @bsmaldon + +### New Aggregators + +- [valuecounter](./plugins/aggregators/valuecounter/README.md) - Contributed by @piotr1212 + +### New Outputs + +- [azure_monitor](./plugins/outputs/azure_monitor/README.md) - Contributed by @influxdata +- [influxdb_v2](./plugins/outputs/influxdb_v2/README.md) - Contributed by @influxdata + +### New Parsers + +- [csv](/plugins/parsers/csv/README.md) - Contributed by @maxunt +- [grok](/plugins/parsers/grok/README.md) - Contributed by @maxunt +- [logfmt](/plugins/parsers/logfmt/README.md) - Contributed by @Ayrdrie & @maxunt +- [wavefront](/plugins/parsers/wavefront/README.md) - Contributed by @puckpuck + +### New Serializers + +- [splunkmetric](/plugins/serializers/splunkmetric/README.md) - Contributed by @ronnocol + +### Features + +- [#4236](https://github.com/influxdata/telegraf/pull/4236): Add SSL/TLS support to redis input. +- [#4160](https://github.com/influxdata/telegraf/pull/4160): Add tengine input plugin. +- [#4262](https://github.com/influxdata/telegraf/pull/4262): Add power draw field to nvidia_smi plugin. +- [#4271](https://github.com/influxdata/telegraf/pull/4271): Add support for solr 7 to the solr input. +- [#4281](https://github.com/influxdata/telegraf/pull/4281): Add owner tag on partitions in burrow input. +- [#4259](https://github.com/influxdata/telegraf/pull/4259): Add container status tag to docker input. +- [#3523](https://github.com/influxdata/telegraf/pull/3523): Add valuecounter aggregator plugin. +- [#4307](https://github.com/influxdata/telegraf/pull/4307): Add new measurement with results of pgrep lookup to procstat input. +- [#4311](https://github.com/influxdata/telegraf/pull/4311): Add support for comma in logparser timestamp format. +- [#4292](https://github.com/influxdata/telegraf/pull/4292): Add path tag to tail input plugin. +- [#4322](https://github.com/influxdata/telegraf/pull/4322): Add log message when tail is added or removed from a file. +- [#4267](https://github.com/influxdata/telegraf/pull/4267): Add option to use of counter time in win perf counters. +- [#4343](https://github.com/influxdata/telegraf/pull/4343): Add energy and power field and device id tag to fibaro input. +- [#4347](https://github.com/influxdata/telegraf/pull/4347): Add http path configuration for OpenTSDB output. +- [#4352](https://github.com/influxdata/telegraf/pull/4352): Gather IPMI metrics concurrently. +- [#4362](https://github.com/influxdata/telegraf/pull/4362): Add mongo document and connection metrics. +- [#3772](https://github.com/influxdata/telegraf/pull/3772): Add enum processor plugin. +- [#4386](https://github.com/influxdata/telegraf/pull/4386): Add user tag to procstat input. +- [#4403](https://github.com/influxdata/telegraf/pull/4403): Add support for multivalue metrics to collectd parser. +- [#4418](https://github.com/influxdata/telegraf/pull/4418): Add support for setting kafka client id. +- [#4332](https://github.com/influxdata/telegraf/pull/4332): Add file input plugin and grok parser. +- [#4320](https://github.com/influxdata/telegraf/pull/4320): Improve cloudwatch output performance. +- [#3768](https://github.com/influxdata/telegraf/pull/3768): Add x509_cert input plugin. +- [#4471](https://github.com/influxdata/telegraf/pull/4471): Add IPSIpAddress syntax to ipaddr conversion in snmp plugin. +- [#4363](https://github.com/influxdata/telegraf/pull/4363): Add filecount input plugin. +- [#4485](https://github.com/influxdata/telegraf/pull/4485): Add support for configuring an AWS endpoint_url. +- [#4491](https://github.com/influxdata/telegraf/pull/4491): Send all messages before waiting for results in kafka output. +- [#4492](https://github.com/influxdata/telegraf/pull/4492): Add support for lz4 compression to kafka output. +- [#4450](https://github.com/influxdata/telegraf/pull/4450): Split multiple sensor keys in ipmi input. +- [#4364](https://github.com/influxdata/telegraf/pull/4364): Support StatisticValues in cloudwatch output plugin. +- [#4431](https://github.com/influxdata/telegraf/pull/4431): Add ip restriction for the prometheus_client output. +- [#3918](https://github.com/influxdata/telegraf/pull/3918): Add pgbouncer input plugin. +- [#2689](https://github.com/influxdata/telegraf/pull/2689): Add ActiveMQ input plugin. +- [#4402](https://github.com/influxdata/telegraf/pull/4402): Add wavefront parser plugin. +- [#4528](https://github.com/influxdata/telegraf/pull/4528): Add rename processor plugin. +- [#4537](https://github.com/influxdata/telegraf/pull/4537): Add message 'max_bytes' configuration to kafka input. +- [#4546](https://github.com/influxdata/telegraf/pull/4546): Add gopsutil meminfo fields to mem plugin. +- [#4285](https://github.com/influxdata/telegraf/pull/4285): Document how to parse telegraf logs. +- [#4542](https://github.com/influxdata/telegraf/pull/4542): Use dep v0.5.0. +- [#4433](https://github.com/influxdata/telegraf/pull/4433): Add ability to set measurement from matched text in grok parser. +- [#4565](https://github.com/influxdata/telegraf/pull/4465): Drop message batches in kafka output if too large. +- [#4579](https://github.com/influxdata/telegraf/pull/4579): Add support for static and random routing keys in kafka output. +- [#4539](https://github.com/influxdata/telegraf/pull/4539): Add logfmt parser plugin. +- [#4551](https://github.com/influxdata/telegraf/pull/4551): Add parser processor plugin. +- [#4559](https://github.com/influxdata/telegraf/pull/4559): Add Icinga2 input plugin. +- [#4351](https://github.com/influxdata/telegraf/pull/4351): Add name, time, path and string field options to JSON parser. +- [#4571](https://github.com/influxdata/telegraf/pull/4571): Add forwarded records to sqlserver input. +- [#4585](https://github.com/influxdata/telegraf/pull/4585): Add Kibana input plugin. +- [#4439](https://github.com/influxdata/telegraf/pull/4439): Add csv parser plugin. +- [#4598](https://github.com/influxdata/telegraf/pull/4598): Add read_buffer_size option to statsd input. +- [#4089](https://github.com/influxdata/telegraf/pull/4089): Add azure_monitor output plugin. +- [#4628](https://github.com/influxdata/telegraf/pull/4628): Add queue_durability parameter to amqp_consumer input. +- [#4476](https://github.com/influxdata/telegraf/pull/4476): Add strings processor. +- [#4536](https://github.com/influxdata/telegraf/pull/4536): Add OAuth2 support to HTTP output plugin. +- [#4633](https://github.com/influxdata/telegraf/pull/4633): Add Unix epoch timestamp support for JSON parser. +- [#4657](https://github.com/influxdata/telegraf/pull/4657): Add options for basic auth to haproxy input. +- [#4411](https://github.com/influxdata/telegraf/pull/4411): Add temp input plugin. +- [#4272](https://github.com/influxdata/telegraf/pull/4272): Add Beanstalkd input plugin. +- [#4669](https://github.com/influxdata/telegraf/pull/4669): Add means to specify server password for redis input. +- [#4339](https://github.com/influxdata/telegraf/pull/4339): Add Splunk Metrics serializer. +- [#4141](https://github.com/influxdata/telegraf/pull/4141): Add input plugin for VMware vSphere. +- [#4667](https://github.com/influxdata/telegraf/pull/4667): Align metrics window to interval in cloudwatch input. +- [#4642](https://github.com/influxdata/telegraf/pull/4642): Improve Azure Managed Instance support + more in sqlserver input. +- [#4682](https://github.com/influxdata/telegraf/pull/4682): Allow alternate binaries for iptables input plugin. +- [#4645](https://github.com/influxdata/telegraf/pull/4645): Add influxdb_v2 output plugin. + +### Bug Fixes + +- [#3438](https://github.com/influxdata/telegraf/issues/3438): Fix divide by zero in logparser input. +- [#4499](https://github.com/influxdata/telegraf/issues/4499): Fix instance and object name in performance counters with backslashes. +- [#4646](https://github.com/influxdata/telegraf/issues/4646): Reset/flush saved contents from bad metric. +- [#4520](https://github.com/influxdata/telegraf/issues/4520): Document all supported cli arguments. +- [#4674](https://github.com/influxdata/telegraf/pull/4674): Log access denied opening a service at debug level in win_services. +- [#4588](https://github.com/influxdata/telegraf/issues/4588): Add support for Kafka 2.0. +- [#4087](https://github.com/influxdata/telegraf/issues/4087): Fix nagios parser does not support ranges in performance data. +- [#4088](https://github.com/influxdata/telegraf/issues/4088): Fix nagios parser does not strip quotes from performance data. +- [#4688](https://github.com/influxdata/telegraf/issues/4688): Fix null value crash in postgresql_extensible input. +- [#4681](https://github.com/influxdata/telegraf/pull/4681): Remove the startup authentication check from the cloudwatch output. +- [#4644](https://github.com/influxdata/telegraf/issues/4644): Support tailing files created after startup in tail input. +- [#4706](https://github.com/influxdata/telegraf/issues/4706): Fix csv format configuration loading. + +## v1.7.4 [2018-08-29] + +### Bug Fixes + +- [#4534](https://github.com/influxdata/telegraf/pull/4534): Skip unserializable metric in influxDB UDP output. +- [#4554](https://github.com/influxdata/telegraf/pull/4554): Fix powerdns input tests. +- [#4584](https://github.com/influxdata/telegraf/pull/4584): Fix burrow_group offset calculation for burrow input. +- [#4550](https://github.com/influxdata/telegraf/pull/4550): Add result_code value for errors running ping command. +- [#4605](https://github.com/influxdata/telegraf/pull/4605): Remove timeout deadline for udp syslog input. +- [#4601](https://github.com/influxdata/telegraf/issues/4601): Ensure channel closed if an error occurs in cgroup input. +- [#4544](https://github.com/influxdata/telegraf/issues/4544): Fix sending of basic auth credentials in http output. +- [#4526](https://github.com/influxdata/telegraf/issues/4526): Use the correct GOARM value in the armel package. + +## v1.7.3 [2018-08-07] + +### Bug Fixes + +- [#4434](https://github.com/influxdata/telegraf/issues/4434): Reduce required docker API version. +- [#4498](https://github.com/influxdata/telegraf/pull/4498): Keep leading whitespace for messages in syslog input. +- [#4470](https://github.com/influxdata/telegraf/issues/4470): Skip bad entries on interrupt input. +- [#4501](https://github.com/influxdata/telegraf/issues/4501): Preserve metric type when using filters in output plugins. +- [#3794](https://github.com/influxdata/telegraf/issues/3794): Fix error message if URL is unparsable in influxdb output. +- [#4059](https://github.com/influxdata/telegraf/issues/4059): Use explicit zpool properties to fix parse error on FreeBSD 11.2. +- [#4514](https://github.com/influxdata/telegraf/pull/4514): Lock buffer when adding metrics. + +## v1.7.2 [2018-07-18] + +### Bug Fixes + +- [#4381](https://github.com/influxdata/telegraf/issues/4381): Use localhost as default server tag in zookeeper input. +- [#4374](https://github.com/influxdata/telegraf/issues/4374): Don't set values when pattern doesn't match in regex processor. +- [#4416](https://github.com/influxdata/telegraf/issues/4416): Fix output format of printer processor. +- [#4422](https://github.com/influxdata/telegraf/issues/4422): Fix metric can have duplicate field. +- [#4389](https://github.com/influxdata/telegraf/issues/4389): Return error if NewRequest fails in http output. +- [#4335](https://github.com/influxdata/telegraf/issues/4335): Reset read deadline for syslog input. +- [#4375](https://github.com/influxdata/telegraf/issues/4375): Exclude cached memory on docker input plugin. + +## v1.7.1 [2018-07-03] + +### Bug Fixes + +- [#4277](https://github.com/influxdata/telegraf/pull/4277): Treat sigterm as a clean shutdown signal. +- [#4284](https://github.com/influxdata/telegraf/pull/4284): Fix selection of tags under nested objects in the JSON parser. +- [#4135](https://github.com/influxdata/telegraf/issues/4135): Fix postfix input handling multi-level queues. +- [#4334](https://github.com/influxdata/telegraf/pull/4334): Fix syslog timestamp parsing with single digit day of month. +- [#2910](https://github.com/influxdata/telegraf/issues/2910): Handle mysql input variations in the user_statistics collecting. +- [#4293](https://github.com/influxdata/telegraf/issues/4293): Fix minmax and basicstats aggregators to use uint64. +- [#4290](https://github.com/influxdata/telegraf/issues/4290): Document swap input plugin. +- [#4316](https://github.com/influxdata/telegraf/issues/4316): Fix incorrect precision being applied to metric in http_listener. + +## v1.7 [2018-06-12] + +### Release Notes + +- The `cassandra` input plugin has been deprecated in favor of the `jolokia2` + input plugin which is much more configurable and more performant. There is + an [example configuration](./plugins/inputs/jolokia2/examples) to help you + get started. + +- For plugins supporting TLS, you can now specify the certificate and keys + using `tls_ca`, `tls_cert`, `tls_key`. These options behave the same as + the, now deprecated, `ssl` forms. + +### New Inputs + +- [aurora](./plugins/inputs/aurora/README.md) - Contributed by @influxdata +- [burrow](./plugins/inputs/burrow/README.md) - Contributed by @arkady-emelyanov +- [fibaro](./plugins/inputs/fibaro/README.md) - Contributed by @dynek +- [jti_openconfig_telemetry](./plugins/inputs/jti_openconfig_telemetry/README.md) - Contributed by @ajhai +- [mcrouter](./plugins/inputs/mcrouter/README.md) - Contributed by @cthayer +- [nvidia_smi](./plugins/inputs/nvidia_smi/README.md) - Contributed by @jackzampolin +- [syslog](./plugins/inputs/syslog/README.md) - Contributed by @influxdata + +### New Processors + +- [converter](./plugins/processors/converter/README.md) - Contributed by @influxdata +- [regex](./plugins/processors/regex/README.md) - Contributed by @44px +- [topk](./plugins/processors/topk/README.md) - Contributed by @mirath + +### New Outputs + +- [http](./plugins/outputs/http/README.md) - Contributed by @Dark0096 +- [application_insights](./plugins/outputs/application_insights/README.md): Contribute by @karolz-ms + +### Features + +- [#3964](https://github.com/influxdata/telegraf/pull/3964): Add repl_oplog_window_sec metric to mongodb input. +- [#3819](https://github.com/influxdata/telegraf/pull/3819): Add per-host shard metrics in mongodb input. +- [#3999](https://github.com/influxdata/telegraf/pull/3999): Skip files with leading `..` in config directory. +- [#4021](https://github.com/influxdata/telegraf/pull/4021): Add TLS support to socket_writer and socket_listener plugins. +- [#4025](https://github.com/influxdata/telegraf/pull/4025): Add snmp input option to strip non fixed length index suffixes. +- [#4035](https://github.com/influxdata/telegraf/pull/4035): Add server version tag to docker input. +- [#4044](https://github.com/influxdata/telegraf/pull/4044): Add support for LeoFS 1.4 to leofs input. +- [#4068](https://github.com/influxdata/telegraf/pull/4068): Add parameter to force the interval of gather for sysstat. +- [#3877](https://github.com/influxdata/telegraf/pull/3877): Support busybox ping in the ping input. +- [#4077](https://github.com/influxdata/telegraf/pull/4077): Add input plugin for McRouter. +- [#4096](https://github.com/influxdata/telegraf/pull/4096): Add topk processor plugin. +- [#4114](https://github.com/influxdata/telegraf/pull/4114): Add cursor metrics to mongodb input. +- [#3455](https://github.com/influxdata/telegraf/pull/3455): Add tag/integer pair for result to net_response. +- [#4010](https://github.com/influxdata/telegraf/pull/3455): Add application_insights output plugin. +- [#4167](https://github.com/influxdata/telegraf/pull/4167): Added several important elasticsearch cluster health metrics. +- [#4094](https://github.com/influxdata/telegraf/pull/4094): Add batch mode to mqtt output. +- [#4158](https://github.com/influxdata/telegraf/pull/4158): Add aurora input plugin. +- [#3839](https://github.com/influxdata/telegraf/pull/3839): Add regex processor plugin. +- [#4165](https://github.com/influxdata/telegraf/pull/4165): Add support for Graphite 1.1 tags. +- [#4162](https://github.com/influxdata/telegraf/pull/4162): Add timeout option to sensors input. +- [#3489](https://github.com/influxdata/telegraf/pull/3489): Add burrow input plugin. +- [#3969](https://github.com/influxdata/telegraf/pull/3969): Add option to unbound module to use threads as tags. +- [#4183](https://github.com/influxdata/telegraf/pull/4183): Add support for TLS and username/password auth to aerospike input. +- [#4190](https://github.com/influxdata/telegraf/pull/4190): Add special syslog timestamp parser to grok parser that uses current year. +- [#4181](https://github.com/influxdata/telegraf/pull/4181): Add syslog input plugin. +- [#4212](https://github.com/influxdata/telegraf/pull/4212): Print the enabled aggregator and processor plugins on startup. +- [#3994](https://github.com/influxdata/telegraf/pull/3994): Add static routing_key option to amqp output. +- [#3995](https://github.com/influxdata/telegraf/pull/3995): Add passive mode exchange declaration option to amqp consumer input. +- [#4216](https://github.com/influxdata/telegraf/pull/4216): Add counter fields to pf input. + +### Bug Fixes + +- [#4018](https://github.com/influxdata/telegraf/pull/4018): Write to working file outputs if any files are not writeable. +- [#4036](https://github.com/influxdata/telegraf/pull/4036): Add all win_perf_counters fields for a series in a single metric. +- [#4118](https://github.com/influxdata/telegraf/pull/4118): Report results of dns_query instead of 0ms on timeout. +- [#4155](https://github.com/influxdata/telegraf/pull/4155): Add consul service tags to metric. +- [#2879](https://github.com/influxdata/telegraf/issues/2879): Fix wildcards and multi instance processes in win_perf_counters. +- [#2468](https://github.com/influxdata/telegraf/issues/2468): Fix crash on 32-bit Windows in win_perf_counters. +- [#4198](https://github.com/influxdata/telegraf/issues/4198): Fix win_perf_counters not collecting at every interval. +- [#4227](https://github.com/influxdata/telegraf/issues/4227): Use same flags for all BSD family ping variants. +- [#4266](https://github.com/influxdata/telegraf/issues/4266): Remove tags with empty values from Wavefront output. + +## v1.6.4 [2018-06-05] + +### Bug Fixes + +- [#4203](https://github.com/influxdata/telegraf/issues/4203): Fix snmp overriding of auto-configured table fields. +- [#4218](https://github.com/influxdata/telegraf/issues/4218): Fix uint support in cloudwatch output. +- [#4188](https://github.com/influxdata/telegraf/pull/4188): Fix documentation of instance_name option in varnish input. +- [#4195](https://github.com/influxdata/telegraf/pull/4195): Revert to previous aerospike library version due to memory leak. + +## v1.6.3 [2018-05-21] + +### Bug Fixes + +- [#4127](https://github.com/influxdata/telegraf/issues/4127): Fix intermittent panic in aerospike input. +- [#4130](https://github.com/influxdata/telegraf/issues/4130): Fix connection leak in jolokia2_agent. +- [#4136](https://github.com/influxdata/telegraf/pull/4130): Fix jolokia2 timeout parsing. +- [#4142](https://github.com/influxdata/telegraf/pull/4142): Fix error parsing dropwizard metrics. +- [#4149](https://github.com/influxdata/telegraf/issues/4149): Fix librato output support for uint and bool. +- [#4176](https://github.com/influxdata/telegraf/pull/4176): Fix waitgroup deadlock if url is incorrect in apache input. + +## v1.6.2 [2018-05-08] + +### Bug Fixes + +- [#4078](https://github.com/influxdata/telegraf/pull/4078): Use same timestamp for fields in system input. +- [#4091](https://github.com/influxdata/telegraf/pull/4091): Fix handling of uint64 in datadog output. +- [#4099](https://github.com/influxdata/telegraf/pull/4099): Ignore UTF8 BOM in JSON parser. +- [#4104](https://github.com/influxdata/telegraf/issues/4104): Fix case for slave metrics in mysql input. +- [#4110](https://github.com/influxdata/telegraf/issues/4110): Fix uint support in cratedb output. + +## v1.6.1 [2018-04-23] + +### Bug Fixes + +- [#3835](https://github.com/influxdata/telegraf/issues/3835): Report mem input fields as gauges instead counters. +- [#4030](https://github.com/influxdata/telegraf/issues/4030): Fix graphite outputs unsigned integers in wrong format. +- [#4043](https://github.com/influxdata/telegraf/issues/4043): Report available fields if utmp is unreadable. +- [#4039](https://github.com/influxdata/telegraf/issues/4039): Fix potential "no fields" error writing to outputs. +- [#4037](https://github.com/influxdata/telegraf/issues/4037): Fix uptime reporting in system input when ran inside docker. +- [#3750](https://github.com/influxdata/telegraf/issues/3750): Fix mem input "cannot allocate memory" error on FreeBSD based systems. +- [#4056](https://github.com/influxdata/telegraf/pull/4056): Fix duplicate tags when overriding an existing tag. +- [#4062](https://github.com/influxdata/telegraf/pull/4062): Add server argument as first argument in unbound input. +- [#4063](https://github.com/influxdata/telegraf/issues/4063): Fix handling of floats with multiple leading zeroes. +- [#4064](https://github.com/influxdata/telegraf/issues/4064): Return errors in mongodb SSL/TLS configuration. + +## v1.6 [2018-04-16] + +### Release Notes + +- The `mysql` input plugin has been updated fix a number of type conversion + issues. This may cause a `field type error` when inserting into InfluxDB due + the change of types. + + To address this we have introduced a new `metric_version` option to control + enabling the new format. For in depth recommendations on upgrading please + reference the [mysql plugin documentation](./plugins/inputs/mysql/README.md#metric-version). + + It is encouraged to migrate to the new model when possible as the old version + is deprecated and will be removed in a future version. + +- The `postgresql` plugins now defaults to using a persistent connection to the database. + In environments where TCP connections are terminated the `max_lifetime` + setting should be set less than the collection `interval` to prevent errors. + +- The `sqlserver` input plugin has a new query and data model that can be enabled + by setting `query_version = 2`. It is encouraged to migrate to the new + model when possible as the old version is deprecated and will be removed in + a future version. + +- An option has been added to the `openldap` input plugin that reverses metric + name to improve grouping. This change is enabled when `reverse_metric_names = true` + is set. It is encouraged to enable this option when possible as the old + ordering is deprecated. + +- The new `http` input configured with `data_format = "json"` can perform the + same task as the, now deprecated, `httpjson` input. + +### New Inputs + +- [http](./plugins/inputs/http/README.md) - Thanks to @grange74 +- [ipset](./plugins/inputs/ipset/README.md) - Thanks to @sajoupa +- [nats](./plugins/inputs/nats/README.md) - Thanks to @mjs & @levex + +### New Processors + +- [override](./plugins/processors/override/README.md) - Thanks to @KarstenSchnitter + +### New Parsers + +- [dropwizard](./docs/DATA_FORMATS_INPUT.md#dropwizard) - Thanks to @atzoum + +### Features + +- [#3551](https://github.com/influxdata/telegraf/pull/3551): Add health status mapping from string to int in elasticsearch input. +- [#3580](https://github.com/influxdata/telegraf/pull/3580): Add control over which stats to gather in basicstats aggregator. +- [#3596](https://github.com/influxdata/telegraf/pull/3596): Add messages_delivered_get to rabbitmq input. +- [#3632](https://github.com/influxdata/telegraf/pull/3632): Add wired field to mem input. +- [#3619](https://github.com/influxdata/telegraf/pull/3619): Add support for gathering exchange metrics to the rabbitmq input. +- [#3565](https://github.com/influxdata/telegraf/pull/3565): Add support for additional metrics on Linux in zfs input. +- [#3524](https://github.com/influxdata/telegraf/pull/3524): Add available_entropy field to kernel input plugin. +- [#3643](https://github.com/influxdata/telegraf/pull/3643): Add user privilege level setting to IPMI sensors. +- [#2701](https://github.com/influxdata/telegraf/pull/2701): Use persistent connection to postgresql database. +- [#2846](https://github.com/influxdata/telegraf/pull/2846): Add support for dropwizard input format. +- [#3666](https://github.com/influxdata/telegraf/pull/3666): Add container health metrics to docker input. +- [#3687](https://github.com/influxdata/telegraf/pull/3687): Add support for using globs in devices list of diskio input plugin. +- [#2754](https://github.com/influxdata/telegraf/pull/2754): Allow running as console application on Windows. +- [#3703](https://github.com/influxdata/telegraf/pull/3703): Add listener counts and node running status to rabbitmq input. +- [#3674](https://github.com/influxdata/telegraf/pull/3674): Add NATS Monitoring Input Plugin. +- [#3702](https://github.com/influxdata/telegraf/pull/3702): Add ability to select which queues will be gathered in rabbitmq input. +- [#3726](https://github.com/influxdata/telegraf/pull/3726): Add support for setting bsd source address to the ping input. +- [#3346](https://github.com/influxdata/telegraf/pull/3346): Add Ipset input plugin. +- [#3719](https://github.com/influxdata/telegraf/pull/3719): Add TLS and HTTP basic auth to prometheus_client output. +- [#3618](https://github.com/influxdata/telegraf/pull/3618): Add new sqlserver output data model. +- [#3559](https://github.com/influxdata/telegraf/pull/3559): Add native Go method for finding pids to procstat. +- [#3722](https://github.com/influxdata/telegraf/pull/3722): Add additional metrics and reverse metric names option to openldap. +- [#3769](https://github.com/influxdata/telegraf/pull/3769): Add TLS support to the mesos input plugin. +- [#3546](https://github.com/influxdata/telegraf/pull/3546): Add http input plugin. +- [#3781](https://github.com/influxdata/telegraf/pull/3781): Add keep alive support to the TCP mode of statsd. +- [#3783](https://github.com/influxdata/telegraf/pull/3783): Support deadline in ping plugin. +- [#3765](https://github.com/influxdata/telegraf/pull/3765): Add option to disable labels in prometheus output for string fields. +- [#3808](https://github.com/influxdata/telegraf/pull/3808): Add shard server stats to the mongodb input plugin. +- [#3713](https://github.com/influxdata/telegraf/pull/3713): Add server option to unbound plugin. +- [#3804](https://github.com/influxdata/telegraf/pull/3804): Convert boolean metric values to float in datadog output. +- [#3799](https://github.com/influxdata/telegraf/pull/3799): Add Solr 3 compatibility. +- [#3797](https://github.com/influxdata/telegraf/pull/3797): Add sum stat to basicstats aggregator. +- [#3626](https://github.com/influxdata/telegraf/pull/3626): Add ability to override proxy from environment in http response. +- [#3853](https://github.com/influxdata/telegraf/pull/3853): Add host to ping timeout log message. +- [#3773](https://github.com/influxdata/telegraf/pull/3773): Add override processor. +- [#3814](https://github.com/influxdata/telegraf/pull/3814): Add status_code and result tags and result_type field to http_response input. +- [#3880](https://github.com/influxdata/telegraf/pull/3880): Added config flag to skip collection of network protocol metrics. +- [#3927](https://github.com/influxdata/telegraf/pull/3927): Add TLS support to kapacitor input. +- [#3496](https://github.com/influxdata/telegraf/pull/3496): Add HTTP basic auth support to the http_listener input. +- [#3452](https://github.com/influxdata/telegraf/issues/3452): Tags in output InfluxDB Line Protocol are now sorted. +- [#3631](https://github.com/influxdata/telegraf/issues/3631): InfluxDB Line Protocol parser now accepts DOS line endings. +- [#2496](https://github.com/influxdata/telegraf/issues/2496): An option has been added to skip database creation in the InfluxDB output. +- [#3366](https://github.com/influxdata/telegraf/issues/3366): Add support for connecting to InfluxDB over a unix domain socket. +- [#3946](https://github.com/influxdata/telegraf/pull/3946): Add optional unsigned integer support to the influx data format. +- [#3811](https://github.com/influxdata/telegraf/pull/3811): Add TLS support to zookeeper input. +- [#2737](https://github.com/influxdata/telegraf/issues/2737): Add filters for container state to docker input. + +### Bug Fixes + +- [#1896](https://github.com/influxdata/telegraf/issues/1896): Fix various mysql data type conversions. +- [#3810](https://github.com/influxdata/telegraf/issues/3810): Fix metric buffer limit in internal plugin after reload. +- [#3801](https://github.com/influxdata/telegraf/issues/3801): Fix panic in http_response on invalid regex. +- [#3973](https://github.com/influxdata/telegraf/issues/3873): Fix socket_listener setting ReadBufferSize on tcp sockets. +- [#1575](https://github.com/influxdata/telegraf/issues/1575): Add tag for target url to phpfpm input. +- [#3868](https://github.com/influxdata/telegraf/issues/3868): Fix cannot unmarshal object error in DC/OS input. +- [#3648](https://github.com/influxdata/telegraf/issues/3648): Fix InfluxDB output not able to reconnect when server address changes. +- [#3957](https://github.com/influxdata/telegraf/issues/3957): Fix parsing of dos line endings in the smart input. +- [#3754](https://github.com/influxdata/telegraf/issues/3754): Fix precision truncation when no timestamp included. +- [#3655](https://github.com/influxdata/telegraf/issues/3655): Fix SNMPv3 connection with Cisco ASA 5515 in snmp input. +- [#3981](https://github.com/influxdata/telegraf/pull/3981): Export all vars defined in /etc/default/telegraf. +- [#4004](https://github.com/influxdata/telegraf/issues/4004): Allow grok pattern to contain newlines. + +## v1.5.3 [2018-03-14] + +### Bug Fixes + +- [#3729](https://github.com/influxdata/telegraf/issues/3729): Set path to / if HOST_MOUNT_PREFIX matches full path. +- [#3739](https://github.com/influxdata/telegraf/issues/3739): Remove userinfo from url tag in prometheus input. +- [#3778](https://github.com/influxdata/telegraf/issues/3778): Fix ping plugin not reporting zero durations. +- [#3697](https://github.com/influxdata/telegraf/issues/3697): Disable keepalive in mqtt output to prevent deadlock. +- [#3786](https://github.com/influxdata/telegraf/pull/3786): Fix collation difference in sqlserver input. +- [#3871](https://github.com/influxdata/telegraf/pull/3871): Fix uptime metric in passenger input plugin. +- [#3851](https://github.com/influxdata/telegraf/issues/3851): Add output of stderr in case of error to exec log message. + +## v1.5.2 [2018-01-30] + +### Bug Fixes + +- [#3684](https://github.com/influxdata/telegraf/pull/3684): Ignore empty lines in Graphite plaintext. +- [#3604](https://github.com/influxdata/telegraf/issues/3604): Fix index out of bounds error in solr input plugin. +- [#3680](https://github.com/influxdata/telegraf/pull/3680): Reconnect before sending graphite metrics if disconnected. +- [#3693](https://github.com/influxdata/telegraf/pull/3693): Align aggregator period with internal ticker to avoid skipping metrics. +- [#3629](https://github.com/influxdata/telegraf/issues/3629): Fix a potential deadlock when using aggregators. +- [#3697](https://github.com/influxdata/telegraf/issues/3697): Limit wait time for writes in mqtt output. +- [#3698](https://github.com/influxdata/telegraf/issues/3698): Revert change in graphite output where dot in field key was replaced by underscore. +- [#3710](https://github.com/influxdata/telegraf/issues/3710): Add timeout to wavefront output write. +- [#3725](https://github.com/influxdata/telegraf/issues/3725): Exclude master_replid fields from redis input. + +## v1.5.1 [2018-01-10] + +### Bug Fixes + +- [#3624](https://github.com/influxdata/telegraf/pull/3624): Fix name error in jolokia2_agent sample config. +- [#3625](https://github.com/influxdata/telegraf/pull/3625): Fix DC/OS login expiration time. +- [#3593](https://github.com/influxdata/telegraf/pull/3593): Set Content-Type charset in influxdb output and allow it be overridden. +- [#3594](https://github.com/influxdata/telegraf/pull/3594): Document permissions setup for postfix input. +- [#3633](https://github.com/influxdata/telegraf/pull/3633): Fix deliver_get field in rabbitmq input. +- [#3607](https://github.com/influxdata/telegraf/issues/3607): Escape environment variables during config toml parsing. + +## v1.5 [2017-12-14] + +### New Plugins + +- [basicstats](./plugins/aggregators/basicstats/README.md) - Thanks to @toni-moreno +- [bond](./plugins/inputs/bond/README.md) - Thanks to @ildarsv +- [cratedb](./plugins/outputs/cratedb/README.md) - Thanks to @felixge +- [dcos](./plugins/inputs/dcos/README.md) - Thanks to @influxdata +- [jolokia2](./plugins/inputs/jolokia2/README.md) - Thanks to @dylanmei +- [nginx_plus](./plugins/inputs/nginx_plus/README.md) - Thanks to @mplonka & @poblahblahblah +- [opensmtpd](./plugins/inputs/opensmtpd/README.md) - Thanks to @aromeyer +- [particle](./plugins/inputs/webhooks/particle/README.md) - Thanks to @davidgs +- [pf](./plugins/inputs/pf/README.md) - Thanks to @nferch +- [postfix](./plugins/inputs/postfix/README.md) - Thanks to @phemmer +- [smart](./plugins/inputs/smart/README.md) - Thanks to @rickard-von-essen +- [solr](./plugins/inputs/solr/README.md) - Thanks to @ljagiello +- [teamspeak](./plugins/inputs/teamspeak/README.md) - Thanks to @p4ddy1 +- [unbound](./plugins/inputs/unbound/README.md) - Thanks to @aromeyer +- [wavefront](./plugins/outputs/wavefront/README.md) - Thanks to @puckpuck + +### Release Notes + +- In the `kinesis` output, use of the `partition_key` and + `use_random_partitionkey` options has been deprecated in favor of the + `partition` subtable. This allows for more flexible methods to set the + partition key such as by metric name or by tag. + +- With the release of the new improved `jolokia2` input, the legacy `jolokia` + plugin is deprecated and will be removed in a future release. Users of this + plugin are encouraged to update to the new `jolokia2` plugin. + +- In the `postgresql` and `postgresql_extensible` plugins, the type of the oid + data type has changed from string to integer. It is recommended to drop + affected fields until a new shard is started. For details on how to + workaround this issue please see [#3622](https://github.com/influxdata/telegraf/issues/3622). + +### Features + +- [#3170](https://github.com/influxdata/telegraf/pull/3170): Add support for sharding based on metric name. +- [#3196](https://github.com/influxdata/telegraf/pull/3196): Add Kafka output plugin topic_suffix option. +- [#3027](https://github.com/influxdata/telegraf/pull/3027): Include mount mode option in disk metrics. +- [#3191](https://github.com/influxdata/telegraf/pull/3191): TLS and MTLS enhancements to HTTPListener input plugin. +- [#3213](https://github.com/influxdata/telegraf/pull/3213): Add polling method to logparser and tail inputs. +- [#3211](https://github.com/influxdata/telegraf/pull/3211): Add timeout option for kubernetes input. +- [#3234](https://github.com/influxdata/telegraf/pull/3234): Add support for timing sums in statsd input. +- [#2617](https://github.com/influxdata/telegraf/issues/2617): Add resource limit monitoring to procstat. +- [#3236](https://github.com/influxdata/telegraf/pull/3236): Add support for k8s service DNS discovery to prometheus input. +- [#3245](https://github.com/influxdata/telegraf/pull/3245): Add configurable metrics endpoint to prometheus output. +- [#3214](https://github.com/influxdata/telegraf/pull/3214): Add new nginx_plus input plugin. +- [#3215](https://github.com/influxdata/telegraf/pull/3215): Add support for NSQLookupd to nsq_consumer. +- [#2278](https://github.com/influxdata/telegraf/pull/2278): Add redesigned Jolokia input plugin. +- [#3106](https://github.com/influxdata/telegraf/pull/3106): Add configurable separator for metrics and fields in opentsdb output. +- [#1692](https://github.com/influxdata/telegraf/pull/1692): Add support for the rollbar occurrence webhook event. +- [#3160](https://github.com/influxdata/telegraf/pull/3160): Add Wavefront output plugin. +- [#3281](https://github.com/influxdata/telegraf/pull/3281): Add extra wired tiger cache metrics to mongodb input. +- [#3141](https://github.com/influxdata/telegraf/pull/3141): Collect Docker Swarm service metrics in docker input plugin. +- [#2449](https://github.com/influxdata/telegraf/pull/2449): Add smart input plugin for collecting S.M.A.R.T. data. +- [#3269](https://github.com/influxdata/telegraf/pull/3269): Add cluster health level configuration to elasticsearch input. +- [#3304](https://github.com/influxdata/telegraf/pull/3304): Add ability to limit node stats in elasticsearch input. +- [#2167](https://github.com/influxdata/telegraf/pull/2167): Add new basicstats aggregator. +- [#3344](https://github.com/influxdata/telegraf/pull/3344): Add UDP IPv6 support to statsd input. +- [#3350](https://github.com/influxdata/telegraf/pull/3350): Use labels in prometheus output for string fields. +- [#3358](https://github.com/influxdata/telegraf/pull/3358): Add support for decimal timestamps to ts-epoch modifier. +- [#3337](https://github.com/influxdata/telegraf/pull/3337): Add histogram and summary types and use in prometheus plugins. +- [#3365](https://github.com/influxdata/telegraf/pull/3365): Gather concurrently from snmp agents. +- [#3333](https://github.com/influxdata/telegraf/issues/3333): Perform DNS lookup before ping and report result. +- [#3398](https://github.com/influxdata/telegraf/issues/3398): Add instance name option to varnish plugin. +- [#3406](https://github.com/influxdata/telegraf/pull/3406): Add support for SSL settings to ElasticSearch output plugin. +- [#3315](https://github.com/influxdata/telegraf/pull/3315): Add Teamspeak 3 input plugin. +- [#3305](https://github.com/influxdata/telegraf/pull/3305): Add modification_time field to filestat input plugin. +- [#2019](https://github.com/influxdata/telegraf/pull/2019): Add Solr input plugin. +- [#3210](https://github.com/influxdata/telegraf/pull/3210): Add CrateDB output plugin. +- [#3459](https://github.com/influxdata/telegraf/pull/3459): Add systemd unit pid and cgroup matching to procstat. +- [#3477](https://github.com/influxdata/telegraf/pull/3477): Add Particle Webhook Plugin. +- [#3471](https://github.com/influxdata/telegraf/pull/3471): Use MAX() instead of SUM() for latency measurements in sqlserver. +- [#3490](https://github.com/influxdata/telegraf/pull/3490): Add index by week number to Elasticsearch output. +- [#3434](https://github.com/influxdata/telegraf/pull/3434): Add unbound input plugin. +- [#3449](https://github.com/influxdata/telegraf/pull/3449): Add opensmtpd input plugin. +- [#3470](https://github.com/influxdata/telegraf/pull/3470): Add support for tags in the index name in elasticsearch output. +- [#2553](https://github.com/influxdata/telegraf/pull/2553): Add postfix input plugin. +- [#3424](https://github.com/influxdata/telegraf/pull/3424): Add bond input plugin. +- [#3518](https://github.com/influxdata/telegraf/pull/3518): Add slab to mem plugin. +- [#3519](https://github.com/influxdata/telegraf/pull/3519): Add input plugin for DC/OS. +- [#3140](https://github.com/influxdata/telegraf/pull/3140): Add support for glob patterns in net input plugin. +- [#3405](https://github.com/influxdata/telegraf/pull/3405): Add input plugin for OpenBSD/FreeBSD pf. +- [#3528](https://github.com/influxdata/telegraf/pull/3528): Add option to amqp output to publish persistent messages. +- [#3530](https://github.com/influxdata/telegraf/pull/3530): Support I (idle) process state on procfs+Linux. + +### Bug Fixes + +- [#3136](https://github.com/influxdata/telegraf/issues/3136): Fix webhooks input address in use during reload. +- [#3258](https://github.com/influxdata/telegraf/issues/3258): Unlock Statsd when stopping to prevent deadlock. +- [#3319](https://github.com/influxdata/telegraf/issues/3319): Fix cloudwatch output requires unneeded permissions. +- [#3351](https://github.com/influxdata/telegraf/issues/3351): Fix prometheus passthrough for existing value types. +- [#3430](https://github.com/influxdata/telegraf/issues/3430): Always ignore autofs filesystems in disk input. +- [#3326](https://github.com/influxdata/telegraf/issues/3326): Fail metrics parsing on unescaped quotes. +- [#3473](https://github.com/influxdata/telegraf/pull/3473): Whitelist allowed char classes for graphite output. +- [#3488](https://github.com/influxdata/telegraf/pull/3488): Use hexadecimal ids and lowercase names in zipkin input. +- [#3263](https://github.com/influxdata/telegraf/issues/3263): Fix snmp-tools output parsing with Windows EOLs. +- [#3447](https://github.com/influxdata/telegraf/issues/3447): Add shadow-utils dependency to rpm package. +- [#3448](https://github.com/influxdata/telegraf/issues/3448): Use deb-systemd-invoke to restart service. +- [#3553](https://github.com/influxdata/telegraf/issues/3553): Fix kafka_consumer outside range of offsets error. +- [#3568](https://github.com/influxdata/telegraf/issues/3568): Fix separation of multiple prometheus_client outputs. +- [#3577](https://github.com/influxdata/telegraf/issues/3577): Don't add system input uptime_format as a counter. + +## v1.4.5 [2017-12-01] + +### Bug Fixes + +- [#3500](https://github.com/influxdata/telegraf/issues/3500): Fix global variable collection when using interval_slow option in mysql input. +- [#3486](https://github.com/influxdata/telegraf/issues/3486): Fix error getting net connections info in netstat input. +- [#3529](https://github.com/influxdata/telegraf/issues/3529): Fix HOST_MOUNT_PREFIX in docker with disk input. + +## v1.4.4 [2017-11-08] + +### Bug Fixes + +- [#3401](https://github.com/influxdata/telegraf/pull/3401): Use schema specified in mqtt_consumer input. +- [#3419](https://github.com/influxdata/telegraf/issues/3419): Redact datadog API key in log output. +- [#3311](https://github.com/influxdata/telegraf/issues/3311): Fix error getting pids in netstat input. +- [#3339](https://github.com/influxdata/telegraf/issues/3339): Support HOST_VAR envvar to locate /var in system input. +- [#3383](https://github.com/influxdata/telegraf/issues/3383): Use current time if docker container read time is zero value. + +## v1.4.3 [2017-10-25] + +### Bug Fixes + +- [#3327](https://github.com/influxdata/telegraf/issues/3327): Fix container name filters in docker input. +- [#3321](https://github.com/influxdata/telegraf/issues/3321): Fix snmpwalk address format in leofs input. +- [#3329](https://github.com/influxdata/telegraf/issues/3329): Fix case sensitivity issue in sqlserver query. +- [#3342](https://github.com/influxdata/telegraf/pull/3342): Fix CPU input plugin stuck after suspend on Linux. +- [#3013](https://github.com/influxdata/telegraf/issues/3013): Fix mongodb input panic when restarting mongodb. +- [#3224](https://github.com/influxdata/telegraf/pull/3224): Preserve url path prefix in influx output. +- [#3354](https://github.com/influxdata/telegraf/pull/3354): Fix TELEGRAF_OPTS expansion in systemd service unit. +- [#3357](https://github.com/influxdata/telegraf/issues/3357): Remove warning when JSON contains null value. +- [#3375](https://github.com/influxdata/telegraf/issues/3375): Fix ACL token usage in consul input plugin. +- [#3369](https://github.com/influxdata/telegraf/issues/3369): Fix unquoting error with Tomcat 6. +- [#3373](https://github.com/influxdata/telegraf/issues/3373): Fix syscall panic in diskio on some Linux systems. + +## v1.4.2 [2017-10-10] + +### Bug Fixes + +- [#3259](https://github.com/influxdata/telegraf/issues/3259): Fix error if int larger than 32-bit in /proc/vmstat. +- [#3265](https://github.com/influxdata/telegraf/issues/3265): Fix parsing of JSON with a UTF8 BOM in httpjson. +- [#2887](https://github.com/influxdata/telegraf/issues/2887): Allow JSON data format to contain zero metrics. +- [#3284](https://github.com/influxdata/telegraf/issues/3284): Fix format of connection_timeout in mqtt_consumer. +- [#3081](https://github.com/influxdata/telegraf/issues/3081): Fix case sensitivity error in sqlserver input. +- [#3297](https://github.com/influxdata/telegraf/issues/3297): Add support for proxy environment variables to http_response. +- [#1588](https://github.com/influxdata/telegraf/issues/1588): Add support for standard proxy env vars in outputs. +- [#3282](https://github.com/influxdata/telegraf/issues/3282): Fix panic in cpu input if number of cpus changes. +- [#2854](https://github.com/influxdata/telegraf/issues/2854): Use chunked transfer encoding in InfluxDB output. + +## v1.4.1 [2017-09-26] + +### Bug Fixes + +- [#3167](https://github.com/influxdata/telegraf/issues/3167): Fix MQTT input exits if Broker is not available on startup. +- [#3217](https://github.com/influxdata/telegraf/issues/3217): Fix optional field value conversions in fluentd input. +- [#3227](https://github.com/influxdata/telegraf/issues/3227): Whitelist allowed char classes for opentsdb output. +- [#3232](https://github.com/influxdata/telegraf/issues/3232): Fix counter and gauge metric types. +- [#3235](https://github.com/influxdata/telegraf/issues/3235): Fix skipped line with empty target in iptables. +- [#3175](https://github.com/influxdata/telegraf/issues/3175): Fix duplicate keys in perf counters sqlserver query. +- [#3230](https://github.com/influxdata/telegraf/issues/3230): Fix panic in statsd p100 calculation. +- [#3242](https://github.com/influxdata/telegraf/issues/3242): Fix arm64 packages contain 32-bit executable. + +## v1.4 [2017-09-05] + +### Release Notes + +- The `kafka_consumer` input has been updated to support Kafka 0.9 and + above style consumer offset handling. The previous version of this plugin + supporting Kafka 0.8 and below is available as the `kafka_consumer_legacy` + plugin. + +- In the `aerospike` input the `node_name` field has been changed to be a tag + for both the `aerospike_node` and `aerospike_namespace` measurements. + +- The default prometheus_client port has been changed to 9273. + +### New Plugins + +- [fail2ban](./plugins/inputs/fail2ban/README.md) - Thanks to @grugrut +- [fluentd](./plugins/inputs/fluentd/README.md) - Thanks to @DanKans +- [histogram](./plugins/aggregators/histogram/README.md) - Thanks to @vlamug +- [minecraft](./plugins/inputs/minecraft/README.md) - Thanks to @adamperlin & @Ayrdrie +- [openldap](./plugins/inputs/openldap/README.md) - Thanks to @cobaugh +- [salesforce](./plugins/inputs/salesforce/README.md) - Thanks to @rody +- [tomcat](./plugins/inputs/tomcat/README.md) - Thanks to @mlindes +- [win_services](./plugins/inputs/win_services/README.md) - Thanks to @vlastahajek +- [zipkin](./plugins/inputs/zipkin/README.md) - Thanks to @adamperlin & @Ayrdrie + +### Features + +- [#2487](https://github.com/influxdata/telegraf/pull/2487): Add Kafka 0.9+ consumer support +- [#2773](https://github.com/influxdata/telegraf/pull/2773): Add support for self-signed certs to InfluxDB input plugin +- [#2293](https://github.com/influxdata/telegraf/pull/2293): Add TCP listener for statsd input +- [#2581](https://github.com/influxdata/telegraf/pull/2581): Add Docker container environment variables as tags. Only whitelisted +- [#2817](https://github.com/influxdata/telegraf/pull/2817): Add timeout option to IPMI sensor plugin +- [#2883](https://github.com/influxdata/telegraf/pull/2883): Add support for an optional SSL/TLS configuration to nginx input plugin +- [#2882](https://github.com/influxdata/telegraf/pull/2882): Add timezone support for logparser timestamps. +- [#2814](https://github.com/influxdata/telegraf/pull/2814): Add result_type field for http_response input. +- [#2734](https://github.com/influxdata/telegraf/pull/2734): Add include/exclude filters for docker containers. +- [#2602](https://github.com/influxdata/telegraf/pull/2602): Add secure connection support to graphite output. +- [#2908](https://github.com/influxdata/telegraf/pull/2908): Add min/max response time on linux/darwin to ping. +- [#2929](https://github.com/influxdata/telegraf/pull/2929): Add HTTP Proxy support to influxdb output. +- [#2933](https://github.com/influxdata/telegraf/pull/2933): Add standard SSL options to mysql input. +- [#2875](https://github.com/influxdata/telegraf/pull/2875): Add input plugin for fail2ban. +- [#2924](https://github.com/influxdata/telegraf/pull/2924): Support HOST_PROC in processes and linux_sysctl_fs inputs. +- [#2960](https://github.com/influxdata/telegraf/pull/2960): Add Minecraft input plugin. +- [#2963](https://github.com/influxdata/telegraf/pull/2963): Add support for RethinkDB 1.0 handshake protocol. +- [#2943](https://github.com/influxdata/telegraf/pull/2943): Add optional usage_active and time_active CPU metrics. +- [#2973](https://github.com/influxdata/telegraf/pull/2973): Change default prometheus_client port. +- [#2661](https://github.com/influxdata/telegraf/pull/2661): Add fluentd input plugin. +- [#2990](https://github.com/influxdata/telegraf/pull/2990): Add result_type field to net_response input plugin. +- [#2571](https://github.com/influxdata/telegraf/pull/2571): Add read timeout to socket_listener +- [#2612](https://github.com/influxdata/telegraf/pull/2612): Add input plugin for OpenLDAP. +- [#3042](https://github.com/influxdata/telegraf/pull/3042): Add network option to dns_query. +- [#3054](https://github.com/influxdata/telegraf/pull/3054): Add redis_version field to redis input. +- [#3063](https://github.com/influxdata/telegraf/pull/3063): Add tls options to docker input. +- [#2387](https://github.com/influxdata/telegraf/pull/2387): Add histogram aggregator plugin. +- [#3080](https://github.com/influxdata/telegraf/pull/3080): Add zipkin input plugin. +- [#3023](https://github.com/influxdata/telegraf/pull/3023): Add Windows Services input plugin. +- [#3098](https://github.com/influxdata/telegraf/pull/3098): Add path tag to logparser containing path of logfile. +- [#3075](https://github.com/influxdata/telegraf/pull/3075): Add salesforce input plugin. +- [#3097](https://github.com/influxdata/telegraf/pull/3097): Add option to run varnish under sudo. +- [#3119](https://github.com/influxdata/telegraf/pull/3119): Add weighted_io_time to diskio input. +- [#2978](https://github.com/influxdata/telegraf/pull/2978): Add gzip content-encoding support to influxdb output. +- [#3127](https://github.com/influxdata/telegraf/pull/3127): Allow using system plugin in Windows. +- [#3112](https://github.com/influxdata/telegraf/pull/3112): Add tomcat input plugin. +- [#3182](https://github.com/influxdata/telegraf/pull/3182): HTTP headers can be added to InfluxDB output. + +### Bug Fixes + +- [#2607](https://github.com/influxdata/telegraf/issues/2607): Improve logging of errors in Cassandra input. +- [#2819](https://github.com/influxdata/telegraf/pull/2819): [enh] set db_version at 0 if query version fails +- [#2749](https://github.com/influxdata/telegraf/pull/2749): Fixed sqlserver input to work with case sensitive server collation. +- [#2716](https://github.com/influxdata/telegraf/pull/2716): Systemd does not see all shutdowns as failures +- [#2782](https://github.com/influxdata/telegraf/pull/2782): Reuse transports in input plugins +- [#2815](https://github.com/influxdata/telegraf/issues/2815): Inputs processes fails with "no such process". +- [#1137](https://github.com/influxdata/telegraf/issues/1137): Fix multiple plugin loading in win_perf_counters. +- [#2855](https://github.com/influxdata/telegraf/pull/2855): MySQL input: log and continue on field parse error. +- [#2885](https://github.com/influxdata/telegraf/pull/2885): Fix timeout option in Windows ping input sample configuration. +- [#2911](https://github.com/influxdata/telegraf/issues/2911): Fix Kinesis output plugin in govcloud. +- [#2917](https://github.com/influxdata/telegraf/issues/2917): Fix Aerospike input adds all nodes to a single series. +- [#2452](https://github.com/influxdata/telegraf/pull/2452): Improve Prometheus Client output documentation. +- [#2984](https://github.com/influxdata/telegraf/pull/2984): Display error message if prometheus output fails to listen. +- [#2997](https://github.com/influxdata/telegraf/issues/2997): Fix elasticsearch output content type detection warning. +- [#2914](https://github.com/influxdata/telegraf/issues/2914): Prevent possible deadlock when using aggregators. +- [#2860](https://github.com/influxdata/telegraf/issues/2860): Fix combined tagdrop/tagpass filtering. +- [#3036](https://github.com/influxdata/telegraf/pull/3036): Fix filtering when both pass and drop match an item. +- [#2964](https://github.com/influxdata/telegraf/issues/2964): Only report cpu usage for online cpus in docker input. +- [#3050](https://github.com/influxdata/telegraf/pull/3050): Start first aggregator period at startup time. +- [#2906](https://github.com/influxdata/telegraf/issues/2906): Fix panic in logparser if file cannot be opened. +- [#2886](https://github.com/influxdata/telegraf/issues/2886): Default to localhost if zookeeper has no servers set. +- [#2457](https://github.com/influxdata/telegraf/issues/2457): Fix docker memory and cpu reporting in Windows. +- [#3058](https://github.com/influxdata/telegraf/issues/3058): Allow iptable entries with trailing text. +- [#1680](https://github.com/influxdata/telegraf/issues/1680): Sanitize password from couchbase metric. +- [#3104](https://github.com/influxdata/telegraf/issues/3104): Converge to typed value in prometheus output. +- [#2899](https://github.com/influxdata/telegraf/issues/2899): Skip compilation of logparser and tail on solaris. +- [#2951](https://github.com/influxdata/telegraf/issues/2951): Discard logging from tail library. +- [#3126](https://github.com/influxdata/telegraf/pull/3126): Remove log message on ping timeout. +- [#3144](https://github.com/influxdata/telegraf/issues/3144): Don't retry points beyond retention policy. +- [#3015](https://github.com/influxdata/telegraf/issues/3015): Don't start Telegraf on install in Amazon Linux. +- [#3153](https://github.com/influxdata/telegraf/issues/3053): Enable hddtemp input on all platforms. +- [#3142](https://github.com/influxdata/telegraf/issues/3142): Escape backslash within string fields. +- [#3162](https://github.com/influxdata/telegraf/issues/3162): Fix parsing of SHM remotes in ntpq input +- [#3149](https://github.com/influxdata/telegraf/issues/3149): Don't fail parsing zpool stats if pool health is UNAVAIL on FreeBSD. +- [#2672](https://github.com/influxdata/telegraf/issues/2672): Fix NSQ input plugin when used with version 1.0.0-compat. +- [#2523](https://github.com/influxdata/telegraf/issues/2523): Added CloudWatch metric constraint validation. +- [#3179](https://github.com/influxdata/telegraf/issues/3179): Skip non-numerical values in graphite format. +- [#3187](https://github.com/influxdata/telegraf/issues/3187): Fix panic when handling string fields with escapes. + +## v1.3.5 [2017-07-26] + +### Bug Fixes + +- [#3049](https://github.com/influxdata/telegraf/issues/3049): Fix prometheus output cannot be reloaded. +- [#3037](https://github.com/influxdata/telegraf/issues/3037): Fix filestat reporting exists when cannot list directory. +- [#2386](https://github.com/influxdata/telegraf/issues/2386): Fix ntpq parse issue when using dns_lookup. +- [#2554](https://github.com/influxdata/telegraf/issues/2554): Fix panic when agent.interval = "0s". + +## v1.3.4 [2017-07-12] + +### Bug Fixes + +- [#3001](https://github.com/influxdata/telegraf/issues/3001): Fix handling of escape characters within fields. +- [#2988](https://github.com/influxdata/telegraf/issues/2988): Fix chrony plugin does not track system time offset. +- [#3004](https://github.com/influxdata/telegraf/issues/3004): Do not allow metrics with trailing slashes. +- [#3011](https://github.com/influxdata/telegraf/issues/3011): Prevent Write from being called concurrently. + +## v1.3.3 [2017-06-28] + +### Bug Fixes + +- [#2915](https://github.com/influxdata/telegraf/issues/2915): Allow dos line endings in tail and logparser. +- [#2937](https://github.com/influxdata/telegraf/issues/2937): Remove label value sanitization in prometheus output. +- [#2948](https://github.com/influxdata/telegraf/issues/2948): Fix bug parsing default timestamps with modified precision. +- [#2954](https://github.com/influxdata/telegraf/issues/2954): Fix panic in elasticsearch input if cannot determine master. + +## v1.3.2 [2017-06-14] + +### Bug Fixes + +- [#2862](https://github.com/influxdata/telegraf/issues/2862): Fix InfluxDB UDP metric splitting. +- [#2888](https://github.com/influxdata/telegraf/issues/2888): Fix mongodb/leofs urls without scheme. +- [#2822](https://github.com/influxdata/telegraf/issues/2822): Fix inconsistent label dimensions in prometheus output. + +## v1.3.1 [2017-05-31] + +### Bug Fixes + +- [#2749](https://github.com/influxdata/telegraf/pull/2749): Fixed sqlserver input to work with case sensitive server collation. +- [#2782](https://github.com/influxdata/telegraf/pull/2782): Reuse transports in input plugins +- [#2815](https://github.com/influxdata/telegraf/issues/2815): Inputs processes fails with "no such process". +- [#2851](https://github.com/influxdata/telegraf/pull/2851): Fix InfluxDB output database quoting. +- [#2856](https://github.com/influxdata/telegraf/issues/2856): Fix net input on older Linux kernels. +- [#2848](https://github.com/influxdata/telegraf/pull/2848): Fix panic in mongo input. +- [#2869](https://github.com/influxdata/telegraf/pull/2869): Fix length calculation of split metric buffer. + +## v1.3 [2017-05-15] + +### Release Notes + +- Users of the windows `ping` plugin will need to drop or migrate their +measurements in order to continue using the plugin. The reason for this is that +the windows plugin was outputting a different type than the linux plugin. This +made it impossible to use the `ping` plugin for both windows and linux +machines. + +- Ceph: the `ceph_pgmap_state` metric content has been modified to use a unique field `count`, with each state expressed as a `state` tag. + +Telegraf < 1.3: + +```text +# field_name value +active+clean 123 +active+clean+scrubbing 3 +``` + +Telegraf >= 1.3: + +```text +# field_name value tag +count 123 state=active+clean +count 3 state=active+clean+scrubbing +``` + +- The [Riemann output plugin](./plugins/outputs/riemann) has been rewritten +and the previous riemann plugin is _incompatible_ with the new one. The reasons +for this are outlined in issue [#1878](https://github.com/influxdata/telegraf/issues/1878). +The previous riemann output will still be available using +`outputs.riemann_legacy` if needed, but that will eventually be deprecated. +It is highly recommended that all users migrate to the new riemann output plugin. + +- Generic [socket_listener](./plugins/inputs/socket_listener) and +[socket_writer](./plugins/outputs/socket_writer) plugins have been implemented +for receiving and sending UDP, TCP, unix, & unix-datagram data. These plugins +will replace udp_listener and tcp_listener, which are still available but will +be deprecated eventually. + +### Features + +- [#2721](https://github.com/influxdata/telegraf/pull/2721): Added SASL options for kafka output plugin. +- [#2723](https://github.com/influxdata/telegraf/pull/2723): Added SSL configuration for input haproxy. +- [#2494](https://github.com/influxdata/telegraf/pull/2494): Add interrupts input plugin. +- [#2094](https://github.com/influxdata/telegraf/pull/2094): Add generic socket listener & writer. +- [#2204](https://github.com/influxdata/telegraf/pull/2204): Extend http_response to support searching for a substring in response. Return 1 if found, else 0. +- [#2137](https://github.com/influxdata/telegraf/pull/2137): Added userstats to mysql input plugin. +- [#2179](https://github.com/influxdata/telegraf/pull/2179): Added more InnoDB metric to MySQL plugin. +- [#2229](https://github.com/influxdata/telegraf/pull/2229): `ceph_pgmap_state` metric now uses a single field `count`, with PG state published as `state` tag. +- [#2251](https://github.com/influxdata/telegraf/pull/2251): InfluxDB output: use own client for improved through-put and less allocations. +- [#2330](https://github.com/influxdata/telegraf/pull/2330): Keep -config-directory when running as Windows service. +- [#1900](https://github.com/influxdata/telegraf/pull/1900): Riemann plugin rewrite. +- [#1453](https://github.com/influxdata/telegraf/pull/1453): diskio: add support for name templates and udev tags. +- [#2277](https://github.com/influxdata/telegraf/pull/2277): add integer metrics for Consul check health state. +- [#2201](https://github.com/influxdata/telegraf/pull/2201): Add lock option to the IPtables input plugin. +- [#2244](https://github.com/influxdata/telegraf/pull/2244): Support ipmi_sensor plugin querying local ipmi sensors. +- [#2339](https://github.com/influxdata/telegraf/pull/2339): Increment gather_errors for all errors emitted by inputs. +- [#2071](https://github.com/influxdata/telegraf/issues/2071): Use official docker SDK. +- [#1678](https://github.com/influxdata/telegraf/pull/1678): Add AMQP consumer input plugin +- [#2512](https://github.com/influxdata/telegraf/pull/2512): Added pprof tool. +- [#2501](https://github.com/influxdata/telegraf/pull/2501): Support DEAD(X) state in system input plugin. +- [#2522](https://github.com/influxdata/telegraf/pull/2522): Add support for mongodb client certificates. +- [#1948](https://github.com/influxdata/telegraf/pull/1948): Support adding SNMP table indexes as tags. +- [#2332](https://github.com/influxdata/telegraf/pull/2332): Add Elasticsearch 5.x output +- [#2587](https://github.com/influxdata/telegraf/pull/2587): Add json timestamp units configurability +- [#2597](https://github.com/influxdata/telegraf/issues/2597): Add support for Linux sysctl-fs metrics. +- [#2425](https://github.com/influxdata/telegraf/pull/2425): Support to include/exclude docker container labels as tags +- [#1667](https://github.com/influxdata/telegraf/pull/1667): dmcache input plugin +- [#2637](https://github.com/influxdata/telegraf/issues/2637): Add support for precision in http_listener +- [#2636](https://github.com/influxdata/telegraf/pull/2636): Add `message_len_max` option to `kafka_consumer` input +- [#1100](https://github.com/influxdata/telegraf/issues/1100): Add collectd parser +- [#1820](https://github.com/influxdata/telegraf/issues/1820): easier plugin testing without outputs +- [#2493](https://github.com/influxdata/telegraf/pull/2493): Check signature in the GitHub webhook plugin +- [#2038](https://github.com/influxdata/telegraf/issues/2038): Add papertrail support to webhooks +- [#2253](https://github.com/influxdata/telegraf/pull/2253): Change jolokia plugin to use bulk requests. +- [#2575](https://github.com/influxdata/telegraf/issues/2575) Add diskio input for Darwin +- [#2705](https://github.com/influxdata/telegraf/pull/2705): Kinesis output: add use_random_partitionkey option +- [#2635](https://github.com/influxdata/telegraf/issues/2635): add tcp keep-alive to socket_listener & socket_writer +- [#2031](https://github.com/influxdata/telegraf/pull/2031): Add Kapacitor input plugin +- [#2732](https://github.com/influxdata/telegraf/pull/2732): Use go 1.8.1 +- [#2712](https://github.com/influxdata/telegraf/issues/2712): Documentation for rabbitmq input plugin +- [#2141](https://github.com/influxdata/telegraf/pull/2141): Logparser handles newly-created files. + +### Bug Fixes + +- [#2633](https://github.com/influxdata/telegraf/pull/2633): ipmi_sensor: allow @ symbol in password +- [#2077](https://github.com/influxdata/telegraf/issues/2077): SQL Server Input - Arithmetic overflow error converting numeric to data type int. +- [#2262](https://github.com/influxdata/telegraf/issues/2262): Flush jitter can inhibit metric collection. +- [#2318](https://github.com/influxdata/telegraf/issues/2318): haproxy input - Add missing fields. +- [#2287](https://github.com/influxdata/telegraf/issues/2287): Kubernetes input: Handle null startTime for stopped pods. +- [#2356](https://github.com/influxdata/telegraf/issues/2356): cpu input panic when /proc/stat is empty. +- [#2341](https://github.com/influxdata/telegraf/issues/2341): telegraf swallowing panics in --test mode. +- [#2358](https://github.com/influxdata/telegraf/pull/2358): Create pidfile with 644 permissions & defer file deletion. +- [#2360](https://github.com/influxdata/telegraf/pull/2360): Fixed install/remove of telegraf on non-systemd Debian/Ubuntu systems +- [#2282](https://github.com/influxdata/telegraf/issues/2282): Reloading telegraf freezes prometheus output. +- [#2390](https://github.com/influxdata/telegraf/issues/2390): Empty tag value causes error on InfluxDB output. +- [#2380](https://github.com/influxdata/telegraf/issues/2380): buffer_size field value is negative number from "internal" plugin. +- [#2414](https://github.com/influxdata/telegraf/issues/2414): Missing error handling in the MySQL plugin leads to segmentation violation. +- [#2462](https://github.com/influxdata/telegraf/pull/2462): Fix type conflict in windows ping plugin. +- [#2178](https://github.com/influxdata/telegraf/issues/2178): logparser: regexp with lookahead. +- [#2466](https://github.com/influxdata/telegraf/issues/2466): Telegraf can crash in LoadDirectory on 0600 files. +- [#2215](https://github.com/influxdata/telegraf/issues/2215): Iptables input: document better that rules without a comment are ignored. +- [#2483](https://github.com/influxdata/telegraf/pull/2483): Fix win_perf_counters capping values at 100. +- [#2498](https://github.com/influxdata/telegraf/pull/2498): Exporting Ipmi.Path to be set by config. +- [#2500](https://github.com/influxdata/telegraf/pull/2500): Remove warning if parse empty content +- [#2520](https://github.com/influxdata/telegraf/pull/2520): Update default value for Cloudwatch rate limit +- [#2513](https://github.com/influxdata/telegraf/issues/2513): create /etc/telegraf/telegraf.d directory in tarball. +- [#2541](https://github.com/influxdata/telegraf/issues/2541): Return error on unsupported serializer data format. +- [#1827](https://github.com/influxdata/telegraf/issues/1827): Fix Windows Performance Counters multi instance identifier +- [#2576](https://github.com/influxdata/telegraf/pull/2576): Add write timeout to Riemann output +- [#2596](https://github.com/influxdata/telegraf/pull/2596): fix timestamp parsing on prometheus plugin +- [#2610](https://github.com/influxdata/telegraf/pull/2610): Fix deadlock when output cannot write +- [#2410](https://github.com/influxdata/telegraf/issues/2410): Fix connection leak in postgresql. +- [#2628](https://github.com/influxdata/telegraf/issues/2628): Set default measurement name for snmp input. +- [#2649](https://github.com/influxdata/telegraf/pull/2649): Improve performance of diskio with many disks +- [#2671](https://github.com/influxdata/telegraf/issues/2671): The internal input plugin uses the wrong units for `heap_objects` +- [#2684](https://github.com/influxdata/telegraf/pull/2684): Fix ipmi_sensor config is shared between all plugin instances +- [#2450](https://github.com/influxdata/telegraf/issues/2450): Network statistics not collected when system has alias interfaces +- [#1911](https://github.com/influxdata/telegraf/issues/1911): Sysstat plugin needs LANG=C or similar locale +- [#2528](https://github.com/influxdata/telegraf/issues/2528): File output closes standard streams on reload. +- [#2603](https://github.com/influxdata/telegraf/issues/2603): AMQP output disconnect blocks all outputs +- [#2706](https://github.com/influxdata/telegraf/issues/2706): Improve documentation for redis input plugin + +## v1.2.1 [2017-02-01] + +### Bug Fixes + +- [#2317](https://github.com/influxdata/telegraf/issues/2317): Fix segfault on nil metrics with influxdb output. +- [#2324](https://github.com/influxdata/telegraf/issues/2324): Fix negative number handling. + +### Features + +- [#2348](https://github.com/influxdata/telegraf/pull/2348): Go version 1.7.4 -> 1.7.5 + +## v1.2 [2017-01-00] + +### Release Notes + +- The StatsD plugin will now default all "delete_" config options to "true". This +will change te default behavior for users who were not specifying these parameters +in their config file. + +- The StatsD plugin will also no longer save it's state on a service reload. +Essentially we have reverted PR [#887](https://github.com/influxdata/telegraf/pull/887). +The reason for this is that saving the state in a global variable is not +thread-safe (see [#1975](https://github.com/influxdata/telegraf/issues/1975) & [#2102](https://github.com/influxdata/telegraf/issues/2102)), +and this creates issues if users want to define multiple instances +of the statsd plugin. Saving state on reload may be considered in the future, +but this would need to be implemented at a higher level and applied to all +plugins, not just statsd. + +### Features + +- [#2123](https://github.com/influxdata/telegraf/pull/2123): Fix improper calculation of CPU percentages +- [#1564](https://github.com/influxdata/telegraf/issues/1564): Use RFC3339 timestamps in log output. +- [#1997](https://github.com/influxdata/telegraf/issues/1997): Non-default HTTP timeouts for RabbitMQ plugin. +- [#2074](https://github.com/influxdata/telegraf/pull/2074): "discard" output plugin added, primarily for testing purposes. +- [#1965](https://github.com/influxdata/telegraf/pull/1965): The JSON parser can now parse an array of objects using the same configuration. +- [#1807](https://github.com/influxdata/telegraf/pull/1807): Option to use device name rather than path for reporting disk stats. +- [#1348](https://github.com/influxdata/telegraf/issues/1348): Telegraf "internal" plugin for collecting stats on itself. +- [#2127](https://github.com/influxdata/telegraf/pull/2127): Update Go version to 1.7.4. +- [#2126](https://github.com/influxdata/telegraf/pull/2126): Support a metric.Split function. +- [#2026](https://github.com/influxdata/telegraf/pull/2065): elasticsearch "shield" (basic auth) support doc. +- [#1885](https://github.com/influxdata/telegraf/pull/1885): Fix over-querying of cloudwatch metrics +- [#1913](https://github.com/influxdata/telegraf/pull/1913): OpenTSDB basic auth support. +- [#1908](https://github.com/influxdata/telegraf/pull/1908): RabbitMQ Connection metrics. +- [#1937](https://github.com/influxdata/telegraf/pull/1937): HAProxy session limit metric. +- [#2068](https://github.com/influxdata/telegraf/issues/2068): Accept strings for StatsD sets. +- [#1893](https://github.com/influxdata/telegraf/issues/1893): Change StatsD default "reset" behavior. +- [#2079](https://github.com/influxdata/telegraf/pull/2079): Enable setting ClientID in MQTT output. +- [#2001](https://github.com/influxdata/telegraf/pull/2001): MongoDB input plugin: Improve state data. +- [#2078](https://github.com/influxdata/telegraf/pull/2078): Ping input: add standard deviation field. +- [#2121](https://github.com/influxdata/telegraf/pull/2121): Add GC pause metric to InfluxDB input plugin. +- [#2006](https://github.com/influxdata/telegraf/pull/2006): Added response_timeout property to prometheus input plugin. +- [#1763](https://github.com/influxdata/telegraf/issues/1763): Pulling github.com/lxn/win's pdh wrapper into telegraf. +- [#1898](https://github.com/influxdata/telegraf/issues/1898): Support negative statsd counters. +- [#1921](https://github.com/influxdata/telegraf/issues/1921): Elasticsearch cluster stats support. +- [#1942](https://github.com/influxdata/telegraf/pull/1942): Change Amazon Kinesis output plugin to use the built-in serializer plugins. +- [#1980](https://github.com/influxdata/telegraf/issues/1980): Hide username/password from elasticsearch error log messages. +- [#2097](https://github.com/influxdata/telegraf/issues/2097): Configurable HTTP timeouts in Jolokia plugin +- [#2255](https://github.com/influxdata/telegraf/pull/2255): Allow changing jolokia attribute delimiter + +### Bug Fixes + +- [#2049](https://github.com/influxdata/telegraf/pull/2049): Fix the Value data format not trimming null characters from input. +- [#1949](https://github.com/influxdata/telegraf/issues/1949): Fix windows `net` plugin. +- [#1775](https://github.com/influxdata/telegraf/issues/1775): Cache & expire metrics for delivery to prometheus +- [#1775](https://github.com/influxdata/telegraf/issues/1775): Cache & expire metrics for delivery to prometheus. +- [#2146](https://github.com/influxdata/telegraf/issues/2146): Fix potential panic in aggregator plugin metric maker. +- [#1843](https://github.com/influxdata/telegraf/pull/1843) & [#1668](https://github.com/influxdata/telegraf/issues/1668): Add optional ability to define PID as a tag. +- [#1730](https://github.com/influxdata/telegraf/issues/1730) & [#2261](https://github.com/influxdata/telegraf/pull/2261): Fix win_perf_counters not gathering non-English counters. +- [#2061](https://github.com/influxdata/telegraf/issues/2061): Fix panic when file stat info cannot be collected due to permissions or other issue(s). +- [#2045](https://github.com/influxdata/telegraf/issues/2045): Graylog output should set short_message field. +- [#1904](https://github.com/influxdata/telegraf/issues/1904): Hddtemp always put the value in the field temperature. +- [#1693](https://github.com/influxdata/telegraf/issues/1693): Properly collect nested jolokia struct data. +- [#1917](https://github.com/influxdata/telegraf/pull/1917): fix puppetagent inputs plugin to support string for config variable. +- [#1987](https://github.com/influxdata/telegraf/issues/1987): fix docker input plugin tags when registry has port. +- [#2089](https://github.com/influxdata/telegraf/issues/2089): Fix tail input when reading from a pipe. +- [#1449](https://github.com/influxdata/telegraf/issues/1449): MongoDB plugin always shows 0 replication lag. +- [#1825](https://github.com/influxdata/telegraf/issues/1825): Consul plugin: add check_id as a tag in metrics to avoid overwrites. +- [#1973](https://github.com/influxdata/telegraf/issues/1973): Partial fix: logparser CLF pattern with IPv6 addresses. +- [#1975](https://github.com/influxdata/telegraf/issues/1975) & [#2102](https://github.com/influxdata/telegraf/issues/2102): Fix thread-safety when using multiple instances of the statsd input plugin. +- [#2027](https://github.com/influxdata/telegraf/issues/2027): docker input: interface conversion panic fix. +- [#1814](https://github.com/influxdata/telegraf/issues/1814): snmp: ensure proper context is present on error messages. +- [#2299](https://github.com/influxdata/telegraf/issues/2299): opentsdb: add tcp:// prefix if no scheme provided. +- [#2297](https://github.com/influxdata/telegraf/issues/2297): influx parser: parse line-protocol without newlines. +- [#2245](https://github.com/influxdata/telegraf/issues/2245): influxdb output: fix field type conflict blocking output buffer. + +## v1.1.2 [2016-12-12] + +### Bug Fixes + +- [#2007](https://github.com/influxdata/telegraf/issues/2007): Make snmptranslate not required when using numeric OID. +- [#2104](https://github.com/influxdata/telegraf/issues/2104): Add a global snmp translation cache. + +## v1.1.1 [2016-11-14] + +### Bug Fixes + +- [#2023](https://github.com/influxdata/telegraf/issues/2023): Fix issue parsing toml durations with single quotes. + +## v1.1.0 [2016-11-07] + +### Release Notes + +- Telegraf now supports two new types of plugins: processors & aggregators. + +- On systemd Telegraf will no longer redirect it's stdout to /var/log/telegraf/telegraf.log. +On most systems, the logs will be directed to the systemd journal and can be +accessed by `journalctl -u telegraf.service`. Consult the systemd journal +documentation for configuring journald. There is also a [`logfile` config option](https://github.com/influxdata/telegraf/blob/master/etc/telegraf.conf#L70) +available in 1.1, which will allow users to easily configure telegraf to +continue sending logs to /var/log/telegraf/telegraf.log. + +### Features + +- [#1726](https://github.com/influxdata/telegraf/issues/1726): Processor & Aggregator plugin support. +- [#1861](https://github.com/influxdata/telegraf/pull/1861): adding the tags in the graylog output plugin +- [#1732](https://github.com/influxdata/telegraf/pull/1732): Telegraf systemd service, log to journal. +- [#1782](https://github.com/influxdata/telegraf/pull/1782): Allow numeric and non-string values for tag_keys. +- [#1694](https://github.com/influxdata/telegraf/pull/1694): Adding Gauge and Counter metric types. +- [#1606](https://github.com/influxdata/telegraf/pull/1606): Remove carraige returns from exec plugin output on Windows +- [#1674](https://github.com/influxdata/telegraf/issues/1674): elasticsearch input: configurable timeout. +- [#1607](https://github.com/influxdata/telegraf/pull/1607): Massage metric names in Instrumental output plugin +- [#1572](https://github.com/influxdata/telegraf/pull/1572): mesos improvements. +- [#1513](https://github.com/influxdata/telegraf/issues/1513): Add Ceph Cluster Performance Statistics +- [#1650](https://github.com/influxdata/telegraf/issues/1650): Ability to configure response_timeout in httpjson input. +- [#1685](https://github.com/influxdata/telegraf/issues/1685): Add additional redis metrics. +- [#1539](https://github.com/influxdata/telegraf/pull/1539): Added capability to send metrics through Http API for OpenTSDB. +- [#1471](https://github.com/influxdata/telegraf/pull/1471): iptables input plugin. +- [#1542](https://github.com/influxdata/telegraf/pull/1542): Add filestack webhook plugin. +- [#1599](https://github.com/influxdata/telegraf/pull/1599): Add server hostname for each docker measurements. +- [#1697](https://github.com/influxdata/telegraf/pull/1697): Add NATS output plugin. +- [#1407](https://github.com/influxdata/telegraf/pull/1407) & [#1915](https://github.com/influxdata/telegraf/pull/1915): HTTP service listener input plugin. +- [#1699](https://github.com/influxdata/telegraf/pull/1699): Add database blacklist option for Postgresql +- [#1791](https://github.com/influxdata/telegraf/pull/1791): Add Docker container state metrics to Docker input plugin output +- [#1755](https://github.com/influxdata/telegraf/issues/1755): Add support to SNMP for IP & MAC address conversion. +- [#1729](https://github.com/influxdata/telegraf/issues/1729): Add support to SNMP for OID index suffixes. +- [#1813](https://github.com/influxdata/telegraf/pull/1813): Change default arguments for SNMP plugin. +- [#1686](https://github.com/influxdata/telegraf/pull/1686): Mesos input plugin: very high-cardinality mesos-task metrics removed. +- [#1838](https://github.com/influxdata/telegraf/pull/1838): Logging overhaul to centralize the logger & log levels, & provide a logfile config option. +- [#1700](https://github.com/influxdata/telegraf/pull/1700): HAProxy plugin socket glob matching. +- [#1847](https://github.com/influxdata/telegraf/pull/1847): Add Kubernetes plugin for retrieving pod metrics. + +### Bug Fixes + +- [#1955](https://github.com/influxdata/telegraf/issues/1955): Fix NATS plug-ins reconnection logic. +- [#1936](https://github.com/influxdata/telegraf/issues/1936): Set required default values in udp_listener & tcp_listener. +- [#1926](https://github.com/influxdata/telegraf/issues/1926): Fix toml unmarshal panic in Duration objects. +- [#1746](https://github.com/influxdata/telegraf/issues/1746): Fix handling of non-string values for JSON keys listed in tag_keys. +- [#1628](https://github.com/influxdata/telegraf/issues/1628): Fix mongodb input panic on version 2.2. +- [#1733](https://github.com/influxdata/telegraf/issues/1733): Fix statsd scientific notation parsing +- [#1716](https://github.com/influxdata/telegraf/issues/1716): Sensors plugin strconv.ParseFloat: parsing "": invalid syntax +- [#1530](https://github.com/influxdata/telegraf/issues/1530): Fix prometheus_client reload panic +- [#1764](https://github.com/influxdata/telegraf/issues/1764): Fix kafka consumer panic when nil error is returned down errs channel. +- [#1768](https://github.com/influxdata/telegraf/pull/1768): Speed up statsd parsing. +- [#1751](https://github.com/influxdata/telegraf/issues/1751): Fix powerdns integer parse error handling. +- [#1752](https://github.com/influxdata/telegraf/issues/1752): Fix varnish plugin defaults not being used. +- [#1517](https://github.com/influxdata/telegraf/issues/1517): Fix windows glob paths. +- [#1137](https://github.com/influxdata/telegraf/issues/1137): Fix issue loading config directory on windows. +- [#1772](https://github.com/influxdata/telegraf/pull/1772): Windows remote management interactive service fix. +- [#1702](https://github.com/influxdata/telegraf/issues/1702): sqlserver, fix issue when case sensitive collation is activated. +- [#1823](https://github.com/influxdata/telegraf/issues/1823): Fix huge allocations in http_listener when dealing with huge payloads. +- [#1833](https://github.com/influxdata/telegraf/issues/1833): Fix translating SNMP fields not in MIB. +- [#1835](https://github.com/influxdata/telegraf/issues/1835): Fix SNMP emitting empty fields. +- [#1854](https://github.com/influxdata/telegraf/pull/1853): SQL Server waitstats truncation bug. +- [#1810](https://github.com/influxdata/telegraf/issues/1810): Fix logparser common log format: numbers in ident. +- [#1793](https://github.com/influxdata/telegraf/pull/1793): Fix JSON Serialization in OpenTSDB output. +- [#1731](https://github.com/influxdata/telegraf/issues/1731): Fix Graphite template ordering, use most specific. +- [#1836](https://github.com/influxdata/telegraf/pull/1836): Fix snmp table field initialization for non-automatic table. +- [#1724](https://github.com/influxdata/telegraf/issues/1724): cgroups path being parsed as metric. +- [#1886](https://github.com/influxdata/telegraf/issues/1886): Fix phpfpm fcgi client panic when URL does not exist. +- [#1344](https://github.com/influxdata/telegraf/issues/1344): Fix config file parse error logging. +- [#1771](https://github.com/influxdata/telegraf/issues/1771): Delete nil fields in the metric maker. +- [#870](https://github.com/influxdata/telegraf/issues/870): Fix MySQL special characters in DSN parsing. +- [#1742](https://github.com/influxdata/telegraf/issues/1742): Ping input odd timeout behavior. +- [#1950](https://github.com/influxdata/telegraf/pull/1950): Switch to github.com/kballard/go-shellquote. + +## v1.0.1 [2016-09-26] + +### Bug Fixes + +- [#1775](https://github.com/influxdata/telegraf/issues/1775): Prometheus output: Fix bug with multi-batch writes. +- [#1738](https://github.com/influxdata/telegraf/issues/1738): Fix unmarshal of influxdb metrics with null tags. +- [#1773](https://github.com/influxdata/telegraf/issues/1773): Add configurable timeout to influxdb input plugin. +- [#1785](https://github.com/influxdata/telegraf/pull/1785): Fix statsd no default value panic. + +## v1.0 [2016-09-08] + +### Release Notes + +**Breaking Change** The SNMP plugin is being deprecated in it's current form. +There is a [new SNMP plugin](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/snmp) +which fixes many of the issues and confusions +of its predecessor. For users wanting to continue to use the deprecated SNMP +plugin, you will need to change your config file from `[[inputs.snmp]]` to +`[[inputs.snmp_legacy]]`. The configuration of the new SNMP plugin is _not_ +backwards-compatible. + +**Breaking Change**: Aerospike main server node measurements have been renamed +aerospike_node. Aerospike namespace measurements have been renamed to +aerospike_namespace. They will also now be tagged with the node_name +that they correspond to. This has been done to differentiate measurements +that pertain to node vs. namespace statistics. + +**Breaking Change**: users of github_webhooks must change to the new +`[[inputs.webhooks]]` plugin. + +This means that the default github_webhooks config: + +```toml +# A Github Webhook Event collector +[[inputs.github_webhooks]] + ## Address and port to host Webhook listener on + service_address = ":1618" +``` + +should now look like: + +```toml +# A Webhooks Event collector +[[inputs.webhooks]] + ## Address and port to host Webhook listener on + service_address = ":1618" + + [inputs.webhooks.github] + path = "/" +``` + +- Telegraf now supports being installed as an official windows service, +which can be installed via +`> C:\Program Files\Telegraf\telegraf.exe --service install` + +- `flush_jitter` behavior has been changed. The random jitter will now be +evaluated at every flush interval, rather than once at startup. This makes it +consistent with the behavior of `collection_jitter`. + +- postgresql plugins now handle oid and name typed columns seamlessly, previously they were ignored/skipped. + +### Features + +- [#1617](https://github.com/influxdata/telegraf/pull/1617): postgresql_extensible now handles name and oid types correctly. +- [#1413](https://github.com/influxdata/telegraf/issues/1413): Separate container_version from container_image tag. +- [#1525](https://github.com/influxdata/telegraf/pull/1525): Support setting per-device and total metrics for Docker network and blockio. +- [#1466](https://github.com/influxdata/telegraf/pull/1466): MongoDB input plugin: adding per DB stats from db.stats() +- [#1503](https://github.com/influxdata/telegraf/pull/1503): Add tls support for certs to RabbitMQ input plugin +- [#1289](https://github.com/influxdata/telegraf/pull/1289): webhooks input plugin. Thanks @francois2metz and @cduez! +- [#1247](https://github.com/influxdata/telegraf/pull/1247): rollbar webhook plugin. +- [#1408](https://github.com/influxdata/telegraf/pull/1408): mandrill webhook plugin. +- [#1402](https://github.com/influxdata/telegraf/pull/1402): docker-machine/boot2docker no longer required for unit tests. +- [#1350](https://github.com/influxdata/telegraf/pull/1350): cgroup input plugin. +- [#1369](https://github.com/influxdata/telegraf/pull/1369): Add input plugin for consuming metrics from NSQD. +- [#1369](https://github.com/influxdata/telegraf/pull/1480): add ability to read redis from a socket. +- [#1387](https://github.com/influxdata/telegraf/pull/1387): **Breaking Change** - Redis `role` tag renamed to `replication_role` to avoid global_tags override +- [#1437](https://github.com/influxdata/telegraf/pull/1437): Fetching Galera status metrics in MySQL +- [#1500](https://github.com/influxdata/telegraf/pull/1500): Aerospike plugin refactored to use official client lib. +- [#1434](https://github.com/influxdata/telegraf/pull/1434): Add measurement name arg to logparser plugin. +- [#1479](https://github.com/influxdata/telegraf/pull/1479): logparser: change resp_code from a field to a tag. +- [#1411](https://github.com/influxdata/telegraf/pull/1411): Implement support for fetching hddtemp data +- [#1340](https://github.com/influxdata/telegraf/issues/1340): statsd: do not log every dropped metric. +- [#1368](https://github.com/influxdata/telegraf/pull/1368): Add precision rounding to all metrics on collection. +- [#1390](https://github.com/influxdata/telegraf/pull/1390): Add support for Tengine +- [#1320](https://github.com/influxdata/telegraf/pull/1320): Logparser input plugin for parsing grok-style log patterns. +- [#1397](https://github.com/influxdata/telegraf/issues/1397): ElasticSearch: now supports connecting to ElasticSearch via SSL +- [#1262](https://github.com/influxdata/telegraf/pull/1261): Add graylog input plugin. +- [#1294](https://github.com/influxdata/telegraf/pull/1294): consul input plugin. Thanks @harnash +- [#1164](https://github.com/influxdata/telegraf/pull/1164): conntrack input plugin. Thanks @robinpercy! +- [#1165](https://github.com/influxdata/telegraf/pull/1165): vmstat input plugin. Thanks @jshim-xm! +- [#1208](https://github.com/influxdata/telegraf/pull/1208): Standardized AWS credentials evaluation & wildcard CloudWatch dimensions. Thanks @johnrengelman! +- [#1264](https://github.com/influxdata/telegraf/pull/1264): Add SSL config options to http_response plugin. +- [#1272](https://github.com/influxdata/telegraf/pull/1272): graphite parser: add ability to specify multiple tag keys, for consistency with influxdb parser. +- [#1265](https://github.com/influxdata/telegraf/pull/1265): Make dns lookups for chrony configurable. Thanks @zbindenren! +- [#1275](https://github.com/influxdata/telegraf/pull/1275): Allow wildcard filtering of varnish stats. +- [#1142](https://github.com/influxdata/telegraf/pull/1142): Support for glob patterns in exec plugin commands configuration. +- [#1278](https://github.com/influxdata/telegraf/pull/1278): RabbitMQ input: made url parameter optional by using DefaultURL `http://localhost:15672` if not specified +- [#1197](https://github.com/influxdata/telegraf/pull/1197): Limit AWS GetMetricStatistics requests to 10 per second. +- [#1278](https://github.com/influxdata/telegraf/pull/1278) & [#1288](https://github.com/influxdata/telegraf/pull/1288) & [#1295](https://github.com/influxdata/telegraf/pull/1295): RabbitMQ/Apache/InfluxDB inputs: made url(s) parameter optional by using reasonable input defaults if not specified +- [#1296](https://github.com/influxdata/telegraf/issues/1296): Refactor of flush_jitter argument. +- [#1213](https://github.com/influxdata/telegraf/issues/1213): Add inactive & active memory to mem plugin. +- [#1543](https://github.com/influxdata/telegraf/pull/1543): Official Windows service. +- [#1414](https://github.com/influxdata/telegraf/pull/1414): Forking sensors command to remove C package dependency. +- [#1389](https://github.com/influxdata/telegraf/pull/1389): Add a new SNMP plugin. + +### Bug Fixes + +- [#1619](https://github.com/influxdata/telegraf/issues/1619): Fix `make windows` build target +- [#1519](https://github.com/influxdata/telegraf/pull/1519): Fix error race conditions and partial failures. +- [#1477](https://github.com/influxdata/telegraf/issues/1477): nstat: fix inaccurate config panic. +- [#1481](https://github.com/influxdata/telegraf/issues/1481): jolokia: fix handling multiple multi-dimensional attributes. +- [#1430](https://github.com/influxdata/telegraf/issues/1430): Fix prometheus character sanitizing. Sanitize more win_perf_counters characters. +- [#1534](https://github.com/influxdata/telegraf/pull/1534): Add diskio io_time to FreeBSD & report timing metrics as ms (as linux does). +- [#1379](https://github.com/influxdata/telegraf/issues/1379): Fix covering Amazon Linux for post remove flow. +- [#1584](https://github.com/influxdata/telegraf/issues/1584): procstat missing fields: read/write bytes & count +- [#1472](https://github.com/influxdata/telegraf/pull/1472): diskio input plugin: set 'skip_serial_number = true' by default to avoid high cardinality. +- [#1426](https://github.com/influxdata/telegraf/pull/1426): nil metrics panic fix. +- [#1384](https://github.com/influxdata/telegraf/pull/1384): Fix datarace in apache input plugin. +- [#1399](https://github.com/influxdata/telegraf/issues/1399): Add `read_repairs` statistics to riak plugin. +- [#1405](https://github.com/influxdata/telegraf/issues/1405): Fix memory/connection leak in prometheus input plugin. +- [#1378](https://github.com/influxdata/telegraf/issues/1378): Trim BOM from config file for Windows support. +- [#1339](https://github.com/influxdata/telegraf/issues/1339): Prometheus client output panic on service reload. +- [#1461](https://github.com/influxdata/telegraf/pull/1461): Prometheus parser, protobuf format header fix. +- [#1334](https://github.com/influxdata/telegraf/issues/1334): Prometheus output, metric refresh and caching fixes. +- [#1432](https://github.com/influxdata/telegraf/issues/1432): Panic fix for multiple graphite outputs under very high load. +- [#1412](https://github.com/influxdata/telegraf/pull/1412): Instrumental output has better reconnect behavior +- [#1460](https://github.com/influxdata/telegraf/issues/1460): Remove PID from procstat plugin to fix cardinality issues. +- [#1427](https://github.com/influxdata/telegraf/issues/1427): Cassandra input: version 2.x "column family" fix. +- [#1463](https://github.com/influxdata/telegraf/issues/1463): Shared WaitGroup in Exec plugin +- [#1436](https://github.com/influxdata/telegraf/issues/1436): logparser: honor modifiers in "pattern" config. +- [#1418](https://github.com/influxdata/telegraf/issues/1418): logparser: error and exit on file permissions/missing errors. +- [#1499](https://github.com/influxdata/telegraf/pull/1499): Make the user able to specify full path for HAproxy stats +- [#1521](https://github.com/influxdata/telegraf/pull/1521): Fix Redis url, an extra "tcp://" was added. +- [#1330](https://github.com/influxdata/telegraf/issues/1330): Fix exec plugin panic when using single binary. +- [#1336](https://github.com/influxdata/telegraf/issues/1336): Fixed incorrect prometheus metrics source selection. +- [#1112](https://github.com/influxdata/telegraf/issues/1112): Set default Zookeeper chroot to empty string. +- [#1335](https://github.com/influxdata/telegraf/issues/1335): Fix overall ping timeout to be calculated based on per-ping timeout. +- [#1374](https://github.com/influxdata/telegraf/pull/1374): Change "default" retention policy to "". +- [#1377](https://github.com/influxdata/telegraf/issues/1377): Graphite output mangling '%' character. +- [#1396](https://github.com/influxdata/telegraf/pull/1396): Prometheus input plugin now supports x509 certs authentication +- [#1252](https://github.com/influxdata/telegraf/pull/1252) & [#1279](https://github.com/influxdata/telegraf/pull/1279): Fix systemd service. Thanks @zbindenren & @PierreF! +- [#1221](https://github.com/influxdata/telegraf/pull/1221): Fix influxdb n_shards counter. +- [#1258](https://github.com/influxdata/telegraf/pull/1258): Fix potential kernel plugin integer parse error. +- [#1268](https://github.com/influxdata/telegraf/pull/1268): Fix potential influxdb input type assertion panic. +- [#1283](https://github.com/influxdata/telegraf/pull/1283): Still send processes metrics if a process exited during metric collection. +- [#1297](https://github.com/influxdata/telegraf/issues/1297): disk plugin panic when usage grab fails. +- [#1316](https://github.com/influxdata/telegraf/pull/1316): Removed leaked "database" tag on redis metrics. Thanks @PierreF! +- [#1323](https://github.com/influxdata/telegraf/issues/1323): Processes plugin: fix potential error with /proc/net/stat directory. +- [#1322](https://github.com/influxdata/telegraf/issues/1322): Fix rare RHEL 5.2 panic in gopsutil diskio gathering function. +- [#1586](https://github.com/influxdata/telegraf/pull/1586): Remove IF NOT EXISTS from influxdb output database creation. +- [#1600](https://github.com/influxdata/telegraf/issues/1600): Fix quoting with text values in postgresql_extensible plugin. +- [#1425](https://github.com/influxdata/telegraf/issues/1425): Fix win_perf_counter "index out of range" panic. +- [#1634](https://github.com/influxdata/telegraf/issues/1634): Fix ntpq panic when field is missing. +- [#1637](https://github.com/influxdata/telegraf/issues/1637): Sanitize graphite output field names. +- [#1695](https://github.com/influxdata/telegraf/pull/1695): Fix MySQL plugin not sending 0 value fields. + +## v0.13.1 [2016-05-24] + +### Release Notes + +- net_response and http_response plugins timeouts will now accept duration +strings, ie, "2s" or "500ms". +- Input plugin Gathers will no longer be logged by default, but a Gather for +_each_ plugin will be logged in Debug mode. +- Debug mode will no longer print every point added to the accumulator. This +functionality can be duplicated using the `file` output plugin and printing +to "stdout". + +### Features + +- [#1173](https://github.com/influxdata/telegraf/pull/1173): varnish input plugin. Thanks @sfox-xmatters! +- [#1138](https://github.com/influxdata/telegraf/pull/1138): nstat input plugin. Thanks @Maksadbek! +- [#1139](https://github.com/influxdata/telegraf/pull/1139): instrumental output plugin. Thanks @jasonroelofs! +- [#1172](https://github.com/influxdata/telegraf/pull/1172): Ceph storage stats. Thanks @robinpercy! +- [#1233](https://github.com/influxdata/telegraf/pull/1233): Updated golint gopsutil dependency. +- [#1238](https://github.com/influxdata/telegraf/pull/1238): chrony input plugin. Thanks @zbindenren! +- [#479](https://github.com/influxdata/telegraf/issues/479): per-plugin execution time added to debug output. +- [#1249](https://github.com/influxdata/telegraf/issues/1249): influxdb output: added write_consistency argument. + +### Bug Fixes + +- [#1195](https://github.com/influxdata/telegraf/pull/1195): Docker panic on timeout. Thanks @zstyblik! +- [#1211](https://github.com/influxdata/telegraf/pull/1211): mongodb input. Fix possible panic. Thanks @kols! +- [#1215](https://github.com/influxdata/telegraf/pull/1215): Fix for possible gopsutil-dependent plugin hangs. +- [#1228](https://github.com/influxdata/telegraf/pull/1228): Fix service plugin host tag overwrite. +- [#1198](https://github.com/influxdata/telegraf/pull/1198): http_response: override request Host header properly +- [#1230](https://github.com/influxdata/telegraf/issues/1230): Fix Telegraf process hangup due to a single plugin hanging. +- [#1214](https://github.com/influxdata/telegraf/issues/1214): Use TCP timeout argument in net_response plugin. +- [#1243](https://github.com/influxdata/telegraf/pull/1243): Logfile not created on systemd. + +## v0.13 [2016-05-11] + +### Release Notes + +- **Breaking change** in jolokia plugin. See the +[jolokia README](https://github.com/influxdata/telegraf/blob/master/plugins/inputs/jolokia/README.md) +for updated configuration. The plugin will now support proxy mode and will make +POST requests. + +- New [agent] configuration option: `metric_batch_size`. This option tells +telegraf the maximum batch size to allow to accumulate before sending a flush +to the configured outputs. `metric_buffer_limit` now refers to the absolute +maximum number of metrics that will accumulate before metrics are dropped. + +- There is no longer an option to +`flush_buffer_when_full`, this is now the default and only behavior of telegraf. + +- **Breaking Change**: docker plugin tags. The cont_id tag no longer exists, it +will now be a field, and be called container_id. Additionally, cont_image and +cont_name are being renamed to container_image and container_name. + +- **Breaking Change**: docker plugin measurements. The `docker_cpu`, `docker_mem`, +`docker_blkio` and `docker_net` measurements are being renamed to +`docker_container_cpu`, `docker_container_mem`, `docker_container_blkio` and +`docker_container_net`. Why? Because these metrics are +specifically tracking per-container stats. The problem with per-container stats, +in some use-cases, is that if containers are short-lived AND names are not +kept consistent, then the series cardinality will balloon very quickly. +So adding "container" to each metric will: +(1) make it more clear that these metrics are per-container, and +(2) allow users to easily drop per-container metrics if cardinality is an +issue (`namedrop = ["docker_container_*"]`) + +- `tagexclude` and `taginclude` are now available, which can be used to remove +tags from measurements on inputs and outputs. See +[the configuration doc](https://github.com/influxdata/telegraf/blob/master/docs/CONFIGURATION.md) +for more details. + +- **Measurement filtering:** All measurement filters now match based on glob +only. Previously there was an undocumented behavior where filters would match +based on _prefix_ in addition to globs. This means that a filter like +`fielddrop = ["time_"]` will need to be changed to `fielddrop = ["time_*"]` + +- **datadog**: measurement and field names will no longer have `_` replaced by `.` + +- The following plugins have changed their tags to _not_ overwrite the host tag: + - cassandra: `host -> cassandra_host` + - disque: `host -> disque_host` + - rethinkdb: `host -> rethinkdb_host` + +- **Breaking Change**: The `win_perf_counters` input has been changed to +sanitize field names, replacing `/Sec` and `/sec` with `_persec`, as well as +spaces with underscores. This is needed because Graphite doesn't like slashes +and spaces, and was failing to accept metrics that had them. +The `/[sS]ec` -> `_persec` is just to make things clearer and uniform. + +- **Breaking Change**: snmp plugin. The `host` tag of the snmp plugin has been +changed to the `snmp_host` tag. + +- The `disk` input plugin can now be configured with the `HOST_MOUNT_PREFIX` environment variable. +This value is prepended to any mountpaths discovered before retrieving stats. +It is not included on the report path. This is necessary for reporting host disk stats when running from within a container. + +### Features + +- [#1031](https://github.com/influxdata/telegraf/pull/1031): Jolokia plugin proxy mode. Thanks @saiello! +- [#1017](https://github.com/influxdata/telegraf/pull/1017): taginclude and tagexclude arguments. +- [#1015](https://github.com/influxdata/telegraf/pull/1015): Docker plugin schema refactor. +- [#889](https://github.com/influxdata/telegraf/pull/889): Improved MySQL plugin. Thanks @maksadbek! +- [#1060](https://github.com/influxdata/telegraf/pull/1060): TTL metrics added to MongoDB input plugin +- [#1056](https://github.com/influxdata/telegraf/pull/1056): Don't allow inputs to overwrite host tags. +- [#1035](https://github.com/influxdata/telegraf/issues/1035): Add `user`, `exe`, `pidfile` tags to procstat plugin. +- [#1041](https://github.com/influxdata/telegraf/issues/1041): Add `n_cpus` field to the system plugin. +- [#1072](https://github.com/influxdata/telegraf/pull/1072): New Input Plugin: filestat. +- [#1066](https://github.com/influxdata/telegraf/pull/1066): Replication lag metrics for MongoDB input plugin +- [#1086](https://github.com/influxdata/telegraf/pull/1086): Ability to specify AWS keys in config file. Thanks @johnrengelman! +- [#1096](https://github.com/influxdata/telegraf/pull/1096): Performance refactor of running output buffers. +- [#967](https://github.com/influxdata/telegraf/issues/967): Buffer logging improvements. +- [#1107](https://github.com/influxdata/telegraf/issues/1107): Support lustre2 job stats. Thanks @hanleyja! +- [#1122](https://github.com/influxdata/telegraf/pull/1122): Support setting config path through env variable and default paths. +- [#1128](https://github.com/influxdata/telegraf/pull/1128): MongoDB jumbo chunks metric for MongoDB input plugin +- [#1146](https://github.com/influxdata/telegraf/pull/1146): HAProxy socket support. Thanks weshmashian! + +### Bug Fixes + +- [#1050](https://github.com/influxdata/telegraf/issues/1050): jolokia plugin - do not overwrite host tag. Thanks @saiello! +- [#921](https://github.com/influxdata/telegraf/pull/921): mqtt_consumer stops gathering metrics. Thanks @chaton78! +- [#1013](https://github.com/influxdata/telegraf/pull/1013): Close dead riemann output connections. Thanks @echupriyanov! +- [#1012](https://github.com/influxdata/telegraf/pull/1012): Set default tags in test accumulator. +- [#1024](https://github.com/influxdata/telegraf/issues/1024): Don't replace `.` with `_` in datadog output. +- [#1058](https://github.com/influxdata/telegraf/issues/1058): Fix possible leaky TCP connections in influxdb output. +- [#1044](https://github.com/influxdata/telegraf/pull/1044): Fix SNMP OID possible collisions. Thanks @relip +- [#1022](https://github.com/influxdata/telegraf/issues/1022): Dont error deb/rpm install on systemd errors. +- [#1078](https://github.com/influxdata/telegraf/issues/1078): Use default AWS credential chain. +- [#1070](https://github.com/influxdata/telegraf/issues/1070): SQL Server input. Fix datatype conversion. +- [#1089](https://github.com/influxdata/telegraf/issues/1089): Fix leaky TCP connections in phpfpm plugin. +- [#914](https://github.com/influxdata/telegraf/issues/914): Telegraf can drop metrics on full buffers. +- [#1098](https://github.com/influxdata/telegraf/issues/1098): Sanitize invalid OpenTSDB characters. +- [#1110](https://github.com/influxdata/telegraf/pull/1110): Sanitize * to - in graphite serializer. Thanks @goodeggs! +- [#1118](https://github.com/influxdata/telegraf/pull/1118): Sanitize Counter names for `win_perf_counters` input. +- [#1125](https://github.com/influxdata/telegraf/pull/1125): Wrap all exec command runners with a timeout, so hung os processes don't halt Telegraf. +- [#1113](https://github.com/influxdata/telegraf/pull/1113): Set MaxRetry and RequiredAcks defaults in Kafka output. +- [#1090](https://github.com/influxdata/telegraf/issues/1090): [agent] and [global_tags] config sometimes not getting applied. +- [#1133](https://github.com/influxdata/telegraf/issues/1133): Use a timeout for docker list & stat cmds. +- [#1052](https://github.com/influxdata/telegraf/issues/1052): Docker panic fix when decode fails. +- [#1136](https://github.com/influxdata/telegraf/pull/1136): "DELAYED" Inserts were deprecated in MySQL 5.6.6. Thanks @PierreF + +## v0.12.1 [2016-04-14] + +### Release Notes + +- Breaking change in the dovecot input plugin. See Features section below. +- Graphite output templates are now supported. See the +[Output Formats README](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md#graphite) +- Possible breaking change for the librato and graphite outputs. Telegraf will +no longer insert field names when the field is simply named `value`. This is +because the `value` field is redundant in the graphite/librato context. + +### Features + +- [#1009](https://github.com/influxdata/telegraf/pull/1009): Cassandra input plugin. Thanks @subhachandrachandra! +- [#976](https://github.com/influxdata/telegraf/pull/976): Reduce allocations in the UDP and statsd inputs. +- [#979](https://github.com/influxdata/telegraf/pull/979): Reduce allocations in the TCP listener. +- [#992](https://github.com/influxdata/telegraf/pull/992): Refactor allocations in TCP/UDP listeners. +- [#935](https://github.com/influxdata/telegraf/pull/935): AWS Cloudwatch input plugin. Thanks @joshhardy & @ljosa! +- [#943](https://github.com/influxdata/telegraf/pull/943): http_response input plugin. Thanks @Lswith! +- [#939](https://github.com/influxdata/telegraf/pull/939): sysstat input plugin. Thanks @zbindenren! +- [#998](https://github.com/influxdata/telegraf/pull/998): **breaking change** enabled global, user and ip queries in dovecot plugin. Thanks @mikif70! +- [#1001](https://github.com/influxdata/telegraf/pull/1001): Graphite serializer templates. +- [#1008](https://github.com/influxdata/telegraf/pull/1008): Adding memstats metrics to the influxdb plugin. + +### Bug Fixes + +- [#968](https://github.com/influxdata/telegraf/issues/968): Processes plugin gets unknown state when spaces are in (command name) +- [#969](https://github.com/influxdata/telegraf/pull/969): ipmi_sensors: allow : in password. Thanks @awaw! +- [#972](https://github.com/influxdata/telegraf/pull/972): dovecot: remove extra newline in dovecot command. Thanks @mrannanj! +- [#645](https://github.com/influxdata/telegraf/issues/645): docker plugin i/o error on closed pipe. Thanks @tripledes! + +## v0.12.0 [2016-04-05] + +### Features + +- [#951](https://github.com/influxdata/telegraf/pull/951): Parse environment variables in the config file. +- [#948](https://github.com/influxdata/telegraf/pull/948): Cleanup config file and make default package version include all plugins (but commented). +- [#927](https://github.com/influxdata/telegraf/pull/927): Adds parsing of tags to the statsd input when using DataDog's dogstatsd extension +- [#863](https://github.com/influxdata/telegraf/pull/863): AMQP output: allow external auth. Thanks @ekini! +- [#707](https://github.com/influxdata/telegraf/pull/707): Improved prometheus plugin. Thanks @titilambert! +- [#878](https://github.com/influxdata/telegraf/pull/878): Added json serializer. Thanks @ch3lo! +- [#880](https://github.com/influxdata/telegraf/pull/880): Add the ability to specify the bearer token to the prometheus plugin. Thanks @jchauncey! +- [#882](https://github.com/influxdata/telegraf/pull/882): Fixed SQL Server Plugin issues +- [#849](https://github.com/influxdata/telegraf/issues/849): Adding ability to parse single values as an input data type. +- [#844](https://github.com/influxdata/telegraf/pull/844): postgres_extensible plugin added. Thanks @menardorama! +- [#866](https://github.com/influxdata/telegraf/pull/866): couchbase input plugin. Thanks @ljosa! +- [#789](https://github.com/influxdata/telegraf/pull/789): Support multiple field specification and `field*` in graphite templates. Thanks @chrusty! +- [#762](https://github.com/influxdata/telegraf/pull/762): Nagios parser for the exec plugin. Thanks @titilambert! +- [#848](https://github.com/influxdata/telegraf/issues/848): Provide option to omit host tag from telegraf agent. +- [#928](https://github.com/influxdata/telegraf/pull/928): Deprecating the statsd "convert_names" options, expose separator config. +- [#919](https://github.com/influxdata/telegraf/pull/919): ipmi_sensor input plugin. Thanks @ebookbug! +- [#945](https://github.com/influxdata/telegraf/pull/945): KAFKA output: codec, acks, and retry configuration. Thanks @framiere! + +### Bug Fixes + +- [#890](https://github.com/influxdata/telegraf/issues/890): Create TLS config even if only ssl_ca is provided. +- [#884](https://github.com/influxdata/telegraf/issues/884): Do not call write method if there are 0 metrics to write. +- [#898](https://github.com/influxdata/telegraf/issues/898): Put database name in quotes, fixes special characters in the database name. +- [#656](https://github.com/influxdata/telegraf/issues/656): No longer run `lsof` on linux to get netstat data, fixes permissions issue. +- [#907](https://github.com/influxdata/telegraf/issues/907): Fix prometheus invalid label/measurement name key. +- [#841](https://github.com/influxdata/telegraf/issues/841): Fix memcached unix socket panic. +- [#873](https://github.com/influxdata/telegraf/issues/873): Fix SNMP plugin sometimes not returning metrics. Thanks @titilambert! +- [#934](https://github.com/influxdata/telegraf/pull/934): phpfpm: Fix fcgi uri path. Thanks @rudenkovk! +- [#805](https://github.com/influxdata/telegraf/issues/805): Kafka consumer stops gathering after i/o timeout. +- [#959](https://github.com/influxdata/telegraf/pull/959): reduce mongodb & prometheus collection timeouts. Thanks @PierreF! + +## v0.11.1 [2016-03-17] + +### Release Notes + +- Primarily this release was cut to fix [#859](https://github.com/influxdata/telegraf/issues/859) + +### Features + +- [#747](https://github.com/influxdata/telegraf/pull/747): Start telegraf on install & remove on uninstall. Thanks @PierreF! +- [#794](https://github.com/influxdata/telegraf/pull/794): Add service reload ability. Thanks @entertainyou! + +### Bug Fixes + +- [#852](https://github.com/influxdata/telegraf/issues/852): Windows zip package fix +- [#859](https://github.com/influxdata/telegraf/issues/859): httpjson plugin panic + +## v0.11.0 [2016-03-15] + +### Features + +- [#692](https://github.com/influxdata/telegraf/pull/770): Support InfluxDB retention policies +- [#771](https://github.com/influxdata/telegraf/pull/771): Default timeouts for input plugns. Thanks @PierreF! +- [#758](https://github.com/influxdata/telegraf/pull/758): UDP Listener input plugin, thanks @whatyouhide! +- [#769](https://github.com/influxdata/telegraf/issues/769): httpjson plugin: allow specifying SSL configuration. +- [#735](https://github.com/influxdata/telegraf/pull/735): SNMP Table feature. Thanks @titilambert! +- [#754](https://github.com/influxdata/telegraf/pull/754): docker plugin: adding `docker info` metrics to output. Thanks @titilambert! +- [#788](https://github.com/influxdata/telegraf/pull/788): -input-list and -output-list command-line options. Thanks @ebookbug! +- [#778](https://github.com/influxdata/telegraf/pull/778): Adding a TCP input listener. +- [#797](https://github.com/influxdata/telegraf/issues/797): Provide option for persistent MQTT consumer client sessions. +- [#799](https://github.com/influxdata/telegraf/pull/799): Add number of threads for procstat input plugin. Thanks @titilambert! +- [#776](https://github.com/influxdata/telegraf/pull/776): Add Zookeeper chroot option to kafka_consumer. Thanks @prune998! +- [#811](https://github.com/influxdata/telegraf/pull/811): Add processes plugin for classifying total procs on system. Thanks @titilambert! +- [#235](https://github.com/influxdata/telegraf/issues/235): Add number of users to the `system` input plugin. +- [#826](https://github.com/influxdata/telegraf/pull/826): "kernel" linux plugin for /proc/stat metrics (context switches, interrupts, etc.) +- [#847](https://github.com/influxdata/telegraf/pull/847): `ntpq`: Input plugin for running ntp query executable and gathering metrics. + +### Bug Fixes + +- [#748](https://github.com/influxdata/telegraf/issues/748): Fix sensor plugin split on ":" +- [#722](https://github.com/influxdata/telegraf/pull/722): Librato output plugin fixes. Thanks @chrusty! +- [#745](https://github.com/influxdata/telegraf/issues/745): Fix Telegraf toml parse panic on large config files. Thanks @titilambert! +- [#781](https://github.com/influxdata/telegraf/pull/781): Fix mqtt_consumer username not being set. Thanks @chaton78! +- [#786](https://github.com/influxdata/telegraf/pull/786): Fix mqtt output username not being set. Thanks @msangoi! +- [#773](https://github.com/influxdata/telegraf/issues/773): Fix duplicate measurements in snmp plugin. Thanks @titilambert! +- [#708](https://github.com/influxdata/telegraf/issues/708): packaging: build ARM package +- [#713](https://github.com/influxdata/telegraf/issues/713): packaging: insecure permissions error on log directory +- [#816](https://github.com/influxdata/telegraf/issues/816): Fix phpfpm panic if fcgi endpoint unreachable. +- [#828](https://github.com/influxdata/telegraf/issues/828): fix net_response plugin overwriting host tag. +- [#821](https://github.com/influxdata/telegraf/issues/821): Remove postgres password from server tag. Thanks @menardorama! + +## v0.10.4.1 + +### Release Notes + +- Bug in the build script broke deb and rpm packages. + +### Bug Fixes + +- [#750](https://github.com/influxdata/telegraf/issues/750): deb package broken +- [#752](https://github.com/influxdata/telegraf/issues/752): rpm package broken + +## v0.10.4 [2016-02-24] + +### Release Notes + +- The pass/drop parameters have been renamed to fielddrop/fieldpass parameters, +to more accurately indicate their purpose. +- There are also now namedrop/namepass parameters for passing/dropping based +on the metric _name_. +- Experimental windows builds now available. + +### Features + +- [#727](https://github.com/influxdata/telegraf/pull/727): riak input, thanks @jcoene! +- [#694](https://github.com/influxdata/telegraf/pull/694): DNS Query input, thanks @mjasion! +- [#724](https://github.com/influxdata/telegraf/pull/724): username matching for procstat input, thanks @zorel! +- [#736](https://github.com/influxdata/telegraf/pull/736): Ignore dummy filesystems from disk plugin. Thanks @PierreF! +- [#737](https://github.com/influxdata/telegraf/pull/737): Support multiple fields for statsd input. Thanks @mattheath! + +### Bug Fixes + +- [#701](https://github.com/influxdata/telegraf/pull/701): output write count shouldnt print in quiet mode. +- [#746](https://github.com/influxdata/telegraf/pull/746): httpjson plugin: Fix HTTP GET parameters. + +## v0.10.3 [2016-02-18] + +### Release Notes + +- Users of the `exec` and `kafka_consumer` (and the new `nats_consumer` +and `mqtt_consumer` plugins) can now specify the incoming data +format that they would like to parse. Currently supports: "json", "influx", and +"graphite" +- Users of message broker and file output plugins can now choose what data format +they would like to output. Currently supports: "influx" and "graphite" +- More info on parsing _incoming_ data formats can be found +[here](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md) +- More info on serializing _outgoing_ data formats can be found +[here](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md) +- Telegraf now has an option `flush_buffer_when_full` that will flush the +metric buffer whenever it fills up for each output, rather than dropping +points and only flushing on a set time interval. This will default to `true` +and is in the `[agent]` config section. + +### Features + +- [#652](https://github.com/influxdata/telegraf/pull/652): CouchDB Input Plugin. Thanks @codehate! +- [#655](https://github.com/influxdata/telegraf/pull/655): Support parsing arbitrary data formats. Currently limited to kafka_consumer and exec inputs. +- [#671](https://github.com/influxdata/telegraf/pull/671): Dovecot input plugin. Thanks @mikif70! +- [#680](https://github.com/influxdata/telegraf/pull/680): NATS consumer input plugin. Thanks @netixen! +- [#676](https://github.com/influxdata/telegraf/pull/676): MQTT consumer input plugin. +- [#683](https://github.com/influxdata/telegraf/pull/683): PostGRES input plugin: add pg_stat_bgwriter. Thanks @menardorama! +- [#679](https://github.com/influxdata/telegraf/pull/679): File/stdout output plugin. +- [#679](https://github.com/influxdata/telegraf/pull/679): Support for arbitrary output data formats. +- [#695](https://github.com/influxdata/telegraf/pull/695): raindrops input plugin. Thanks @burdandrei! +- [#650](https://github.com/influxdata/telegraf/pull/650): net_response input plugin. Thanks @titilambert! +- [#699](https://github.com/influxdata/telegraf/pull/699): Flush based on buffer size rather than time. +- [#682](https://github.com/influxdata/telegraf/pull/682): Mesos input plugin. Thanks @tripledes! + +### Bug Fixes + +- [#443](https://github.com/influxdata/telegraf/issues/443): Fix Ping command timeout parameter on Linux. +- [#662](https://github.com/influxdata/telegraf/pull/667): Change `[tags]` to `[global_tags]` to fix multiple-plugin tags bug. +- [#642](https://github.com/influxdata/telegraf/issues/642): Riemann output plugin issues. +- [#394](https://github.com/influxdata/telegraf/issues/394): Support HTTP POST. Thanks @gabelev! +- [#715](https://github.com/influxdata/telegraf/pull/715): Fix influxdb precision config panic. Thanks @netixen! + +## v0.10.2 [2016-02-04] + +### Release Notes + +- Statsd timing measurements are now aggregated into a single measurement with +fields. +- Graphite output now inserts tags into the bucket in alphabetical order. +- Normalized TLS/SSL support for output plugins: MQTT, AMQP, Kafka +- `verify_ssl` config option was removed from Kafka because it was actually +doing the opposite of what it claimed to do (yikes). It's been replaced by +`insecure_skip_verify` + +### Features + +- [#575](https://github.com/influxdata/telegraf/pull/575): Support for collecting Windows Performance Counters. Thanks @TheFlyingCorpse! +- [#564](https://github.com/influxdata/telegraf/issues/564): features for plugin writing simplification. Internal metric data type. +- [#603](https://github.com/influxdata/telegraf/pull/603): Aggregate statsd timing measurements into fields. Thanks @marcinbunsch! +- [#601](https://github.com/influxdata/telegraf/issues/601): Warn when overwriting cached metrics. +- [#614](https://github.com/influxdata/telegraf/pull/614): PowerDNS input plugin. Thanks @Kasen! +- [#617](https://github.com/influxdata/telegraf/pull/617): exec plugin: parse influx line protocol in addition to JSON. +- [#628](https://github.com/influxdata/telegraf/pull/628): Windows perf counters: pre-vista support + +### Bug Fixes + +- [#595](https://github.com/influxdata/telegraf/issues/595): graphite output should include tags to separate duplicate measurements. +- [#599](https://github.com/influxdata/telegraf/issues/599): datadog plugin tags not working. +- [#600](https://github.com/influxdata/telegraf/issues/600): datadog measurement/field name parsing is wrong. +- [#602](https://github.com/influxdata/telegraf/issues/602): Fix statsd field name templating. +- [#612](https://github.com/influxdata/telegraf/pull/612): Docker input panic fix if stats received are nil. +- [#634](https://github.com/influxdata/telegraf/pull/634): Properly set host headers in httpjson. Thanks @reginaldosousa! + +## v0.10.1 [2016-01-27] + +### Release Notes + +- Telegraf now keeps a fixed-length buffer of metrics per-output. This buffer +defaults to 10,000 metrics, and is adjustable. The buffer is cleared when a +successful write to that output occurs. +- The docker plugin has been significantly overhauled to add more metrics +and allow for docker-machine (incl OSX) support. +[See the readme](https://github.com/influxdata/telegraf/blob/master/plugins/inputs/docker/README.md) +for the latest measurements, fields, and tags. There is also now support for +specifying a docker endpoint to get metrics from. + +### Features + +- [#509](https://github.com/influxdata/telegraf/pull/509): Flatten JSON arrays with indices. Thanks @psilva261! +- [#512](https://github.com/influxdata/telegraf/pull/512): Python 3 build script, add lsof dep to package. Thanks @Ormod! +- [#475](https://github.com/influxdata/telegraf/pull/475): Add response time to httpjson plugin. Thanks @titilambert! +- [#519](https://github.com/influxdata/telegraf/pull/519): Added a sensors input based on lm-sensors. Thanks @md14454! +- [#467](https://github.com/influxdata/telegraf/issues/467): Add option to disable statsd measurement name conversion. +- [#534](https://github.com/influxdata/telegraf/pull/534): NSQ input plugin. Thanks @allingeek! +- [#494](https://github.com/influxdata/telegraf/pull/494): Graphite output plugin. Thanks @titilambert! +- AMQP SSL support. Thanks @ekini! +- [#539](https://github.com/influxdata/telegraf/pull/539): Reload config on SIGHUP. Thanks @titilambert! +- [#522](https://github.com/influxdata/telegraf/pull/522): Phusion passenger input plugin. Thanks @kureikain! +- [#541](https://github.com/influxdata/telegraf/pull/541): Kafka output TLS cert support. Thanks @Ormod! +- [#551](https://github.com/influxdata/telegraf/pull/551): Statsd UDP read packet size now defaults to 1500 bytes, and is configurable. +- [#552](https://github.com/influxdata/telegraf/pull/552): Support for collection interval jittering. +- [#484](https://github.com/influxdata/telegraf/issues/484): Include usage percent with procstat metrics. +- [#553](https://github.com/influxdata/telegraf/pull/553): Amazon CloudWatch output. thanks @skwong2! +- [#503](https://github.com/influxdata/telegraf/pull/503): Support docker endpoint configuration. +- [#563](https://github.com/influxdata/telegraf/pull/563): Docker plugin overhaul. +- [#285](https://github.com/influxdata/telegraf/issues/285): Fixed-size buffer of points. +- [#546](https://github.com/influxdata/telegraf/pull/546): SNMP Input plugin. Thanks @titilambert! +- [#589](https://github.com/influxdata/telegraf/pull/589): Microsoft SQL Server input plugin. Thanks @zensqlmonitor! +- [#573](https://github.com/influxdata/telegraf/pull/573): Github webhooks consumer input. Thanks @jackzampolin! +- [#471](https://github.com/influxdata/telegraf/pull/471): httpjson request headers. Thanks @asosso! + +### Bug Fixes + +- [#506](https://github.com/influxdata/telegraf/pull/506): Ping input doesn't return response time metric when timeout. Thanks @titilambert! +- [#508](https://github.com/influxdata/telegraf/pull/508): Fix prometheus cardinality issue with the `net` plugin +- [#499](https://github.com/influxdata/telegraf/issues/499) & [#502](https://github.com/influxdata/telegraf/issues/502): php fpm unix socket and other fixes, thanks @kureikain! +- [#543](https://github.com/influxdata/telegraf/issues/543): Statsd Packet size sometimes truncated. +- [#440](https://github.com/influxdata/telegraf/issues/440): Don't query filtered devices for disk stats. +- [#463](https://github.com/influxdata/telegraf/issues/463): Docker plugin not working on AWS Linux +- [#568](https://github.com/influxdata/telegraf/issues/568): Multiple output race condition. +- [#585](https://github.com/influxdata/telegraf/pull/585): Log stack trace and continue on Telegraf panic. Thanks @wutaizeng! + +## v0.10.0 [2016-01-12] + +### Release Notes + +- Linux packages have been taken out of `opt`, the binary is now in `/usr/bin` +and configuration files are in `/etc/telegraf` +- **breaking change** `plugins` have been renamed to `inputs`. This was done because +`plugins` is too generic, as there are now also "output plugins", and will likely +be "aggregator plugins" and "filter plugins" in the future. Additionally, +`inputs/` and `outputs/` directories have been placed in the root-level `plugins/` +directory. +- **breaking change** the `io` plugin has been renamed `diskio` +- **breaking change** plugin measurements aggregated into a single measurement. +- **breaking change** `jolokia` plugin: must use global tag/drop/pass parameters +for configuration. +- **breaking change** `twemproxy` plugin: `prefix` option removed. +- **breaking change** `procstat` cpu measurements are now prepended with `cpu_time_` +instead of only `cpu_` +- **breaking change** some command-line flags have been renamed to separate words. +`-configdirectory` -> `-config-directory`, `-filter` -> `-input-filter`, +`-outputfilter` -> `-output-filter` +- The prometheus plugin schema has not been changed (measurements have not been +aggregated). + +### Packaging change note + +RHEL/CentOS users upgrading from 0.2.x to 0.10.0 will probably have their +configurations overwritten by the upgrade. There is a backup stored at +/etc/telegraf/telegraf.conf.$(date +%s).backup. + +### Features + +- Plugin measurements aggregated into a single measurement. +- Added ability to specify per-plugin tags +- Added ability to specify per-plugin measurement suffix and prefix. +(`name_prefix` and `name_suffix`) +- Added ability to override base plugin measurement name. (`name_override`) + +### Bug Fixes + +## v0.2.5 [unreleased] + +### Features + +- [#427](https://github.com/influxdata/telegraf/pull/427): zfs plugin: pool stats added. Thanks @allenpetersen! +- [#428](https://github.com/influxdata/telegraf/pull/428): Amazon Kinesis output. Thanks @jimmystewpot! +- [#449](https://github.com/influxdata/telegraf/pull/449): influxdb plugin, thanks @mark-rushakoff + +### Bug Fixes + +- [#430](https://github.com/influxdata/telegraf/issues/430): Network statistics removed in elasticsearch 2.1. Thanks @jipperinbham! +- [#452](https://github.com/influxdata/telegraf/issues/452): Elasticsearch open file handles error. Thanks @jipperinbham! + +## v0.2.4 [2015-12-08] + +### Features + +- [#412](https://github.com/influxdata/telegraf/pull/412): Additional memcached stats. Thanks @mgresser! +- [#410](https://github.com/influxdata/telegraf/pull/410): Additional redis metrics. Thanks @vlaadbrain! +- [#414](https://github.com/influxdata/telegraf/issues/414): Jolokia plugin auth parameters +- [#415](https://github.com/influxdata/telegraf/issues/415): memcached plugin: support unix sockets +- [#418](https://github.com/influxdata/telegraf/pull/418): memcached plugin additional unit tests. +- [#408](https://github.com/influxdata/telegraf/pull/408): MailChimp plugin. +- [#382](https://github.com/influxdata/telegraf/pull/382): Add system wide network protocol stats to `net` plugin. +- [#401](https://github.com/influxdata/telegraf/pull/401): Support pass/drop/tagpass/tagdrop for outputs. Thanks @oldmantaiter! + +### Bug Fixes + +- [#405](https://github.com/influxdata/telegraf/issues/405): Prometheus output cardinality issue +- [#388](https://github.com/influxdata/telegraf/issues/388): Fix collection hangup when cpu times decrement. + +## v0.2.3 [2015-11-30] + +### Release Notes + +- **breaking change** The `kafka` plugin has been renamed to `kafka_consumer`. +and most of the config option names have changed. +This only affects the kafka consumer _plugin_ (not the +output). There were a number of problems with the kafka plugin that led to it +only collecting data once at startup, so the kafka plugin was basically non- +functional. +- Plugins can now be specified as a list, and multiple plugin instances of the +same type can be specified, like this: + +```toml +[[inputs.cpu]] + percpu = false + totalcpu = true + +[[inputs.cpu]] + percpu = true + totalcpu = false + drop = ["cpu_time"] +``` + +- Riemann output added +- Aerospike plugin: tag changed from `host` -> `aerospike_host` + +### Features + +- [#379](https://github.com/influxdata/telegraf/pull/379): Riemann output, thanks @allenj! +- [#375](https://github.com/influxdata/telegraf/pull/375): kafka_consumer service plugin. +- [#392](https://github.com/influxdata/telegraf/pull/392): Procstat plugin can now accept pgrep -f pattern, thanks @ecarreras! +- [#383](https://github.com/influxdata/telegraf/pull/383): Specify plugins as a list. +- [#354](https://github.com/influxdata/telegraf/pull/354): Add ability to specify multiple metrics in one statsd line. Thanks @MerlinDMC! + +### Bug Fixes + +- [#371](https://github.com/influxdata/telegraf/issues/371): Kafka consumer plugin not functioning. +- [#389](https://github.com/influxdata/telegraf/issues/389): NaN value panic + +## v0.2.2 [2015-11-18] + +### Release Notes + +- 0.2.1 has a bug where all lists within plugins get duplicated, this includes +lists of servers/URLs. 0.2.2 is being released solely to fix that bug + +### Bug Fixes + +- [#377](https://github.com/influxdata/telegraf/pull/377): Fix for duplicate slices in inputs. + +## v0.2.1 [2015-11-16] + +### Release Notes + +- Telegraf will no longer use docker-compose for "long" unit test, it has been +changed to just run docker commands in the Makefile. See `make docker-run` and +`make docker-kill`. `make test` will still run all unit tests with docker. +- Long unit tests are now run in CircleCI, with docker & race detector +- Redis plugin tag has changed from `host` to `server` +- HAProxy plugin tag has changed from `host` to `server` +- UDP output now supported +- Telegraf will now compile on FreeBSD +- Users can now specify outputs as lists, specifying multiple outputs of the +same type. + +### Features + +- [#325](https://github.com/influxdata/telegraf/pull/325): NSQ output. Thanks @jrxFive! +- [#318](https://github.com/influxdata/telegraf/pull/318): Prometheus output. Thanks @oldmantaiter! +- [#338](https://github.com/influxdata/telegraf/pull/338): Restart Telegraf on package upgrade. Thanks @linsomniac! +- [#337](https://github.com/influxdata/telegraf/pull/337): Jolokia plugin, thanks @saiello! +- [#350](https://github.com/influxdata/telegraf/pull/350): Amon output. +- [#365](https://github.com/influxdata/telegraf/pull/365): Twemproxy plugin by @codeb2cc +- [#317](https://github.com/influxdata/telegraf/issues/317): ZFS plugin, thanks @cornerot! +- [#364](https://github.com/influxdata/telegraf/pull/364): Support InfluxDB UDP output. +- [#370](https://github.com/influxdata/telegraf/pull/370): Support specifying multiple outputs, as lists. +- [#372](https://github.com/influxdata/telegraf/pull/372): Remove gosigar and update go-dockerclient for FreeBSD support. Thanks @MerlinDMC! + +### Bug Fixes + +- [#331](https://github.com/influxdata/telegraf/pull/331): Dont overwrite host tag in redis plugin. +- [#336](https://github.com/influxdata/telegraf/pull/336): Mongodb plugin should take 2 measurements. +- [#351](https://github.com/influxdata/telegraf/issues/317): Fix continual "CREATE DATABASE" in writes +- [#360](https://github.com/influxdata/telegraf/pull/360): Apply prefix before ShouldPass check. Thanks @sotfo! + +## v0.2.0 [2015-10-27] + +### Release Notes + +- The -test flag will now only output 2 collections for plugins that need it +- There is a new agent configuration option: `flush_interval`. This option tells +Telegraf how often to flush data to InfluxDB and other output sinks. For example, +users can set `interval = "2s"` and `flush_interval = "60s"` for Telegraf to +collect data every 2 seconds, and flush every 60 seconds. +- `precision` and `utc` are no longer valid agent config values. `precision` has +moved to the `influxdb` output config, where it will continue to default to "s" +- debug and test output will now print the raw line-protocol string +- Telegraf will now, by default, round the collection interval to the nearest +even interval. This means that `interval="10s"` will collect every :00, :10, etc. +To ease scale concerns, flushing will be "jittered" by a random amount so that +all Telegraf instances do not flush at the same time. Both of these options can +be controlled via the `round_interval` and `flush_jitter` config options. +- Telegraf will now retry metric flushes twice + +### Features + +- [#205](https://github.com/influxdata/telegraf/issues/205): Include per-db redis keyspace info +- [#226](https://github.com/influxdata/telegraf/pull/226): Add timestamps to points in Kafka/AMQP outputs. Thanks @ekini +- [#90](https://github.com/influxdata/telegraf/issues/90): Add Docker labels to tags in docker plugin +- [#223](https://github.com/influxdata/telegraf/pull/223): Add port tag to nginx plugin. Thanks @neezgee! +- [#227](https://github.com/influxdata/telegraf/pull/227): Add command intervals to exec plugin. Thanks @jpalay! +- [#241](https://github.com/influxdata/telegraf/pull/241): MQTT Output. Thanks @shirou! +- Memory plugin: cached and buffered measurements re-added +- Logging: additional logging for each collection interval, track the number +of metrics collected and from how many inputs. +- [#240](https://github.com/influxdata/telegraf/pull/240): procstat plugin, thanks @ranjib! +- [#244](https://github.com/influxdata/telegraf/pull/244): netstat plugin, thanks @shirou! +- [#262](https://github.com/influxdata/telegraf/pull/262): zookeeper plugin, thanks @jrxFive! +- [#237](https://github.com/influxdata/telegraf/pull/237): statsd service plugin, thanks @sparrc +- [#273](https://github.com/influxdata/telegraf/pull/273): puppet agent plugin, thats @jrxFive! +- [#280](https://github.com/influxdata/telegraf/issues/280): Use InfluxDB client v2. +- [#281](https://github.com/influxdata/telegraf/issues/281): Eliminate need to deep copy Batch Points. +- [#286](https://github.com/influxdata/telegraf/issues/286): bcache plugin, thanks @cornerot! +- [#287](https://github.com/influxdata/telegraf/issues/287): Batch AMQP output, thanks @ekini! +- [#301](https://github.com/influxdata/telegraf/issues/301): Collect on even intervals +- [#298](https://github.com/influxdata/telegraf/pull/298): Support retrying output writes +- [#300](https://github.com/influxdata/telegraf/issues/300): aerospike plugin. Thanks @oldmantaiter! +- [#322](https://github.com/influxdata/telegraf/issues/322): Librato output. Thanks @jipperinbham! + +### Bug Fixes + +- [#228](https://github.com/influxdata/telegraf/pull/228): New version of package will replace old one. Thanks @ekini! +- [#232](https://github.com/influxdata/telegraf/pull/232): Fix bashism run during deb package installation. Thanks @yankcrime! +- [#261](https://github.com/influxdata/telegraf/issues/260): RabbitMQ panics if wrong credentials given. Thanks @ekini! +- [#245](https://github.com/influxdata/telegraf/issues/245): Document Exec plugin example. Thanks @ekini! +- [#264](https://github.com/influxdata/telegraf/issues/264): logrotate config file fixes. Thanks @linsomniac! +- [#290](https://github.com/influxdata/telegraf/issues/290): Fix some plugins sending their values as strings. +- [#289](https://github.com/influxdata/telegraf/issues/289): Fix accumulator panic on nil tags. +- [#302](https://github.com/influxdata/telegraf/issues/302): Fix `[tags]` getting applied, thanks @gotyaoi! + +## v0.1.9 [2015-09-22] + +### Release Notes + +- InfluxDB output config change: `url` is now `urls`, and is a list. Config files +will still be backwards compatible if only `url` is specified. +- The -test flag will now output two metric collections +- Support for filtering telegraf outputs on the CLI -- Telegraf will now +allow filtering of output sinks on the command-line using the `-outputfilter` +flag, much like how the `-filter` flag works for inputs. +- Support for filtering on config-file creation -- Telegraf now supports +filtering to -sample-config command. You can now run +`telegraf -sample-config -filter cpu -outputfilter influxdb` to get a config +file with only the cpu plugin defined, and the influxdb output defined. +- **Breaking Change**: The CPU collection plugin has been refactored to fix some +bugs and outdated dependency issues. At the same time, I also decided to fix +a naming consistency issue, so cpu_percentageIdle will become cpu_usage_idle. +Also, all CPU time measurements now have it indicated in their name, so cpu_idle +will become cpu_time_idle. Additionally, cpu_time measurements are going to be +dropped in the default config. +- **Breaking Change**: The memory plugin has been refactored and some measurements +have been renamed for consistency. Some measurements have also been removed from being outputted. They are still being collected by gopsutil, and could easily be +re-added in a "verbose" mode if there is demand for it. + +### Features + +- [#143](https://github.com/influxdata/telegraf/issues/143): InfluxDB clustering support +- [#181](https://github.com/influxdata/telegraf/issues/181): Makefile GOBIN support. Thanks @Vye! +- [#203](https://github.com/influxdata/telegraf/pull/200): AMQP output. Thanks @ekini! +- [#182](https://github.com/influxdata/telegraf/pull/182): OpenTSDB output. Thanks @rplessl! +- [#187](https://github.com/influxdata/telegraf/pull/187): Retry output sink connections on startup. +- [#220](https://github.com/influxdata/telegraf/pull/220): Add port tag to apache plugin. Thanks @neezgee! +- [#217](https://github.com/influxdata/telegraf/pull/217): Add filtering for output sinks +and filtering when specifying a config file. + +### Bug Fixes + +- [#170](https://github.com/influxdata/telegraf/issues/170): Systemd support +- [#175](https://github.com/influxdata/telegraf/issues/175): Set write precision before gathering metrics +- [#178](https://github.com/influxdata/telegraf/issues/178): redis plugin, multiple server thread hang bug +- Fix net plugin on darwin +- [#84](https://github.com/influxdata/telegraf/issues/84): Fix docker plugin on CentOS. Thanks @neezgee! +- [#189](https://github.com/influxdata/telegraf/pull/189): Fix mem_used_perc. Thanks @mced! +- [#192](https://github.com/influxdata/telegraf/issues/192): Increase compatibility of postgresql plugin. Now supports versions 8.1+ +- [#203](https://github.com/influxdata/telegraf/issues/203): EL5 rpm support. Thanks @ekini! +- [#206](https://github.com/influxdata/telegraf/issues/206): CPU steal/guest values wrong on linux. +- [#212](https://github.com/influxdata/telegraf/issues/212): Add hashbang to postinstall script. Thanks @ekini! +- [#212](https://github.com/influxdata/telegraf/issues/212): Fix makefile warning. Thanks @ekini! + +## v0.1.8 [2015-09-04] + +### Release Notes + +- Telegraf will now write data in UTC at second precision by default +- Now using Go 1.5 to build telegraf + +### Features + +- [#150](https://github.com/influxdata/telegraf/pull/150): Add Host Uptime metric to system plugin +- [#158](https://github.com/influxdata/telegraf/pull/158): Apache Plugin. Thanks @KPACHbIuLLIAnO4 +- [#159](https://github.com/influxdata/telegraf/pull/159): Use second precision for InfluxDB writes +- [#165](https://github.com/influxdata/telegraf/pull/165): Add additional metrics to mysql plugin. Thanks @nickscript0 +- [#162](https://github.com/influxdata/telegraf/pull/162): Write UTC by default, provide option +- [#166](https://github.com/influxdata/telegraf/pull/166): Upload binaries to S3 +- [#169](https://github.com/influxdata/telegraf/pull/169): Ping plugin + +### Bug Fixes + +## v0.1.7 [2015-08-28] + +### Features + +- [#38](https://github.com/influxdata/telegraf/pull/38): Kafka output producer. +- [#133](https://github.com/influxdata/telegraf/pull/133): Add plugin.Gather error logging. Thanks @nickscript0! +- [#136](https://github.com/influxdata/telegraf/issues/136): Add a -usage flag for printing usage of a single plugin. +- [#137](https://github.com/influxdata/telegraf/issues/137): Memcached: fix when a value contains a space +- [#138](https://github.com/influxdata/telegraf/issues/138): MySQL server address tag. +- [#142](https://github.com/influxdata/telegraf/pull/142): Add Description and SampleConfig funcs to output interface +- Indent the toml config file for readability + +### Bug Fixes + +- [#128](https://github.com/influxdata/telegraf/issues/128): system_load measurement missing. +- [#129](https://github.com/influxdata/telegraf/issues/129): Latest pkg url fix. +- [#131](https://github.com/influxdata/telegraf/issues/131): Fix memory reporting on linux & darwin. Thanks @subhachandrachandra! +- [#140](https://github.com/influxdata/telegraf/issues/140): Memory plugin prec->perc typo fix. Thanks @brunoqc! + +## v0.1.6 [2015-08-20] + +### Features + +- [#112](https://github.com/influxdata/telegraf/pull/112): Datadog output. Thanks @jipperinbham! +- [#116](https://github.com/influxdata/telegraf/pull/116): Use godep to vendor all dependencies +- [#120](https://github.com/influxdata/telegraf/pull/120): Httpjson plugin. Thanks @jpalay & @alvaromorales! + +### Bug Fixes + +- [#113](https://github.com/influxdata/telegraf/issues/113): Update README with Telegraf/InfluxDB compatibility +- [#118](https://github.com/influxdata/telegraf/pull/118): Fix for disk usage stats in Windows. Thanks @srfraser! +- [#122](https://github.com/influxdata/telegraf/issues/122): Fix for DiskUsage segv fault. Thanks @srfraser! +- [#126](https://github.com/influxdata/telegraf/issues/126): Nginx plugin not catching net.SplitHostPort error + +## v0.1.5 [2015-08-13] + +### Features + +- [#54](https://github.com/influxdata/telegraf/pull/54): MongoDB plugin. Thanks @jipperinbham! +- [#55](https://github.com/influxdata/telegraf/pull/55): Elasticsearch plugin. Thanks @brocaar! +- [#71](https://github.com/influxdata/telegraf/pull/71): HAProxy plugin. Thanks @kureikain! +- [#72](https://github.com/influxdata/telegraf/pull/72): Adding TokuDB metrics to MySQL. Thanks vadimtk! +- [#73](https://github.com/influxdata/telegraf/pull/73): RabbitMQ plugin. Thanks @ianunruh! +- [#77](https://github.com/influxdata/telegraf/issues/77): Automatically create database. +- [#79](https://github.com/influxdata/telegraf/pull/56): Nginx plugin. Thanks @codeb2cc! +- [#86](https://github.com/influxdata/telegraf/pull/86): Lustre2 plugin. Thanks srfraser! +- [#91](https://github.com/influxdata/telegraf/pull/91): Unit testing +- [#92](https://github.com/influxdata/telegraf/pull/92): Exec plugin. Thanks @alvaromorales! +- [#98](https://github.com/influxdata/telegraf/pull/98): LeoFS plugin. Thanks @mocchira! +- [#103](https://github.com/influxdata/telegraf/pull/103): Filter by metric tags. Thanks @srfraser! +- [#106](https://github.com/influxdata/telegraf/pull/106): Options to filter plugins on startup. Thanks @zepouet! +- [#107](https://github.com/influxdata/telegraf/pull/107): Multiple outputs beyond influxdb. Thanks @jipperinbham! +- [#108](https://github.com/influxdata/telegraf/issues/108): Support setting per-CPU and total-CPU gathering. +- [#111](https://github.com/influxdata/telegraf/pull/111): Report CPU Usage in cpu plugin. Thanks @jpalay! + +### Bug Fixes + +- [#85](https://github.com/influxdata/telegraf/pull/85): Fix GetLocalHost testutil function for mac users +- [#89](https://github.com/influxdata/telegraf/pull/89): go fmt fixes +- [#94](https://github.com/influxdata/telegraf/pull/94): Fix for issue #93, explicitly call sarama.v1 -> sarama +- [#101](https://github.com/influxdata/telegraf/issues/101): switch back from master branch if building locally +- [#99](https://github.com/influxdata/telegraf/issues/99): update integer output to new InfluxDB line protocol format + +## v0.1.4 [2015-07-09] + +### Features + +- [#56](https://github.com/influxdata/telegraf/pull/56): Update README for Kafka plugin. Thanks @EmilS! + +### Bug Fixes + +- [#50](https://github.com/influxdata/telegraf/pull/50): Fix init.sh script to use telegraf directory. Thanks @jseriff! +- [#52](https://github.com/influxdata/telegraf/pull/52): Update CHANGELOG to reference updated directory. Thanks @benfb! + +## v0.1.3 [2015-07-05] + +### Features + +- [#35](https://github.com/influxdata/telegraf/pull/35): Add Kafka plugin. Thanks @EmilS! +- [#47](https://github.com/influxdata/telegraf/pull/47): Add RethinkDB plugin. Thanks @jipperinbham! + +### Bug Fixes + +- [#45](https://github.com/influxdata/telegraf/pull/45): Skip disk tags that don't have a value. Thanks @jhofeditz! +- [#43](https://github.com/influxdata/telegraf/pull/43): Fix bug in MySQL plugin. Thanks @marcosnils! + +## v0.1.2 [2015-07-01] + +### Features + +- [#12](https://github.com/influxdata/telegraf/pull/12): Add Linux/ARM to the list of built binaries. Thanks @voxxit! +- [#14](https://github.com/influxdata/telegraf/pull/14): Clarify the S3 buckets that Telegraf is pushed to. +- [#16](https://github.com/influxdata/telegraf/pull/16): Convert Redis to use URI, support Redis AUTH. Thanks @jipperinbham! +- [#21](https://github.com/influxdata/telegraf/pull/21): Add memcached plugin. Thanks @Yukki! + +### Bug Fixes + +- [#13](https://github.com/influxdata/telegraf/pull/13): Fix the packaging script. +- [#19](https://github.com/influxdata/telegraf/pull/19): Add host name to metric tags. Thanks @sherifzain! +- [#20](https://github.com/influxdata/telegraf/pull/20): Fix race condition with accumulator mutex. Thanks @nkatsaros! +- [#23](https://github.com/influxdata/telegraf/pull/23): Change name of folder for packages. Thanks @colinrymer! +- [#32](https://github.com/influxdata/telegraf/pull/32): Fix spelling of memoory -> memory. Thanks @tylernisonoff! + +## v0.1.1 [2015-06-19] + +### Release Notes + +This is the initial release of Telegraf. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..4413f27 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4258 @@ + +# Changelog + +## v1.34.4 [2025-05-19] + +### Bugfixes + +- [#17009](https://github.com/influxdata/telegraf/pull/17009) `inputs.cloudwatch` Restore filtering to match all dimensions +- [#16978](https://github.com/influxdata/telegraf/pull/16978) `inputs.nfsclient` Handle errors during mountpoint filtering +- [#17021](https://github.com/influxdata/telegraf/pull/17021) `inputs.opcua` Fix type mismatch in unit test +- [#16854](https://github.com/influxdata/telegraf/pull/16854) `inputs.opcua` Handle session invalidation between gather cycles +- [#16879](https://github.com/influxdata/telegraf/pull/16879) `inputs.tail` Prevent leaking file descriptors +- [#16815](https://github.com/influxdata/telegraf/pull/16815) `inputs.win_eventlog` Handle large events to avoid they get dropped silently +- [#16878](https://github.com/influxdata/telegraf/pull/16878) `parsers.json_v2` Handle measurements with multiple objects correctly + +### Dependency Updates + +- [#16991](https://github.com/influxdata/telegraf/pull/16991) `deps` Bump cloud.google.com/go/bigquery from 1.67.0 to 1.68.0 +- [#16963](https://github.com/influxdata/telegraf/pull/16963) `deps` Bump cloud.google.com/go/storage from 1.52.0 to 1.53.0 +- [#16955](https://github.com/influxdata/telegraf/pull/16955) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue from 1.0.0 to 1.0.1 +- [#16989](https://github.com/influxdata/telegraf/pull/16989) `deps` Bump github.com/SAP/go-hdb from 1.13.5 to 1.13.6 +- [#16998](https://github.com/influxdata/telegraf/pull/16998) `deps` Bump github.com/apache/arrow-go/v18 from 18.2.0 to 18.3.0 +- [#16952](https://github.com/influxdata/telegraf/pull/16952) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.47.3 to 1.48.0 +- [#16995](https://github.com/influxdata/telegraf/pull/16995) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.48.0 to 1.49.0 +- [#16974](https://github.com/influxdata/telegraf/pull/16974) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.212.0 to 1.214.0 +- [#16993](https://github.com/influxdata/telegraf/pull/16993) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.215.0 to 1.218.0 +- [#16968](https://github.com/influxdata/telegraf/pull/16968) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.33.3 to 1.35.0 +- [#16988](https://github.com/influxdata/telegraf/pull/16988) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.30.2 to 1.31.0 +- [#17013](https://github.com/influxdata/telegraf/pull/17013) `deps` Bump github.com/ebitengine/purego from 0.8.2 to 0.8.3 +- [#16972](https://github.com/influxdata/telegraf/pull/16972) `deps` Bump github.com/hashicorp/consul/api from 1.32.0 to 1.32.1 +- [#16992](https://github.com/influxdata/telegraf/pull/16992) `deps` Bump github.com/microsoft/go-mssqldb from 1.8.0 to 1.8.1 +- [#16990](https://github.com/influxdata/telegraf/pull/16990) `deps` Bump github.com/miekg/dns from 1.1.65 to 1.1.66 +- [#16975](https://github.com/influxdata/telegraf/pull/16975) `deps` Bump github.com/nats-io/nats-server/v2 from 2.11.2 to 2.11.3 +- [#16967](https://github.com/influxdata/telegraf/pull/16967) `deps` Bump github.com/nats-io/nats.go from 1.41.2 to 1.42.0 +- [#16964](https://github.com/influxdata/telegraf/pull/16964) `deps` Bump github.com/rclone/rclone from 1.69.1 to 1.69.2 +- [#16973](https://github.com/influxdata/telegraf/pull/16973) `deps` Bump github.com/redis/go-redis/v9 from 9.7.3 to 9.8.0 +- [#16962](https://github.com/influxdata/telegraf/pull/16962) `deps` Bump github.com/shirou/gopsutil/v4 from 4.25.3 to 4.25.4 +- [#16969](https://github.com/influxdata/telegraf/pull/16969) `deps` Bump github.com/snowflakedb/gosnowflake from 1.13.3 to 1.14.0 +- [#16994](https://github.com/influxdata/telegraf/pull/16994) `deps` Bump github.com/vishvananda/netlink from 1.3.1-0.20250221194427-0af32151e72b to 1.3.1 +- [#16958](https://github.com/influxdata/telegraf/pull/16958) `deps` Bump go.step.sm/crypto from 0.62.0 to 0.63.0 +- [#16960](https://github.com/influxdata/telegraf/pull/16960) `deps` Bump golang.org/x/crypto from 0.37.0 to 0.38.0 +- [#16966](https://github.com/influxdata/telegraf/pull/16966) `deps` Bump golang.org/x/net from 0.39.0 to 0.40.0 +- [#16957](https://github.com/influxdata/telegraf/pull/16957) `deps` Bump google.golang.org/api from 0.230.0 to 0.231.0 +- [#16853](https://github.com/influxdata/telegraf/pull/16853) `deps` Switch to maintained azure testcontainer module + +## v1.34.3 [2025-05-05] + +### Bugfixes + +- [#16697](https://github.com/influxdata/telegraf/pull/16697) `agent` Correctly truncate the disk buffer +- [#16868](https://github.com/influxdata/telegraf/pull/16868) `common.ratelimiter` Only grow the buffer but never shrink +- [#16812](https://github.com/influxdata/telegraf/pull/16812) `inputs.cloudwatch` Handle metric includes/excludes correctly to prevent panic +- [#16911](https://github.com/influxdata/telegraf/pull/16911) `inputs.lustre2` Skip empty files +- [#16594](https://github.com/influxdata/telegraf/pull/16594) `inputs.opcua` Handle node array values +- [#16782](https://github.com/influxdata/telegraf/pull/16782) `inputs.win_wmi` Replace hard-coded class-name with correct config setting +- [#16781](https://github.com/influxdata/telegraf/pull/16781) `inputs.win_wmi` Restrict threading model to APARTMENTTHREADED +- [#16857](https://github.com/influxdata/telegraf/pull/16857) `outputs.quix` Allow empty certificate for new cloud managed instances + +### Dependency Updates + +- [#16804](https://github.com/influxdata/telegraf/pull/16804) `deps` Bump cloud.google.com/go/bigquery from 1.66.2 to 1.67.0 +- [#16835](https://github.com/influxdata/telegraf/pull/16835) `deps` Bump cloud.google.com/go/monitoring from 1.24.0 to 1.24.2 +- [#16785](https://github.com/influxdata/telegraf/pull/16785) `deps` Bump cloud.google.com/go/pubsub from 1.48.0 to 1.49.0 +- [#16897](https://github.com/influxdata/telegraf/pull/16897) `deps` Bump cloud.google.com/go/storage from 1.51.0 to 1.52.0 +- [#16840](https://github.com/influxdata/telegraf/pull/16840) `deps` Bump github.com/BurntSushi/toml from 1.4.0 to 1.5.0 +- [#16838](https://github.com/influxdata/telegraf/pull/16838) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go from 1.63.104 to 1.63.106 +- [#16908](https://github.com/influxdata/telegraf/pull/16908) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go from 1.63.106 to 1.63.107 +- [#16789](https://github.com/influxdata/telegraf/pull/16789) `deps` Bump github.com/antchfx/xpath from 1.3.3 to 1.3.4 +- [#16807](https://github.com/influxdata/telegraf/pull/16807) `deps` Bump github.com/apache/arrow-go/v18 from 18.1.0 to 18.2.0 +- [#16844](https://github.com/influxdata/telegraf/pull/16844) `deps` Bump github.com/apache/iotdb-client-go from 1.3.3 to 1.3.4 +- [#16839](https://github.com/influxdata/telegraf/pull/16839) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.44.1 to 1.44.3 +- [#16836](https://github.com/influxdata/telegraf/pull/16836) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.45.3 to 1.47.3 +- [#16846](https://github.com/influxdata/telegraf/pull/16846) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.42.2 to 1.42.4 +- [#16905](https://github.com/influxdata/telegraf/pull/16905) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.42.4 to 1.43.1 +- [#16842](https://github.com/influxdata/telegraf/pull/16842) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.210.1 to 1.211.3 +- [#16900](https://github.com/influxdata/telegraf/pull/16900) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.211.3 to 1.212.0 +- [#16903](https://github.com/influxdata/telegraf/pull/16903) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.33.2 to 1.33.3 +- [#16793](https://github.com/influxdata/telegraf/pull/16793) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.27.4 to 1.30.2 +- [#16802](https://github.com/influxdata/telegraf/pull/16802) `deps` Bump github.com/clarify/clarify-go from 0.3.1 to 0.4.0 +- [#16849](https://github.com/influxdata/telegraf/pull/16849) `deps` Bump github.com/docker/docker from 28.0.4+incompatible to 28.1.1+incompatible +- [#16830](https://github.com/influxdata/telegraf/pull/16830) `deps` Bump github.com/go-ldap/ldap/v3 from 3.4.10 to 3.4.11 +- [#16801](https://github.com/influxdata/telegraf/pull/16801) `deps` Bump github.com/go-sql-driver/mysql from 1.8.1 to 1.9.2 +- [#16806](https://github.com/influxdata/telegraf/pull/16806) `deps` Bump github.com/gofrs/uuid/v5 from 5.3.0 to 5.3.2 +- [#16895](https://github.com/influxdata/telegraf/pull/16895) `deps` Bump github.com/google/cel-go from 0.24.1 to 0.25.0 +- [#16797](https://github.com/influxdata/telegraf/pull/16797) `deps` Bump github.com/gopcua/opcua from 0.7.1 to 0.7.4 +- [#16894](https://github.com/influxdata/telegraf/pull/16894) `deps` Bump github.com/gopcua/opcua from 0.7.4 to 0.8.0 +- [#16660](https://github.com/influxdata/telegraf/pull/16660) `deps` Bump github.com/gosmnp/gosnmp from 1.39.0 to 1.40.0 +- [#16902](https://github.com/influxdata/telegraf/pull/16902) `deps` Bump github.com/gosnmp/gosnmp from 1.39.0 to 1.40.0 +- [#16841](https://github.com/influxdata/telegraf/pull/16841) `deps` Bump github.com/hashicorp/consul/api from 1.31.2 to 1.32.0 +- [#16891](https://github.com/influxdata/telegraf/pull/16891) `deps` Bump github.com/jedib0t/go-pretty/v6 from 6.6.5 to 6.6.7 +- [#16892](https://github.com/influxdata/telegraf/pull/16892) `deps` Bump github.com/lxc/incus/v6 from 6.11.0 to 6.12.0 +- [#16786](https://github.com/influxdata/telegraf/pull/16786) `deps` Bump github.com/microsoft/go-mssqldb from 1.7.2 to 1.8.0 +- [#16851](https://github.com/influxdata/telegraf/pull/16851) `deps` Bump github.com/miekg/dns from 1.1.64 to 1.1.65 +- [#16808](https://github.com/influxdata/telegraf/pull/16808) `deps` Bump github.com/nats-io/nats-server/v2 from 2.10.25 to 2.10.27 +- [#16888](https://github.com/influxdata/telegraf/pull/16888) `deps` Bump github.com/nats-io/nats-server/v2 from 2.10.27 to 2.11.2 +- [#16909](https://github.com/influxdata/telegraf/pull/16909) `deps` Bump github.com/nats-io/nats.go from 1.41.1 to 1.41.2 +- [#16790](https://github.com/influxdata/telegraf/pull/16790) `deps` Bump github.com/openconfig/gnmi from 0.11.0 to 0.14.1 +- [#16799](https://github.com/influxdata/telegraf/pull/16799) `deps` Bump github.com/openconfig/goyang from 1.6.0 to 1.6.2 +- [#16848](https://github.com/influxdata/telegraf/pull/16848) `deps` Bump github.com/prometheus-community/pro-bing from 0.4.1 to 0.7.0 +- [#16795](https://github.com/influxdata/telegraf/pull/16795) `deps` Bump github.com/prometheus/client_golang from 1.21.1 to 1.22.0 +- [#16845](https://github.com/influxdata/telegraf/pull/16845) `deps` Bump github.com/prometheus/client_model from 0.6.1 to 0.6.2 +- [#16901](https://github.com/influxdata/telegraf/pull/16901) `deps` Bump github.com/prometheus/procfs from 0.16.0 to 0.16.1 +- [#16792](https://github.com/influxdata/telegraf/pull/16792) `deps` Bump github.com/safchain/ethtool from 0.3.0 to 0.5.10 +- [#16791](https://github.com/influxdata/telegraf/pull/16791) `deps` Bump github.com/seancfoley/ipaddress-go from 1.7.0 to 1.7.1 +- [#16794](https://github.com/influxdata/telegraf/pull/16794) `deps` Bump github.com/shirou/gopsutil/v4 from 4.25.1 to 4.25.3 +- [#16828](https://github.com/influxdata/telegraf/pull/16828) `deps` Bump github.com/snowflakedb/gosnowflake from 1.11.2 to 1.13.1 +- [#16904](https://github.com/influxdata/telegraf/pull/16904) `deps` Bump github.com/snowflakedb/gosnowflake from 1.13.1 to 1.13.3 +- [#16787](https://github.com/influxdata/telegraf/pull/16787) `deps` Bump github.com/srebhan/cborquery from 1.0.3 to 1.0.4 +- [#16837](https://github.com/influxdata/telegraf/pull/16837) `deps` Bump github.com/srebhan/protobufquery from 1.0.1 to 1.0.4 +- [#16893](https://github.com/influxdata/telegraf/pull/16893) `deps` Bump github.com/testcontainers/testcontainers-go from 0.36.0 to 0.37.0 +- [#16803](https://github.com/influxdata/telegraf/pull/16803) `deps` Bump github.com/testcontainers/testcontainers-go/modules/kafka from 0.34.0 to 0.36.0 +- [#16890](https://github.com/influxdata/telegraf/pull/16890) `deps` Bump github.com/testcontainers/testcontainers-go/modules/kafka from 0.36.0 to 0.37.0 +- [#16850](https://github.com/influxdata/telegraf/pull/16850) `deps` Bump github.com/vmware/govmomi from 0.49.0 to 0.50.0 +- [#16784](https://github.com/influxdata/telegraf/pull/16784) `deps` Bump github.com/yuin/goldmark from 1.7.8 to 1.7.9 +- [#16896](https://github.com/influxdata/telegraf/pull/16896) `deps` Bump github.com/yuin/goldmark from 1.7.9 to 1.7.11 +- [#16832](https://github.com/influxdata/telegraf/pull/16832) `deps` Bump go.mongodb.org/mongo-driver from 1.17.0 to 1.17.3 +- [#16800](https://github.com/influxdata/telegraf/pull/16800) `deps` Bump go.opentelemetry.io/collector/pdata from 1.29.0 to 1.30.0 +- [#16907](https://github.com/influxdata/telegraf/pull/16907) `deps` Bump go.opentelemetry.io/collector/pdata from 1.30.0 to 1.31.0 +- [#16831](https://github.com/influxdata/telegraf/pull/16831) `deps` Bump go.step.sm/crypto from 0.60.0 to 0.61.0 +- [#16886](https://github.com/influxdata/telegraf/pull/16886) `deps` Bump go.step.sm/crypto from 0.61.0 to 0.62.0 +- [#16816](https://github.com/influxdata/telegraf/pull/16816) `deps` Bump golangci-lint from v2.0.2 to v2.1.2 +- [#16852](https://github.com/influxdata/telegraf/pull/16852) `deps` Bump gonum.org/v1/gonum from 0.15.1 to 0.16.0 +- [#16805](https://github.com/influxdata/telegraf/pull/16805) `deps` Bump google.golang.org/api from 0.228.0 to 0.229.0 +- [#16898](https://github.com/influxdata/telegraf/pull/16898) `deps` Bump google.golang.org/api from 0.229.0 to 0.230.0 +- [#16834](https://github.com/influxdata/telegraf/pull/16834) `deps` Bump google.golang.org/grpc from 1.71.1 to 1.72.0 +- [#16889](https://github.com/influxdata/telegraf/pull/16889) `deps` Bump k8s.io/client-go from 0.32.3 to 0.33.0 +- [#16843](https://github.com/influxdata/telegraf/pull/16843) `deps` Bump modernc.org/sqlite from 1.36.2 to 1.37.0 + +## v1.34.2 [2025-04-14] + +### Bugfixes + +- [#16375](https://github.com/influxdata/telegraf/pull/16375) `aggregators` Handle time drift when calculating aggregation windows + +### Dependency Updates + +- [#16689](https://github.com/influxdata/telegraf/pull/16689) `deps` Bump cloud.google.com/go/pubsub from 1.45.3 to 1.48.0 +- [#16769](https://github.com/influxdata/telegraf/pull/16769) `deps` Bump cloud.google.com/go/storage from 1.50.0 to 1.51.0 +- [#16771](https://github.com/influxdata/telegraf/pull/16771) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.17.0 to 1.18.0 +- [#16708](https://github.com/influxdata/telegraf/pull/16708) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs from 1.2.3 to 1.3.1 +- [#16764](https://github.com/influxdata/telegraf/pull/16764) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs from 1.3.1 to 1.3.2 +- [#16777](https://github.com/influxdata/telegraf/pull/16777) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.30.3 to 2.34.0 +- [#16707](https://github.com/influxdata/telegraf/pull/16707) `deps` Bump github.com/IBM/sarama from v1.43.3 to v1.45.1 +- [#16739](https://github.com/influxdata/telegraf/pull/16739) `deps` Bump github.com/SAP/go-hdb from 1.9.10 to 1.13.5 +- [#16754](https://github.com/influxdata/telegraf/pull/16754) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go from 1.62.721 to 1.63.104 +- [#16767](https://github.com/influxdata/telegraf/pull/16767) `deps` Bump github.com/antchfx/jsonquery from 1.3.3 to 1.3.6 +- [#16758](https://github.com/influxdata/telegraf/pull/16758) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.29.6 to 1.29.13 +- [#16710](https://github.com/influxdata/telegraf/pull/16710) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.59 to 1.17.65 +- [#16685](https://github.com/influxdata/telegraf/pull/16685) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.43.14 to 1.44.1 +- [#16773](https://github.com/influxdata/telegraf/pull/16773) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.40.0 to 1.42.2 +- [#16688](https://github.com/influxdata/telegraf/pull/16688) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.203.1 to 1.210.1 +- [#16772](https://github.com/influxdata/telegraf/pull/16772) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.32.6 to 1.33.2 +- [#16711](https://github.com/influxdata/telegraf/pull/16711) `deps` Bump github.com/cloudevents/sdk-go/v2 from 2.15.2 to 2.16.0 +- [#16687](https://github.com/influxdata/telegraf/pull/16687) `deps` Bump github.com/google/cel-go from 0.23.0 to 0.24.1 +- [#16712](https://github.com/influxdata/telegraf/pull/16712) `deps` Bump github.com/gophercloud/gophercloud/v2 from 2.0.0-rc.3 to 2.6.0 +- [#16738](https://github.com/influxdata/telegraf/pull/16738) `deps` Bump github.com/gorcon/rcon from 1.3.5 to 1.4.0 +- [#16737](https://github.com/influxdata/telegraf/pull/16737) `deps` Bump github.com/gosnmp/gosnmp from 1.38.0 to 1.39.0 +- [#16752](https://github.com/influxdata/telegraf/pull/16752) `deps` Bump github.com/lxc/incus/v6 from 6.9.0 to 6.11.0 +- [#16761](https://github.com/influxdata/telegraf/pull/16761) `deps` Bump github.com/nats-io/nats.go from 1.39.1 to 1.41.1 +- [#16753](https://github.com/influxdata/telegraf/pull/16753) `deps` Bump github.com/netsampler/goflow2/v2 from 2.2.1 to 2.2.2 +- [#16760](https://github.com/influxdata/telegraf/pull/16760) `deps` Bump github.com/p4lang/p4runtime from 1.4.0 to 1.4.1 +- [#16766](https://github.com/influxdata/telegraf/pull/16766) `deps` Bump github.com/prometheus/common from 0.62.0 to 0.63.0 +- [#16686](https://github.com/influxdata/telegraf/pull/16686) `deps` Bump github.com/rclone/rclone from 1.68.2 to 1.69.1 +- [#16770](https://github.com/influxdata/telegraf/pull/16770) `deps` Bump github.com/sijms/go-ora/v2 from 2.8.22 to 2.8.24 +- [#16709](https://github.com/influxdata/telegraf/pull/16709) `deps` Bump github.com/testcontainers/testcontainers-go from 0.35.0 to 0.36.0 +- [#16763](https://github.com/influxdata/telegraf/pull/16763) `deps` Bump github.com/tinylib/msgp from 1.2.0 to 1.2.5 +- [#16757](https://github.com/influxdata/telegraf/pull/16757) `deps` Bump github.com/urfave/cli/v2 from 2.27.2 to 2.27.6 +- [#16724](https://github.com/influxdata/telegraf/pull/16724) `deps` Bump github.com/vmware/govmomi from v0.45.1 to v0.49.0 +- [#16768](https://github.com/influxdata/telegraf/pull/16768) `deps` Bump go.opentelemetry.io/collector/pdata from 1.25.0 to 1.29.0 +- [#16765](https://github.com/influxdata/telegraf/pull/16765) `deps` Bump go.step.sm/crypto from 0.59.1 to 0.60.0 +- [#16756](https://github.com/influxdata/telegraf/pull/16756) `deps` Bump golang.org/x/crypto from 0.36.0 to 0.37.0 +- [#16683](https://github.com/influxdata/telegraf/pull/16683) `deps` Bump golangci-lint from v1.64.5 to v2.0.2 +- [#16759](https://github.com/influxdata/telegraf/pull/16759) `deps` Bump google.golang.org/api from 0.224.0 to 0.228.0 +- [#16755](https://github.com/influxdata/telegraf/pull/16755) `deps` Bump k8s.io/client-go from 0.32.1 to 0.32.3 +- [#16684](https://github.com/influxdata/telegraf/pull/16684) `deps` Bump tj-actions/changed-files from 46.0.1 to 46.0.3 +- [#16736](https://github.com/influxdata/telegraf/pull/16736) `deps` Bump tj-actions/changed-files from 46.0.3 to 46.0.4 +- [#16751](https://github.com/influxdata/telegraf/pull/16751) `deps` Bump tj-actions/changed-files from 46.0.4 to 46.0.5 + +## v1.34.1 [2025-03-24] + +### Bugfixes + +- [#16638](https://github.com/influxdata/telegraf/pull/16638) `agent` Condense plugin source information table when multiple plugins in same file +- [#16674](https://github.com/influxdata/telegraf/pull/16674) `inputs.tail` Do not seek on pipes +- [#16643](https://github.com/influxdata/telegraf/pull/16643) `inputs.tail` Use correct initial_read_offset persistent offset naming in the code +- [#16628](https://github.com/influxdata/telegraf/pull/16628) `outputs.influxdb_v2` Use dynamic token secret +- [#16625](https://github.com/influxdata/telegraf/pull/16625) `outputs.sql` Allow to disable timestamp column +- [#16682](https://github.com/influxdata/telegraf/pull/16682) `secrets` Make 'insufficient lockable memory' warning work on BSDs + +### Dependency Updates + +- [#16612](https://github.com/influxdata/telegraf/pull/16612) `deps` Bump github.com/PaesslerAG/gval from 1.2.2 to 1.2.4 +- [#16650](https://github.com/influxdata/telegraf/pull/16650) `deps` Bump github.com/aws/smithy-go from 1.22.2 to 1.22.3 +- [#16680](https://github.com/influxdata/telegraf/pull/16680) `deps` Bump github.com/golang-jwt/jwt/v4 from 4.5.1 to 4.5.2 +- [#16679](https://github.com/influxdata/telegraf/pull/16679) `deps` Bump github.com/golang-jwt/jwt/v5 from 5.2.1 to 5.2.2 +- [#16610](https://github.com/influxdata/telegraf/pull/16610) `deps` Bump github.com/golang/snappy from 0.0.4 to 1.0.0 +- [#16652](https://github.com/influxdata/telegraf/pull/16652) `deps` Bump github.com/hashicorp/consul/api from 1.29.2 to 1.31.2 +- [#16651](https://github.com/influxdata/telegraf/pull/16651) `deps` Bump github.com/leodido/go-syslog/v4 from 4.1.0 to 4.2.0 +- [#16613](https://github.com/influxdata/telegraf/pull/16613) `deps` Bump github.com/linkedin/goavro/v2 from 2.13.0 to 2.13.1 +- [#16671](https://github.com/influxdata/telegraf/pull/16671) `deps` Bump github.com/redis/go-redis/v9 from 9.7.0 to 9.7.3 +- [#16611](https://github.com/influxdata/telegraf/pull/16611) `deps` Bump go.step.sm/crypto from 0.54.0 to 0.59.1 +- [#16640](https://github.com/influxdata/telegraf/pull/16640) `deps` Bump golang.org/x/crypto from 0.35.0 to 0.36.0 +- [#16620](https://github.com/influxdata/telegraf/pull/16620) `deps` Bump golang.org/x/net from 0.35.0 to 0.36.0 +- [#16639](https://github.com/influxdata/telegraf/pull/16639) `deps` Bump golang.org/x/oauth2 from 0.26.0 to 0.28.0 +- [#16653](https://github.com/influxdata/telegraf/pull/16653) `deps` Bump k8s.io/api from 0.32.1 to 0.32.3 +- [#16659](https://github.com/influxdata/telegraf/pull/16659) `deps` Bump tj-actions/changed-files from v45 to v46.0.1 + +## v1.34.0 [2025-03-10] + +### New Plugins + +- [#15988](https://github.com/influxdata/telegraf/pull/15988) `inputs.firehose` Add new plugin +- [#16352](https://github.com/influxdata/telegraf/pull/16352) `inputs.huebridge` Add plugin +- [#16392](https://github.com/influxdata/telegraf/pull/16392) `inputs.nsdp` Add plugin + +### Features + +- [#16333](https://github.com/influxdata/telegraf/pull/16333) `agent` Add support for input probing +- [#16270](https://github.com/influxdata/telegraf/pull/16270) `agent` Print plugins source information +- [#16474](https://github.com/influxdata/telegraf/pull/16474) `inputs.cgroup` Support more cgroup v2 formats +- [#16337](https://github.com/influxdata/telegraf/pull/16337) `inputs.cloudwatch` Allow wildcards for namespaces +- [#16292](https://github.com/influxdata/telegraf/pull/16292) `inputs.docker` Support swarm jobs +- [#16501](https://github.com/influxdata/telegraf/pull/16501) `inputs.exec` Allow to get untruncated errors in debug mode +- [#16480](https://github.com/influxdata/telegraf/pull/16480) `inputs.gnmi` Add support for `depth` extension +- [#16336](https://github.com/influxdata/telegraf/pull/16336) `inputs.infiniband` Add support for RDMA counters +- [#16124](https://github.com/influxdata/telegraf/pull/16124) `inputs.ipset` Add metric for number of entries and individual IPs +- [#16579](https://github.com/influxdata/telegraf/pull/16579) `inputs.nvidia_smi` Add new power-draw fields for v12 scheme +- [#16305](https://github.com/influxdata/telegraf/pull/16305) `inputs.nvidia_smi` Implement probing +- [#16105](https://github.com/influxdata/telegraf/pull/16105) `inputs.procstat` Add child level tag +- [#16066](https://github.com/influxdata/telegraf/pull/16066) `inputs.proxmox` Allow to add VM-id and status as tag +- [#16287](https://github.com/influxdata/telegraf/pull/16287) `inputs.systemd_units` Add active_enter_timestamp_us field +- [#16342](https://github.com/influxdata/telegraf/pull/16342) `inputs.tail` Add `initial_read_offset` config for controlling read behavior +- [#16355](https://github.com/influxdata/telegraf/pull/16355) `inputs.webhooks` Add support for GitHub workflow events +- [#16508](https://github.com/influxdata/telegraf/pull/16508) `inputs.x509_cert` Add support for JKS and PKCS#12 keystores +- [#16491](https://github.com/influxdata/telegraf/pull/16491) `outputs.mqtt` Add sprig for topic name generator for homie layout +- [#16570](https://github.com/influxdata/telegraf/pull/16570) `outputs.nats` Use Jetstream publisher when using Jetstream +- [#16566](https://github.com/influxdata/telegraf/pull/16566) `outputs.prometheus_client` Allow adding custom headers +- [#16272](https://github.com/influxdata/telegraf/pull/16272) `parsers.avro` Allow union fields to be specified as tags +- [#16493](https://github.com/influxdata/telegraf/pull/16493) `parsers.prometheusremotewrite` Add dense metric version to better support histograms +- [#16214](https://github.com/influxdata/telegraf/pull/16214) `processors.converter` Add support for base64 encoded IEEE floats +- [#16497](https://github.com/influxdata/telegraf/pull/16497) `processors.template` Add sprig function for templates + +### Bugfixes + +- [#16542](https://github.com/influxdata/telegraf/pull/16542) `inputs.gnmi` Handle path elements without name but with keys correctly +- [#16606](https://github.com/influxdata/telegraf/pull/16606) `inputs.huebridge` Cleanup and fix linter issues +- [#16580](https://github.com/influxdata/telegraf/pull/16580) `inputs.net` Skip checks in containerized environments +- [#16555](https://github.com/influxdata/telegraf/pull/16555) `outputs.opensearch` Use correct pipeline name while creating bulk-indexers +- [#16557](https://github.com/influxdata/telegraf/pull/16557) `serializers.prometheus` Use legacy validation for metric name + +### Dependency Updates + +- [#16576](https://github.com/influxdata/telegraf/pull/16576) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.8.1 to 1.8.2 +- [#16553](https://github.com/influxdata/telegraf/pull/16553) `deps` Bump github.com/Azure/go-autorest/autorest from 0.11.29 to 0.11.30 +- [#16552](https://github.com/influxdata/telegraf/pull/16552) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.198.1 to 1.203.1 +- [#16554](https://github.com/influxdata/telegraf/pull/16554) `deps` Bump github.com/go-jose/go-jose/v4 from 4.0.4 to 4.0.5 +- [#16574](https://github.com/influxdata/telegraf/pull/16574) `deps` Bump github.com/gopcua/opcua from 0.5.3 to 0.7.1 +- [#16551](https://github.com/influxdata/telegraf/pull/16551) `deps` Bump github.com/nats-io/nats.go from 1.39.0 to 1.39.1 +- [#16575](https://github.com/influxdata/telegraf/pull/16575) `deps` Bump github.com/tidwall/wal from 1.1.7 to 1.1.8 +- [#16578](https://github.com/influxdata/telegraf/pull/16578) `deps` Bump super-linter/super-linter from 7.2.1 to 7.3.0 + +## v1.33.3 [2025-02-25] + +### Important Changes + +- PR [#16507](https://github.com/influxdata/telegraf/pull/16507) adds the + `enforce_first_namespace_as_origin` to the GNMI input plugin. This option + allows to disable mangling of the response `path` tag by _not_ using namespaces + as origin. It is highly recommended to disable the option. + However, disabling the behavior might change the `path` tag and + thus might break existing queries. Furthermore, the tag modification might + increase cardinality in your database. + +### Bugfixes + +- [#16546](https://github.com/influxdata/telegraf/pull/16546) `agent` Add authorization and user-agent when watching remote configs +- [#16507](https://github.com/influxdata/telegraf/pull/16507) `inputs.gnmi` Allow to disable using first namespace as origin +- [#16511](https://github.com/influxdata/telegraf/pull/16511) `inputs.proxmox` Allow search domain to be empty +- [#16530](https://github.com/influxdata/telegraf/pull/16530) `internal` Fix plural acronyms in SnakeCase function +- [#16539](https://github.com/influxdata/telegraf/pull/16539) `logging` Handle closing correctly and fix tests +- [#16535](https://github.com/influxdata/telegraf/pull/16535) `processors.execd` Detect line-protocol parser correctly + +### Dependency Updates + +- [#16506](https://github.com/influxdata/telegraf/pull/16506) `deps` Bump github.com/ClickHouse/clickhouse-go/v2 from 2.30.1 to 2.30.3 +- [#16502](https://github.com/influxdata/telegraf/pull/16502) `deps` Bump github.com/antchfx/xmlquery from 1.4.1 to 1.4.4 +- [#16519](https://github.com/influxdata/telegraf/pull/16519) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.43.1 to 1.43.14 +- [#16503](https://github.com/influxdata/telegraf/pull/16503) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.36.2 to 1.40.0 +- [#16522](https://github.com/influxdata/telegraf/pull/16522) `deps` Bump github.com/nats-io/nats.go from 1.37.0 to 1.39.0 +- [#16505](https://github.com/influxdata/telegraf/pull/16505) `deps` Bump github.com/srebhan/cborquery from 1.0.1 to 1.0.3 +- [#16534](https://github.com/influxdata/telegraf/pull/16534) `deps` Bump github.com/vishvananda/netlink from 1.3.0 to 1.3.1-0.20250221194427-0af32151e72b +- [#16521](https://github.com/influxdata/telegraf/pull/16521) `deps` Bump go.opentelemetry.io/collector/pdata from 1.12.0 to 1.25.0 +- [#16504](https://github.com/influxdata/telegraf/pull/16504) `deps` Bump golang.org/x/net from 0.34.0 to 0.35.0 +- [#16512](https://github.com/influxdata/telegraf/pull/16512) `deps` Bump golangci-lint from v1.63.4 to v1.64.5 + +## v1.33.2 [2025-02-10] + +### Important Changes + +- PR [#16423](https://github.com/influxdata/telegraf/pull/16423) converts the ClickHouse drivers to the v2 version. + This new version also requires a + [new format for the DSN](https://github.com/ClickHouse/clickhouse-go/tree/v2.30.2?tab=readme-ov-file#dsn). The plugin + tries its best to convert the old DSN to the new format but might not be able to do so. Please check for warnings in + your log file and convert to the new format as soon as possible. +- PR [#16403](https://github.com/influxdata/telegraf/pull/16403) ensures consistency of the NetFlow plugin's + `ip_version` field type by enforcing "IPv4", "IPv6", or "unknown" string values. Previously the `ip_version` could + become an (unsigned) integer when parsing raw-packets' headers especially with SFlow v5 input. Please watch + out for type-conflicts on the output side! + +### Bugfixes + +- [#16477](https://github.com/influxdata/telegraf/pull/16477) `agent` Avoid panic by checking for skip_processors_after_aggregators +- [#16489](https://github.com/influxdata/telegraf/pull/16489) `agent` Set `godebug x509negativeserial=1` as a workaround +- [#16403](https://github.com/influxdata/telegraf/pull/16403) `inputs.netflow` Ensure type consistency for sFlow's IP version field +- [#16447](https://github.com/influxdata/telegraf/pull/16447) `inputs.x509_cert` Add config to left-pad serial number to 128-bits +- [#16448](https://github.com/influxdata/telegraf/pull/16448) `outputs.azure_monitor` Prevent infinite send loop for outdated metrics +- [#16472](https://github.com/influxdata/telegraf/pull/16472) `outputs.sql` Fix insert into ClickHouse +- [#16454](https://github.com/influxdata/telegraf/pull/16454) `service` Set address to prevent orphaned dbus-session processes + +### Dependency Updates + +- [#16442](https://github.com/influxdata/telegraf/pull/16442) `deps` Bump cloud.google.com/go/storage from 1.47.0 to 1.50.0 +- [#16414](https://github.com/influxdata/telegraf/pull/16414) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.7.0 to 1.8.1 +- [#16416](https://github.com/influxdata/telegraf/pull/16416) `deps` Bump github.com/apache/iotdb-client-go from 1.3.2 to 1.3.3 +- [#16415](https://github.com/influxdata/telegraf/pull/16415) `deps` Bump github.com/aws/aws-sdk-go-v2 from 1.32.8 to 1.33.0 +- [#16394](https://github.com/influxdata/telegraf/pull/16394) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.38.0 to 1.45.3 +- [#16468](https://github.com/influxdata/telegraf/pull/16468) `deps` Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.33.10 to 1.33.12 +- [#16439](https://github.com/influxdata/telegraf/pull/16439) `deps` Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.33.2 to 1.33.10 +- [#16395](https://github.com/influxdata/telegraf/pull/16395) `deps` Bump github.com/eclipse/paho.golang from 0.21.0 to 0.22.0 +- [#16470](https://github.com/influxdata/telegraf/pull/16470) `deps` Bump github.com/go-ldap/ldap/v3 from 3.4.8 to 3.4.10 +- [#16440](https://github.com/influxdata/telegraf/pull/16440) `deps` Bump github.com/google/cel-go from 0.21.0 to 0.23.0 +- [#16445](https://github.com/influxdata/telegraf/pull/16445) `deps` Bump github.com/lxc/incus/v6 from 6.6.0 to 6.9.0 +- [#16466](https://github.com/influxdata/telegraf/pull/16466) `deps` Bump github.com/nats-io/nats-server/v2 from 2.10.17 to 2.10.25 +- [#16453](https://github.com/influxdata/telegraf/pull/16453) `deps` Bump github.com/prometheus/common from 0.61.0 to 0.62.0 +- [#16417](https://github.com/influxdata/telegraf/pull/16417) `deps` Bump github.com/shirou/gopsutil/v4 from 4.24.10 to 4.24.12 +- [#16369](https://github.com/influxdata/telegraf/pull/16369) `deps` Bump github.com/shirou/gopsutil/v4 from v4.24.10 to v4.24.12 +- [#16397](https://github.com/influxdata/telegraf/pull/16397) `deps` Bump github.com/showwin/speedtest-go from 1.7.9 to 1.7.10 +- [#16467](https://github.com/influxdata/telegraf/pull/16467) `deps` Bump github.com/yuin/goldmark from 1.6.0 to 1.7.8 +- [#16360](https://github.com/influxdata/telegraf/pull/16360) `deps` Bump golangci-lint from v1.62.2 to v1.63.4 +- [#16469](https://github.com/influxdata/telegraf/pull/16469) `deps` Bump google.golang.org/api from 0.214.0 to 0.219.0 +- [#16396](https://github.com/influxdata/telegraf/pull/16396) `deps` Bump k8s.io/api from 0.31.3 to 0.32.1 +- [#16482](https://github.com/influxdata/telegraf/pull/16482) `deps` Update Apache arrow from 0.0-20240716144821-cf5d7c7ec3cf to 18.1.0 +- [#16423](https://github.com/influxdata/telegraf/pull/16423) `deps` Update ClickHouse SQL driver from 1.5.4 to to 2.30.1 + +## v1.33.1 [2025-01-10] + +### Important Changes + +- The default value of `skip_processors_after_aggregators` will change to `true` + with Telegraf `v1.40.0`, skip running the processors again after aggregators! + If you need the current default behavior, please explicitly set the option to + `false`! To silence the warning and use the future default behavior, please + explicitly set the option to `true`. + +### Bugfixes + +- [#16290](https://github.com/influxdata/telegraf/pull/16290) `agent` Skip initialization of second processor state if requested +- [#16377](https://github.com/influxdata/telegraf/pull/16377) `inputs.intel_powerstat` Fix option removal version +- [#16310](https://github.com/influxdata/telegraf/pull/16310) `inputs.mongodb` Do not dereference nil pointer if gathering database stats fails +- [#16383](https://github.com/influxdata/telegraf/pull/16383) `outputs.influxdb_v2` Allow overriding auth and agent headers +- [#16388](https://github.com/influxdata/telegraf/pull/16388) `outputs.influxdb_v2` Fix panic and API error handling +- [#16289](https://github.com/influxdata/telegraf/pull/16289) `outputs.remotefile` Handle tracking metrics correctly + +### Dependency Updates + +- [#16344](https://github.com/influxdata/telegraf/pull/16344) `deps` Bump cloud.google.com/go/bigquery from 1.64.0 to 1.65.0 +- [#16283](https://github.com/influxdata/telegraf/pull/16283) `deps` Bump cloud.google.com/go/monitoring from 1.21.1 to 1.22.0 +- [#16315](https://github.com/influxdata/telegraf/pull/16315) `deps` Bump github.com/Azure/go-autorest/autorest/adal from 0.9.23 to 0.9.24 +- [#16319](https://github.com/influxdata/telegraf/pull/16319) `deps` Bump github.com/IBM/nzgo/v12 from 12.0.9-0.20231115043259-49c27f2dfe48 to 12.0.9 +- [#16346](https://github.com/influxdata/telegraf/pull/16346) `deps` Bump github.com/Masterminds/semver/v3 from 3.3.0 to 3.3.1 +- [#16280](https://github.com/influxdata/telegraf/pull/16280) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.27.39 to 1.28.6 +- [#16343](https://github.com/influxdata/telegraf/pull/16343) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.162.1 to 1.198.1 +- [#16317](https://github.com/influxdata/telegraf/pull/16317) `deps` Bump github.com/fatih/color from 1.17.0 to 1.18.0 +- [#16345](https://github.com/influxdata/telegraf/pull/16345) `deps` Bump github.com/gopacket/gopacket from 1.3.0 to 1.3.1 +- [#16282](https://github.com/influxdata/telegraf/pull/16282) `deps` Bump github.com/nats-io/nats.go from 1.36.0 to 1.37.0 +- [#16318](https://github.com/influxdata/telegraf/pull/16318) `deps` Bump github.com/prometheus/common from 0.60.0 to 0.61.0 +- [#16324](https://github.com/influxdata/telegraf/pull/16324) `deps` Bump github.com/vapourismo/knx-go from v0.0.0-20240217175130-922a0d50c241 to v0.0.0-20240915133544-a6ab43471c11 +- [#16297](https://github.com/influxdata/telegraf/pull/16297) `deps` Bump golang.org/x/crypto from 0.29.0 to 0.31.0 +- [#16281](https://github.com/influxdata/telegraf/pull/16281) `deps` Bump k8s.io/client-go from 0.30.1 to 0.31.3 +- [#16313](https://github.com/influxdata/telegraf/pull/16313) `deps` Bump super-linter/super-linter from 7.2.0 to 7.2.1 + +## v1.33.0 [2024-12-09] + +### New Plugins + +- [#15754](https://github.com/influxdata/telegraf/pull/15754) `inputs.neoom_beaam` Add new plugin +- [#15869](https://github.com/influxdata/telegraf/pull/15869) `processors.batch` Add batch processor +- [#16144](https://github.com/influxdata/telegraf/pull/16144) `outputs.quix` Add plugin + +### Features + +- [#16010](https://github.com/influxdata/telegraf/pull/16010) `agent` Add --watch-interval option for polling config changes +- [#15948](https://github.com/influxdata/telegraf/pull/15948) `aggregators.basicstats` Add first field +- [#15891](https://github.com/influxdata/telegraf/pull/15891) `common.socket` Allow parallel parsing with a pool of workers +- [#16141](https://github.com/influxdata/telegraf/pull/16141) `inputs.amqp_consumer` Allow specification of queue arguments +- [#15950](https://github.com/influxdata/telegraf/pull/15950) `inputs.diskio` Add field io await and util +- [#15919](https://github.com/influxdata/telegraf/pull/15919) `inputs.kafka_consumer` Implement startup error behavior options +- [#15910](https://github.com/influxdata/telegraf/pull/15910) `inputs.memcached` Add support for external-store metrics +- [#15990](https://github.com/influxdata/telegraf/pull/15990) `inputs.mock` Add sine phase +- [#16040](https://github.com/influxdata/telegraf/pull/16040) `inputs.modbus` Allow grouping across register types +- [#15865](https://github.com/influxdata/telegraf/pull/15865) `inputs.prometheus` Allow to use secrets for credentials +- [#16230](https://github.com/influxdata/telegraf/pull/16230) `inputs.smart` Add Power on Hours and Cycle Count +- [#15935](https://github.com/influxdata/telegraf/pull/15935) `inputs.snmp` Add displayhint conversion +- [#16027](https://github.com/influxdata/telegraf/pull/16027) `inputs.snmp` Convert uneven bytes to int +- [#15976](https://github.com/influxdata/telegraf/pull/15976) `inputs.socket_listener` Use reception time as timestamp +- [#15853](https://github.com/influxdata/telegraf/pull/15853) `inputs.statsd` Allow reporting sets and timings count as floats +- [#11591](https://github.com/influxdata/telegraf/pull/11591) `inputs.vsphere` Add VM memory configuration +- [#16109](https://github.com/influxdata/telegraf/pull/16109) `inputs.vsphere` Add cpu temperature field +- [#15917](https://github.com/influxdata/telegraf/pull/15917) `inputs` Add option to choose the metric time source +- [#16242](https://github.com/influxdata/telegraf/pull/16242) `logging` Allow overriding message key for structured logging +- [#15742](https://github.com/influxdata/telegraf/pull/15742) `outputs.influxdb_v2` Add rate limit implementation +- [#15943](https://github.com/influxdata/telegraf/pull/15943) `outputs.mqtt` Add sprig functions for topic name generator +- [#16041](https://github.com/influxdata/telegraf/pull/16041) `outputs.postgresql` Allow limiting of column name length +- [#16258](https://github.com/influxdata/telegraf/pull/16258) `outputs` Add rate-limiting infrastructure +- [#16146](https://github.com/influxdata/telegraf/pull/16146) `outputs` Implement partial write errors +- [#15883](https://github.com/influxdata/telegraf/pull/15883) `outputs` Only copy metric if its not filtered out +- [#15893](https://github.com/influxdata/telegraf/pull/15893) `serializers.prometheusremotewrite` Log metric conversion errors + +### Bugfixes + +- [#16248](https://github.com/influxdata/telegraf/pull/16248) `inputs.netflow` Decode flags in TCP and IP headers correctly +- [#16257](https://github.com/influxdata/telegraf/pull/16257) `inputs.procstat` Handle running processes correctly across multiple filters +- [#16219](https://github.com/influxdata/telegraf/pull/16219) `logging` Add Close() func for redirectLogger +- [#16255](https://github.com/influxdata/telegraf/pull/16255) `logging` Clean up extra empty spaces when redirectLogger is used +- [#16274](https://github.com/influxdata/telegraf/pull/16274) `logging` Fix duplicated prefix and attrMsg in log message when redirectLogger is used + +### Dependency Updates + +- [#16232](https://github.com/influxdata/telegraf/pull/16232) `deps` Bump cloud.google.com/go/bigquery from 1.63.1 to 1.64.0 +- [#16235](https://github.com/influxdata/telegraf/pull/16235) `deps` Bump cloud.google.com/go/storage from 1.43.0 to 1.47.0 +- [#16198](https://github.com/influxdata/telegraf/pull/16198) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.42.2 to 1.43.1 +- [#16234](https://github.com/influxdata/telegraf/pull/16234) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.29.3 to 1.32.6 +- [#16201](https://github.com/influxdata/telegraf/pull/16201) `deps` Bump github.com/intel/powertelemetry from 1.0.1 to 1.0.2 +- [#16200](https://github.com/influxdata/telegraf/pull/16200) `deps` Bump github.com/rclone/rclone from 1.68.1 to 1.68.2 +- [#16199](https://github.com/influxdata/telegraf/pull/16199) `deps` Bump github.com/vishvananda/netns from 0.0.4 to 0.0.5 +- [#16236](https://github.com/influxdata/telegraf/pull/16236) `deps` Bump golang.org/x/net from 0.30.0 to 0.31.0 +- [#16250](https://github.com/influxdata/telegraf/pull/16250) `deps` Bump golangci-lint from v1.62.0 to v1.62.2 +- [#16233](https://github.com/influxdata/telegraf/pull/16233) `deps` Bump google.golang.org/grpc from 1.67.1 to 1.68.0 +- [#16202](https://github.com/influxdata/telegraf/pull/16202) `deps` Bump modernc.org/sqlite from 1.33.1 to 1.34.1 +- [#16203](https://github.com/influxdata/telegraf/pull/16203) `deps` Bump super-linter/super-linter from 7.1.0 to 7.2.0 + +## v1.32.3 [2024-11-18] + +### Important Changes + +- PR [#16015](https://github.com/influxdata/telegraf/pull/16015) changes the + internal counters of the Bind plugin to unsigned integers matching the server + implementation. We keep backward compatibility by setting + `report_counters_as_int` to `true` by default to avoid type conflicts on the + output side. However, you should change this setting to `false` as soon as + possible to avoid invalid values and parsing errors with the v3 XML + statistics. + +### Bugfixes + +- [#16123](https://github.com/influxdata/telegraf/pull/16123) `agent` Restore setup order of stateful plugins to Init() then SetState() +- [#16111](https://github.com/influxdata/telegraf/pull/16111) `common.socket` Make sure the scanner buffer matches the read-buffer size +- [#16156](https://github.com/influxdata/telegraf/pull/16156) `common.socket` Use read buffer size config setting as a datagram reader buffer size +- [#16015](https://github.com/influxdata/telegraf/pull/16015) `inputs.bind` Convert counters to uint64 +- [#16171](https://github.com/influxdata/telegraf/pull/16171) `inputs.gnmi` Register connection statistics before creating client +- [#16197](https://github.com/influxdata/telegraf/pull/16197) `inputs.netflow` Cast TCP ports to uint16 +- [#16110](https://github.com/influxdata/telegraf/pull/16110) `inputs.ntpq` Avoid panic on empty lines and make sure -p is present +- [#16155](https://github.com/influxdata/telegraf/pull/16155) `inputs.snmp` Fix crash when trying to format fields from unknown OIDs +- [#16145](https://github.com/influxdata/telegraf/pull/16145) `inputs.snmp_trap` Remove timeout deprecation +- [#16108](https://github.com/influxdata/telegraf/pull/16108) `logger` Avoid setting the log-format default too early + +### Dependency Updates + +- [#16093](https://github.com/influxdata/telegraf/pull/16093) `deps` Bump cloud.google.com/go/pubsub from 1.42.0 to 1.45.1 +- [#16175](https://github.com/influxdata/telegraf/pull/16175) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.37 to 1.17.44 +- [#16096](https://github.com/influxdata/telegraf/pull/16096) `deps` Bump github.com/gofrs/uuid/v5 from 5.2.0 to 5.3.0 +- [#16136](https://github.com/influxdata/telegraf/pull/16136) `deps` Bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1 +- [#16094](https://github.com/influxdata/telegraf/pull/16094) `deps` Bump github.com/gopacket/gopacket from 1.2.0 to 1.3.0 +- [#16133](https://github.com/influxdata/telegraf/pull/16133) `deps` Bump github.com/jackc/pgtype from 1.14.3 to 1.14.4 +- [#16131](https://github.com/influxdata/telegraf/pull/16131) `deps` Bump github.com/openconfig/gnmi from 0.10.0 to 0.11.0 +- [#16092](https://github.com/influxdata/telegraf/pull/16092) `deps` Bump github.com/prometheus/client_golang from 1.20.4 to 1.20.5 +- [#16178](https://github.com/influxdata/telegraf/pull/16178) `deps` Bump github.com/rclone/rclone from 1.67.0 to 1.68.1 +- [#16132](https://github.com/influxdata/telegraf/pull/16132) `deps` Bump github.com/shirou/gopsutil/v4 from 4.24.9 to 4.24.10 +- [#16176](https://github.com/influxdata/telegraf/pull/16176) `deps` Bump github.com/sijms/go-ora/v2 from 2.8.19 to 2.8.22 +- [#16134](https://github.com/influxdata/telegraf/pull/16134) `deps` Bump github.com/testcontainers/testcontainers-go/modules/kafka from 0.33.0 to 0.34.0 +- [#16174](https://github.com/influxdata/telegraf/pull/16174) `deps` Bump github.com/tidwall/gjson from 1.17.1 to 1.18.0 +- [#16135](https://github.com/influxdata/telegraf/pull/16135) `deps` Bump github.com/vmware/govmomi from 0.39.0 to 0.45.1 +- [#16095](https://github.com/influxdata/telegraf/pull/16095) `deps` Bump golang.org/x/sys from 0.25.0 to 0.26.0 +- [#16177](https://github.com/influxdata/telegraf/pull/16177) `deps` Bump golang.org/x/text from 0.19.0 to 0.20.0 +- [#16172](https://github.com/influxdata/telegraf/pull/16172) `deps` Bump golangci-lint from v1.61.0 to v1.62.0 + +## v1.32.2 [2024-10-28] + +### Bugfixes + +- [#15966](https://github.com/influxdata/telegraf/pull/15966) `agent` Use a unique WAL file for plugin instances of the same type +- [#16074](https://github.com/influxdata/telegraf/pull/16074) `inputs.kafka_consumer` Fix deadlock +- [#16009](https://github.com/influxdata/telegraf/pull/16009) `inputs.netflow` Cast complex types to field compatible ones +- [#16026](https://github.com/influxdata/telegraf/pull/16026) `inputs.opcua` Allow to retry reads on invalid sessions +- [#16060](https://github.com/influxdata/telegraf/pull/16060) `inputs.procstat` Correctly use systemd-unit setting for finding them +- [#16008](https://github.com/influxdata/telegraf/pull/16008) `inputs.win_eventlog` Handle XML data fields' filtering the same way as event fields +- [#15968](https://github.com/influxdata/telegraf/pull/15968) `outputs.remotefile` Create a new serializer instance per output file +- [#16014](https://github.com/influxdata/telegraf/pull/16014) `outputs.syslog` Trim field-names belonging to explicit SDIDs correctly + +### Dependency Updates + +- [#15992](https://github.com/influxdata/telegraf/pull/15992) `deps` Bump cloud.google.com/go/bigquery from 1.62.0 to 1.63.1 +- [#16056](https://github.com/influxdata/telegraf/pull/16056) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.14.0 to 1.16.0 +- [#16021](https://github.com/influxdata/telegraf/pull/16021) `deps` Bump github.com/IBM/sarama from 1.43.2 to 1.43.3 +- [#16019](https://github.com/influxdata/telegraf/pull/16019) `deps` Bump github.com/alitto/pond from 1.9.0 to 1.9.2 +- [#16018](https://github.com/influxdata/telegraf/pull/16018) `deps` Bump github.com/apache/thrift from 0.20.0 to 0.21.0 +- [#16054](https://github.com/influxdata/telegraf/pull/16054) `deps` Bump github.com/aws/aws-sdk-go-v2 from 1.32.1 to 1.32.2 +- [#15996](https://github.com/influxdata/telegraf/pull/15996) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.40.4 to 1.42.1 +- [#16055](https://github.com/influxdata/telegraf/pull/16055) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.42.1 to 1.42.2 +- [#16057](https://github.com/influxdata/telegraf/pull/16057) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.34.9 to 1.36.2 +- [#16022](https://github.com/influxdata/telegraf/pull/16022) `deps` Bump github.com/docker/docker from 27.1.1+incompatible to 27.3.1+incompatible +- [#15993](https://github.com/influxdata/telegraf/pull/15993) `deps` Bump github.com/gosnmp/gosnmp from 1.37.0 to 1.38.0 +- [#15947](https://github.com/influxdata/telegraf/pull/15947) `deps` Bump github.com/gwos/tcg/sdk from v8.7.2 to v8.8.0 +- [#16053](https://github.com/influxdata/telegraf/pull/16053) `deps` Bump github.com/lxc/incus/v6 from 6.2.0 to 6.6.0 +- [#15994](https://github.com/influxdata/telegraf/pull/15994) `deps` Bump github.com/signalfx/golib/v3 from 3.3.53 to 3.3.54 +- [#15995](https://github.com/influxdata/telegraf/pull/15995) `deps` Bump github.com/snowflakedb/gosnowflake from 1.11.1 to 1.11.2 +- [#16020](https://github.com/influxdata/telegraf/pull/16020) `deps` Bump go.step.sm/crypto from 0.51.1 to 0.54.0 +- [#16023](https://github.com/influxdata/telegraf/pull/16023) `deps` Bump github.com/shirou/gopsutil from v3.24.4 to v4.24.9 + +## v1.32.1 [2024-10-07] + +### Important Changes + +- PR [#15796](https://github.com/influxdata/telegraf/pull/15796) changes the + delivery state update of un-parseable messages from `ACK` to `NACK` without + requeueing. This way, those messages are not lost and can optionally be + handled using a dead-letter exchange by other means. +- Removal of old-style serializer creation. This should not directly affect + users as it is an API change. All serializers in Telegraf are already ported + to the new framework. If you experience any issues with not being able to + create serializers let us know! + +### Bugfixes + +- [#15969](https://github.com/influxdata/telegraf/pull/15969) `agent` Fix buffer not flushing if all metrics are written +- [#15937](https://github.com/influxdata/telegraf/pull/15937) `config` Correctly print removal version info +- [#15900](https://github.com/influxdata/telegraf/pull/15900) `common.http` Keep timeout after creating oauth client +- [#15796](https://github.com/influxdata/telegraf/pull/15796) `inputs.amqp_consumer` NACKing messages on non-delivery related errors +- [#15923](https://github.com/influxdata/telegraf/pull/15923) `inputs.cisco_telemetry_mdt` Handle NXOS DME subtree telemetry format +- [#15907](https://github.com/influxdata/telegraf/pull/15907) `inputs.consul` Move config checking to Init method +- [#15982](https://github.com/influxdata/telegraf/pull/15982) `inputs.influxdb_v2_listener` Fix concurrent read/write dict +- [#15960](https://github.com/influxdata/telegraf/pull/15960) `inputs.vsphere` Add tags to VSAN ESA disks +- [#15921](https://github.com/influxdata/telegraf/pull/15921) `parsers.avro` Add mutex to cache access +- [#15965](https://github.com/influxdata/telegraf/pull/15965) `processors.aws_ec2` Remove leading slash and cancel worker only if it exists + +### Dependency Updates + +- [#15932](https://github.com/influxdata/telegraf/pull/15932) `deps` Bump cloud.google.com/go/monitoring from 1.20.2 to 1.21.1 +- [#15863](https://github.com/influxdata/telegraf/pull/15863) `deps` Bump github.com/Azure/azure-kusto-go from 0.15.3 to 0.16.1 +- [#15862](https://github.com/influxdata/telegraf/pull/15862) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.13.0 to 1.14.0 +- [#15957](https://github.com/influxdata/telegraf/pull/15957) `deps` Bump github.com/aws/aws-sdk-go-v2/feature/ec2/imds from 1.16.12 to 1.16.14 +- [#15859](https://github.com/influxdata/telegraf/pull/15859) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.34.4 to 1.34.9 +- [#15931](https://github.com/influxdata/telegraf/pull/15931) `deps` Bump github.com/boschrexroth/ctrlx-datalayer-golang from 1.3.0 to 1.3.1 +- [#15890](https://github.com/influxdata/telegraf/pull/15890) `deps` Bump github.com/harlow/kinesis-consumer from v0.3.6-0.20240606153816-553e2392fdf3 to v0.3.6-0.20240916192723-43900507c911 +- [#15904](https://github.com/influxdata/telegraf/pull/15904) `deps` Bump github.com/netsampler/goflow2/v2 from 2.1.5 to 2.2.1 +- [#15903](https://github.com/influxdata/telegraf/pull/15903) `deps` Bump github.com/p4lang/p4runtime from 1.3.0 to 1.4.0 +- [#15905](https://github.com/influxdata/telegraf/pull/15905) `deps` Bump github.com/prometheus/client_golang from 1.20.2 to 1.20.3 +- [#15930](https://github.com/influxdata/telegraf/pull/15930) `deps` Bump github.com/prometheus/client_golang from 1.20.3 to 1.20.4 +- [#15962](https://github.com/influxdata/telegraf/pull/15962) `deps` Bump github.com/prometheus/common from 0.55.0 to 0.60.0 +- [#15860](https://github.com/influxdata/telegraf/pull/15860) `deps` Bump github.com/snowflakedb/gosnowflake from 1.10.0 to 1.11.1 +- [#15954](https://github.com/influxdata/telegraf/pull/15954) `deps` Bump github.com/srebhan/protobufquery from 0.0.0-20230803132024-ae4c0d878e55 to 1.0.1 +- [#15929](https://github.com/influxdata/telegraf/pull/15929) `deps` Bump go.mongodb.org/mongo-driver from 1.16.0 to 1.17.0 +- [#15902](https://github.com/influxdata/telegraf/pull/15902) `deps` Bump golang.org/x/mod from 0.19.0 to 0.21.0 +- [#15955](https://github.com/influxdata/telegraf/pull/15955) `deps` Bump golang.org/x/oauth2 from 0.21.0 to 0.23.0 +- [#15861](https://github.com/influxdata/telegraf/pull/15861) `deps` Bump golang.org/x/term from 0.23.0 to 0.24.0 +- [#15856](https://github.com/influxdata/telegraf/pull/15856) `deps` Bump golangci-lint from v1.60.3 to v1.61.0 +- [#15933](https://github.com/influxdata/telegraf/pull/15933) `deps` Bump k8s.io/apimachinery from 0.30.1 to 0.31.1 +- [#15901](https://github.com/influxdata/telegraf/pull/15901) `deps` Bump modernc.org/sqlite from 1.32.0 to 1.33.1 + +## v1.32.0 [2024-09-09] + +### Important Changes + +- This release contains a logging overhaul as well as some new features for + logging (see PRs [#15556](https://github.com/influxdata/telegraf/pull/15556), + [#15629](https://github.com/influxdata/telegraf/pull/15629), + [#15677](https://github.com/influxdata/telegraf/pull/15677), + [#15695](https://github.com/influxdata/telegraf/pull/15695) and + [#15751](https://github.com/influxdata/telegraf/pull/15751)). + As a consequence the redunant `logtarget` setting is deprecated, `stderr` is + used if no `logfile` is provided, otherwise messages are logged to the given + file. For using the Windows `eventlog` set `logformat = "eventlog"`! +- This release contains a change in json_v2 parser config parsing - + if the config is empty (not define any rules), initialization will fail + (see PR [#15844](https://github.com/influxdata/telegraf/pull/15844)). +- This release contains a feature for a disk-backed metric buffer under the + `buffer_strategy` agent config (see + PR [#15564](https://github.com/influxdata/telegraf/pull/15564)). + Please note, this feature is **experimental**, please give it a test and + report any issues you encounter. + +### New Plugins + +- [#15700](https://github.com/influxdata/telegraf/pull/15700) `inputs.slurm` SLURM workload manager +- [#15602](https://github.com/influxdata/telegraf/pull/15602) `outputs.parquet` Parquet file writer +- [#15569](https://github.com/influxdata/telegraf/pull/15569) `outputs.remotefile` Output to remote location like S3 + +### Features + +- [#15732](https://github.com/influxdata/telegraf/pull/15732) `agent` Add config check sub-command +- [#15564](https://github.com/influxdata/telegraf/pull/15564) `agent` Add metric disk buffer +- [#15645](https://github.com/influxdata/telegraf/pull/15645) `agent` Enable watching for new configuration files +- [#15644](https://github.com/influxdata/telegraf/pull/15644) `agent` Watch for deleted files +- [#15695](https://github.com/influxdata/telegraf/pull/15695) `logging` Add 'trace' log-level +- [#15677](https://github.com/influxdata/telegraf/pull/15677) `logging` Allow to override log-level per plugin +- [#15751](https://github.com/influxdata/telegraf/pull/15751) `logging` Implement structured logging +- [#15640](https://github.com/influxdata/telegraf/pull/15640) `common.cookie` Allow usage of secrets in headers +- [#15636](https://github.com/influxdata/telegraf/pull/15636) `common.shim` Enable metric tracking within external plugins +- [#15570](https://github.com/influxdata/telegraf/pull/15570) `common.tls` Allow group aliases for cipher-suites +- [#15628](https://github.com/influxdata/telegraf/pull/15628) `inputs.amd_rocm_smi` Parse newer ROCm versions +- [#15519](https://github.com/influxdata/telegraf/pull/15519) `inputs.azure_monitor` Add client options parameter +- [#15544](https://github.com/influxdata/telegraf/pull/15544) `inputs.elasticsearch` Add support for custom headers +- [#15688](https://github.com/influxdata/telegraf/pull/15688) `inputs.elasticsearch` Gather enrich stats +- [#15834](https://github.com/influxdata/telegraf/pull/15834) `inputs.execd` Allow to provide logging prefixes on stderr +- [#15764](https://github.com/influxdata/telegraf/pull/15764) `inputs.http_listener_v2` Add unix socket mode +- [#15495](https://github.com/influxdata/telegraf/pull/15495) `inputs.ipmi_sensor` Collect additional commands +- [#15790](https://github.com/influxdata/telegraf/pull/15790) `inputs.kafka_consumer` Allow to select the metric time source +- [#15648](https://github.com/influxdata/telegraf/pull/15648) `inputs.modbus` Allow reading single bits of input and holding registers +- [#15528](https://github.com/influxdata/telegraf/pull/15528) `inputs.mqtt_consumer` Add variable length topic parsing +- [#15486](https://github.com/influxdata/telegraf/pull/15486) `inputs.mqtt_consumer` Implement startup error behaviors +- [#15749](https://github.com/influxdata/telegraf/pull/15749) `inputs.mysql` Add support for replica status +- [#15521](https://github.com/influxdata/telegraf/pull/15521) `inputs.netflow` Add more fields for sFlow extended gateway packets +- [#15396](https://github.com/influxdata/telegraf/pull/15396) `inputs.netflow` Add support for sFlow drop notification packets +- [#15468](https://github.com/influxdata/telegraf/pull/15468) `inputs.openstack` Allow collection without admin privileges +- [#15637](https://github.com/influxdata/telegraf/pull/15637) `inputs.opentelemetry` Add profiles support +- [#15423](https://github.com/influxdata/telegraf/pull/15423) `inputs.procstat` Add ability to collect per-process socket statistics +- [#15655](https://github.com/influxdata/telegraf/pull/15655) `inputs.s7comm` Implement startup-error behavior settings +- [#15600](https://github.com/influxdata/telegraf/pull/15600) `inputs.sql` Add SAP HANA SQL driver +- [#15424](https://github.com/influxdata/telegraf/pull/15424) `inputs.sqlserver` Introduce user specified ID parameter for ADD logins +- [#15687](https://github.com/influxdata/telegraf/pull/15687) `inputs.statsd` Expose allowed_pending_messages as internal stat +- [#15458](https://github.com/influxdata/telegraf/pull/15458) `inputs.systemd_units` Support user scoped units +- [#15702](https://github.com/influxdata/telegraf/pull/15702) `outputs.datadog` Add support for submitting alongside dd-agent +- [#15668](https://github.com/influxdata/telegraf/pull/15668) `outputs.dynatrace` Report metrics as a delta counter using regular expression +- [#15471](https://github.com/influxdata/telegraf/pull/15471) `outputs.elasticsearch` Allow custom template index settings +- [#15613](https://github.com/influxdata/telegraf/pull/15613) `outputs.elasticsearch` Support data streams +- [#15722](https://github.com/influxdata/telegraf/pull/15722) `outputs.kafka` Add option to add metric name as record header +- [#15689](https://github.com/influxdata/telegraf/pull/15689) `outputs.kafka` Add option to set producer message timestamp +- [#15787](https://github.com/influxdata/telegraf/pull/15787) `outputs.syslog` Implement startup error behavior options +- [#15697](https://github.com/influxdata/telegraf/pull/15697) `parsers.value` Add base64 datatype +- [#15795](https://github.com/influxdata/telegraf/pull/15795) `processors.aws_ec2` Allow to use instance metadata + +### Bugfixes + +- [#15661](https://github.com/influxdata/telegraf/pull/15661) `agent` Fix buffer directory config and document +- [#15788](https://github.com/influxdata/telegraf/pull/15788) `inputs.kinesis_consumer` Honor the configured endpoint +- [#15791](https://github.com/influxdata/telegraf/pull/15791) `inputs.mysql` Enforce float for all known floating-point information +- [#15743](https://github.com/influxdata/telegraf/pull/15743) `inputs.snmp` Avoid sending a nil to gosmi's GetEnumBitsFormatted +- [#15815](https://github.com/influxdata/telegraf/pull/15815) `logger` Handle trace level for standard log +- [#15781](https://github.com/influxdata/telegraf/pull/15781) `outputs.kinesis` Honor the configured endpoint +- [#15615](https://github.com/influxdata/telegraf/pull/15615) `outputs.remotefile` Resolve linter not checking error +- [#15740](https://github.com/influxdata/telegraf/pull/15740) `serializers.template` Unwrap metrics if required + +### Dependency Updates + +- [#15829](https://github.com/influxdata/telegraf/pull/15829) `deps` Bump github.com/BurntSushi/toml from 1.3.2 to 1.4.0 +- [#15775](https://github.com/influxdata/telegraf/pull/15775) `deps` Bump github.com/aws/aws-sdk-go-v2/feature/ec2/imds from 1.16.11 to 1.16.12 +- [#15733](https://github.com/influxdata/telegraf/pull/15733) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.38.7 to 1.40.3 +- [#15761](https://github.com/influxdata/telegraf/pull/15761) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.40.3 to 1.40.4 +- [#15827](https://github.com/influxdata/telegraf/pull/15827) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.37.3 to 1.38.0 +- [#15760](https://github.com/influxdata/telegraf/pull/15760) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.25.5 to 1.27.4 +- [#15737](https://github.com/influxdata/telegraf/pull/15737) `deps` Bump github.com/eclipse/paho.mqtt.golang from 1.4.3 to 1.5.0 +- [#15734](https://github.com/influxdata/telegraf/pull/15734) `deps` Bump github.com/google/cel-go from 0.20.1 to 0.21.0 +- [#15777](https://github.com/influxdata/telegraf/pull/15777) `deps` Bump github.com/miekg/dns from 1.1.59 to 1.1.62 +- [#15828](https://github.com/influxdata/telegraf/pull/15828) `deps` Bump github.com/openconfig/goyang from 1.5.0 to 1.6.0 +- [#15735](https://github.com/influxdata/telegraf/pull/15735) `deps` Bump github.com/pion/dtls/v2 from 2.2.11 to 2.2.12 +- [#15779](https://github.com/influxdata/telegraf/pull/15779) `deps` Bump github.com/prometheus/client_golang from 1.19.1 to 1.20.2 +- [#15831](https://github.com/influxdata/telegraf/pull/15831) `deps` Bump github.com/prometheus/prometheus from 0.53.1 to 0.54.1 +- [#15736](https://github.com/influxdata/telegraf/pull/15736) `deps` Bump github.com/redis/go-redis/v9 from 9.5.1 to 9.6.1 +- [#15830](https://github.com/influxdata/telegraf/pull/15830) `deps` Bump github.com/seancfoley/ipaddress-go from 1.6.0 to 1.7.0 +- [#15842](https://github.com/influxdata/telegraf/pull/15842) `deps` Bump github.com/showwin/speedtest-go from 1.7.7 to 1.7.9 +- [#15778](https://github.com/influxdata/telegraf/pull/15778) `deps` Bump go.step.sm/crypto from 0.50.0 to 0.51.1 +- [#15776](https://github.com/influxdata/telegraf/pull/15776) `deps` Bump golang.org/x/net from 0.27.0 to 0.28.0 +- [#15757](https://github.com/influxdata/telegraf/pull/15757) `deps` Bump golang.org/x/sync from 0.7.0 to 0.8.0 +- [#15759](https://github.com/influxdata/telegraf/pull/15759) `deps` Bump gonum.org/v1/gonum from 0.15.0 to 0.15.1 +- [#15758](https://github.com/influxdata/telegraf/pull/15758) `deps` Bump modernc.org/sqlite from 1.30.0 to 1.32.0 +- [#15756](https://github.com/influxdata/telegraf/pull/15756) `deps` Bump super-linter/super-linter from 6.8.0 to 7.0.0 +- [#15826](https://github.com/influxdata/telegraf/pull/15826) `deps` Bump super-linter/super-linter from 7.0.0 to 7.1.0 +- [#15780](https://github.com/influxdata/telegraf/pull/15780) `deps` Bump tj-actions/changed-files from 44 to 45 + +## v1.31.3 [2024-08-12] + +### Bugfixes + +- [#15552](https://github.com/influxdata/telegraf/pull/15552) `inputs.chrony` Use DGRAM for the unix socket +- [#15667](https://github.com/influxdata/telegraf/pull/15667) `inputs.diskio` Print warnings once, add details to messages +- [#15670](https://github.com/influxdata/telegraf/pull/15670) `inputs.mqtt_consumer` Restore trace logging option +- [#15696](https://github.com/influxdata/telegraf/pull/15696) `inputs.opcua` Reconnect if closed connection +- [#15724](https://github.com/influxdata/telegraf/pull/15724) `inputs.smartctl` Use --scan-open instead of --scan to provide correct device type info +- [#15649](https://github.com/influxdata/telegraf/pull/15649) `inputs.tail` Prevent deadlock when closing and max undelivered lines hit + +### Dependency Updates + +- [#15720](https://github.com/influxdata/telegraf/pull/15720) `deps` Bump Go from v1.22.5 to v1.22.6 +- [#15683](https://github.com/influxdata/telegraf/pull/15683) `deps` Bump cloud.google.com/go/bigquery from 1.61.0 to 1.62.0 +- [#15654](https://github.com/influxdata/telegraf/pull/15654) `deps` Bump cloud.google.com/go/monitoring from 1.19.0 to 1.20.2 +- [#15679](https://github.com/influxdata/telegraf/pull/15679) `deps` Bump cloud.google.com/go/monitoring from 1.20.2 to 1.20.3 +- [#15626](https://github.com/influxdata/telegraf/pull/15626) `deps` Bump github.com/antchfx/xmlquery from 1.4.0 to 1.4.1 +- [#15706](https://github.com/influxdata/telegraf/pull/15706) `deps` Bump github.com/apache/iotdb-client-go from 1.2.0-tsbs to 1.3.2 +- [#15651](https://github.com/influxdata/telegraf/pull/15651) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.17 to 1.17.27 +- [#15703](https://github.com/influxdata/telegraf/pull/15703) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from v1.27.4 to v1.29.3 +- [#15681](https://github.com/influxdata/telegraf/pull/15681) `deps` Bump github.com/docker/docker from 25.0.5-incompatible to 27.1.1-incompatible +- [#15650](https://github.com/influxdata/telegraf/pull/15650) `deps` Bump github.com/gofrs/uuid/v5 from 5.0.0 to 5.2.0 +- [#15705](https://github.com/influxdata/telegraf/pull/15705) `deps` Bump github.com/gorilla/websocket from 1.5.1 to 1.5.3 +- [#15708](https://github.com/influxdata/telegraf/pull/15708) `deps` Bump github.com/multiplay/go-ts3 from 1.1.0 to 1.2.0 +- [#15707](https://github.com/influxdata/telegraf/pull/15707) `deps` Bump github.com/prometheus-community/pro-bing from 0.4.0 to 0.4.1 +- [#15709](https://github.com/influxdata/telegraf/pull/15709) `deps` Bump github.com/prometheus/prometheus from 0.48.1 to 0.53.1 +- [#15680](https://github.com/influxdata/telegraf/pull/15680) `deps` Bump github.com/vmware/govmomi from 0.37.2 to 0.39.0 +- [#15682](https://github.com/influxdata/telegraf/pull/15682) `deps` Bump go.mongodb.org/mongo-driver from 1.14.0 to 1.16.0 +- [#15652](https://github.com/influxdata/telegraf/pull/15652) `deps` Bump go.step.sm/crypto from 0.47.1 to 0.50.0 +- [#15653](https://github.com/influxdata/telegraf/pull/15653) `deps` Bump google.golang.org/grpc from 1.64.1 to 1.65.0 +- [#15704](https://github.com/influxdata/telegraf/pull/15704) `deps` Bump super-linter/super-linter from 6.7.0 to 6.8.0 + +## v1.31.2 [2024-07-22] + +### Bugfixes + +- [#15589](https://github.com/influxdata/telegraf/pull/15589) `common.socket` Switch to context to simplify closing +- [#15601](https://github.com/influxdata/telegraf/pull/15601) `inputs.ping` Check addr length to avoid crash +- [#15618](https://github.com/influxdata/telegraf/pull/15618) `inputs.snmp` Translate field correctly when not in table +- [#15586](https://github.com/influxdata/telegraf/pull/15586) `parsers.xpath` Allow resolving extensions +- [#15630](https://github.com/influxdata/telegraf/pull/15630) `tools.custom_builder` Handle multiple instances of the same plugin correctly + +### Dependency Updates + +- [#15582](https://github.com/influxdata/telegraf/pull/15582) `deps` Bump cloud.google.com/go/storage from 1.41.0 to 1.42.0 +- [#15623](https://github.com/influxdata/telegraf/pull/15623) `deps` Bump cloud.google.com/go/storage from 1.42.0 to 1.43.0 +- [#15607](https://github.com/influxdata/telegraf/pull/15607) `deps` Bump github.com/alitto/pond from 1.8.3 to 1.9.0 +- [#15625](https://github.com/influxdata/telegraf/pull/15625) `deps` Bump github.com/antchfx/xpath from 1.3.0 to 1.3.1 +- [#15622](https://github.com/influxdata/telegraf/pull/15622) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.34.3 to 1.37.3 +- [#15606](https://github.com/influxdata/telegraf/pull/15606) `deps` Bump github.com/hashicorp/consul/api from 1.26.1 to 1.29.1 +- [#15604](https://github.com/influxdata/telegraf/pull/15604) `deps` Bump github.com/jackc/pgx/v4 from 4.18.2 to 4.18.3 +- [#15581](https://github.com/influxdata/telegraf/pull/15581) `deps` Bump github.com/nats-io/nats-server/v2 from 2.10.16 to 2.10.17 +- [#15603](https://github.com/influxdata/telegraf/pull/15603) `deps` Bump github.com/openconfig/goyang from 1.0.0 to 1.5.0 +- [#15624](https://github.com/influxdata/telegraf/pull/15624) `deps` Bump github.com/sijms/go-ora/v2 from 2.8.4 to 2.8.19 +- [#15585](https://github.com/influxdata/telegraf/pull/15585) `deps` Bump github.com/testcontainers/testcontainers-go/modules/kafka from 0.30.0 to 0.31.0 +- [#15605](https://github.com/influxdata/telegraf/pull/15605) `deps` Bump github.com/tinylib/msgp from 1.1.9 to 1.2.0 +- [#15584](https://github.com/influxdata/telegraf/pull/15584) `deps` Bump github.com/urfave/cli/v2 from 2.27.1 to 2.27.2 +- [#15614](https://github.com/influxdata/telegraf/pull/15614) `deps` Bump google.golang.org/grpc from 1.64.0 to 1.64.1 +- [#15608](https://github.com/influxdata/telegraf/pull/15608) `deps` Bump super-linter/super-linter from 6.6.0 to 6.7.0 + +For versions earlier than v1.13 and earlier see +[CHANGELOG-1.13.md](CHANGELOG-1.13.md). + +## v1.31.1 [2024-07-01] + +### Bugfixes + +- [#15488](https://github.com/influxdata/telegraf/pull/15488) `agent` Ignore startup-errors in test mode +- [#15568](https://github.com/influxdata/telegraf/pull/15568) `inputs.chrony` Handle ServerStats4 response +- [#15551](https://github.com/influxdata/telegraf/pull/15551) `inputs.chrony` Support local (reference) sources +- [#15565](https://github.com/influxdata/telegraf/pull/15565) `inputs.gnmi` Handle YANG namespaces in paths correctly +- [#15496](https://github.com/influxdata/telegraf/pull/15496) `inputs.http_response` Fix for IPv4 and IPv6 addresses when interface is set +- [#15493](https://github.com/influxdata/telegraf/pull/15493) `inputs.mysql` Handle custom TLS configs correctly +- [#15514](https://github.com/influxdata/telegraf/pull/15514) `logging` Add back constants for backward compatibility +- [#15531](https://github.com/influxdata/telegraf/pull/15531) `secretstores.oauth2` Ensure endpoint params is not nil + +### Dependency Updates + +- [#15483](https://github.com/influxdata/telegraf/pull/15483) `deps` Bump cloud.google.com/go/monitoring from 1.18.1 to 1.19.0 +- [#15559](https://github.com/influxdata/telegraf/pull/15559) `deps` Bump github.com/Azure/azure-kusto-go from 0.15.2 to 0.15.3 +- [#15489](https://github.com/influxdata/telegraf/pull/15489) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.5.1 to 1.6.0 +- [#15560](https://github.com/influxdata/telegraf/pull/15560) `deps` Bump github.com/Azure/go-autorest/autorest/azure/auth from 0.5.12 to 0.5.13 +- [#15480](https://github.com/influxdata/telegraf/pull/15480) `deps` Bump github.com/IBM/sarama from 1.43.1 to 1.43.2 +- [#15526](https://github.com/influxdata/telegraf/pull/15526) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.37.0 to 1.38.7 +- [#15527](https://github.com/influxdata/telegraf/pull/15527) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.30.2 to 1.32.9 +- [#15558](https://github.com/influxdata/telegraf/pull/15558) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.32.9 to 1.33.2 +- [#15448](https://github.com/influxdata/telegraf/pull/15448) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.161.1 to 1.162.1 +- [#15557](https://github.com/influxdata/telegraf/pull/15557) `deps` Bump github.com/go-ldap/ldap/v3 from 3.4.6 to 3.4.8 +- [#15523](https://github.com/influxdata/telegraf/pull/15523) `deps` Bump github.com/linkedin/goavro/v2 from 2.12.0 to 2.13.0 +- [#15484](https://github.com/influxdata/telegraf/pull/15484) `deps` Bump github.com/microsoft/go-mssqldb from 1.7.0 to 1.7.2 +- [#15561](https://github.com/influxdata/telegraf/pull/15561) `deps` Bump github.com/nats-io/nats-server/v2 from 2.10.14 to 2.10.16 +- [#15524](https://github.com/influxdata/telegraf/pull/15524) `deps` Bump github.com/prometheus/common from 0.53.0 to 0.54.0 +- [#15481](https://github.com/influxdata/telegraf/pull/15481) `deps` Bump github.com/prometheus/procfs from 0.15.0 to 0.15.1 +- [#15482](https://github.com/influxdata/telegraf/pull/15482) `deps` Bump github.com/rabbitmq/amqp091-go from 1.9.0 to 1.10.0 +- [#15525](https://github.com/influxdata/telegraf/pull/15525) `deps` Bump go.step.sm/crypto from 0.44.1 to 0.47.1 +- [#15479](https://github.com/influxdata/telegraf/pull/15479) `deps` Bump super-linter/super-linter from 6.5.1 to 6.6.0 + +## v1.31.0 [2024-06-10] + +### Important Changes + +- [PR #15186](https://github.com/influxdata/telegraf/pull/15186) changes the + meaning of `inputs.procstat` fields `read_bytes` and `write_bytes` on Linux + to now contain _all_ I/O operations for consistency with other + operating-systems. The previous values are output as `disk_read_bytes` and + `disk_write_bytes` measuring _only_ the I/O on the storage layer. + +### New Plugins + +- [#15066](https://github.com/influxdata/telegraf/pull/15066) `inputs.smartctl` smartctl +- [#15298](https://github.com/influxdata/telegraf/pull/15298) `parsers.openmetrics` OpenMetrics +- [#15008](https://github.com/influxdata/telegraf/pull/15008) `parsers.parquet` Apache Parquet +- [#15094](https://github.com/influxdata/telegraf/pull/15094) `processors.timestamp` Timestamp + +### Features + +- [#15433](https://github.com/influxdata/telegraf/pull/15433) `agent` Add uint support in cli test output +- [#15377](https://github.com/influxdata/telegraf/pull/15377) `agent` Introduce CLI option to set config URL retry attempts +- [#15388](https://github.com/influxdata/telegraf/pull/15388) `agent` Introduce CLI option to reload remote URL configs on change +- [#15030](https://github.com/influxdata/telegraf/pull/15030) `aggregators.basicstats` Add last field +- [#15268](https://github.com/influxdata/telegraf/pull/15268) `aggregators.final` Add option to disable appending _final +- [#15319](https://github.com/influxdata/telegraf/pull/15319) `aggregators.merge` Allow to round metric timestamps +- [#15426](https://github.com/influxdata/telegraf/pull/15426) `cli` List available parsers and serializers +- [#15341](https://github.com/influxdata/telegraf/pull/15341) `common.opcua` Add session timeout as configuration option +- [#15395](https://github.com/influxdata/telegraf/pull/15395) `input.azure_monitor` Use default Azure credentials chain when no secret provided +- [#15233](https://github.com/influxdata/telegraf/pull/15233) `inputs.ceph` Use perf schema to determine metric type +- [#14992](https://github.com/influxdata/telegraf/pull/14992) `inputs.dns_query` Allow ignoring errors of specific types +- [#15400](https://github.com/influxdata/telegraf/pull/15400) `inputs.exec` Add option to ignore return code +- [#15271](https://github.com/influxdata/telegraf/pull/15271) `inputs.execd` Add option to not restart program on error +- [#15330](https://github.com/influxdata/telegraf/pull/15330) `inputs.file` Add tag with absolute path of file +- [#15171](https://github.com/influxdata/telegraf/pull/15171) `inputs.gnmi` Add keepalive settings +- [#15278](https://github.com/influxdata/telegraf/pull/15278) `inputs.gnmi` Add option to create more descriptive tags +- [#15173](https://github.com/influxdata/telegraf/pull/15173) `inputs.gnmi` Add secret store support for username and password +- [#15201](https://github.com/influxdata/telegraf/pull/15201) `inputs.gnmi` Add yang-model decoding of JSON IETF payloads +- [#15256](https://github.com/influxdata/telegraf/pull/15256) `inputs.gnmi` Allow to pass accepted cipher suites +- [#15454](https://github.com/influxdata/telegraf/pull/15454) `inputs.http_listener` Allow setting custom success return code +- [#15110](https://github.com/influxdata/telegraf/pull/15110) `inputs.http_response` Add cookie authentication +- [#15438](https://github.com/influxdata/telegraf/pull/15438) `inputs.influxdb` Add metrics for build, crypto and commandline +- [#15361](https://github.com/influxdata/telegraf/pull/15361) `inputs.influxdb_v2_listener` Add support for rate limiting +- [#15407](https://github.com/influxdata/telegraf/pull/15407) `inputs.influxdb_v2_listener` Support secret store for token +- [#15329](https://github.com/influxdata/telegraf/pull/15329) `inputs.internet_speed` Introduce packet loss field +- [#15368](https://github.com/influxdata/telegraf/pull/15368) `inputs.kafka_consumer` Add resolve canonical bootstrap server option +- [#15169](https://github.com/influxdata/telegraf/pull/15169) `inputs.knx_listener` Add support for string data type +- [#15069](https://github.com/influxdata/telegraf/pull/15069) `inputs.knx_listener` Allow usage of DPT string representation +- [#15049](https://github.com/influxdata/telegraf/pull/15049) `inputs.kubernetes` Add option to node metric name +- [#15044](https://github.com/influxdata/telegraf/pull/15044) `inputs.lustre2` Add eviction_count field +- [#15042](https://github.com/influxdata/telegraf/pull/15042) `inputs.lustre2` Add health-check metric +- [#14813](https://github.com/influxdata/telegraf/pull/14813) `inputs.lustre2` Add support for bulk read/write stats +- [#15045](https://github.com/influxdata/telegraf/pull/15045) `inputs.lustre2` Skip brw_stats in case of insufficient permissions +- [#15270](https://github.com/influxdata/telegraf/pull/15270) `inputs.mock` Add baseline option to sine +- [#15314](https://github.com/influxdata/telegraf/pull/15314) `inputs.netflow` Add support for IPFIX option packets +- [#15180](https://github.com/influxdata/telegraf/pull/15180) `inputs.netflow` Add support for netflow v9 option packets +- [#15282](https://github.com/influxdata/telegraf/pull/15282) `inputs.nvidia_smi` Add power-limit field for v12 scheme +- [#15460](https://github.com/influxdata/telegraf/pull/15460) `inputs.openstack` Use service catalog from v3 authentication if available +- [#15231](https://github.com/influxdata/telegraf/pull/15231) `inputs.opentelemetry` Add option to set max receive message size +- [#15299](https://github.com/influxdata/telegraf/pull/15299) `inputs.procstat` Add option to select properties to collect +- [#14948](https://github.com/influxdata/telegraf/pull/14948) `inputs.procstat` Allow multiple selection criteria +- [#15186](https://github.com/influxdata/telegraf/pull/15186) `inputs.procstat` Report consistent I/O on Linux +- [#14981](https://github.com/influxdata/telegraf/pull/14981) `inputs.radius` Provide setting to set request IP address +- [#15293](https://github.com/influxdata/telegraf/pull/15293) `inputs.redis` Add latency percentiles metric +- [#15000](https://github.com/influxdata/telegraf/pull/15000) `inputs.s7comm` Add optional connection type setting +- [#15439](https://github.com/influxdata/telegraf/pull/15439) `inputs.snmp` Convert octet string with invalid data to hex +- [#15137](https://github.com/influxdata/telegraf/pull/15137) `inputs.sqlserver` Add persistent version store metrics +- [#15380](https://github.com/influxdata/telegraf/pull/15380) `inputs.statsd` Add support for DogStatsD v1.2 +- [#15371](https://github.com/influxdata/telegraf/pull/15371) `inputs.statsd` Allow counters to report as float +- [#15306](https://github.com/influxdata/telegraf/pull/15306) `inputs.win_eventlog` Add option to define event batch-size +- [#14973](https://github.com/influxdata/telegraf/pull/14973) `inputs.win_wmi` Add support for remote queries +- [#15300](https://github.com/influxdata/telegraf/pull/15300) `inputs.win_wmi` Allow to invoke methods +- [#15145](https://github.com/influxdata/telegraf/pull/15145) `inputs` Add framework to retry on startup errors +- [#15065](https://github.com/influxdata/telegraf/pull/15065) `outputs.cratedb` Allow configuration of startup error handling +- [#15477](https://github.com/influxdata/telegraf/pull/15477) `outputs.elasticsearch` Allow settings extra headers for elasticsearch output +- [#15225](https://github.com/influxdata/telegraf/pull/15225) `outputs.influxdb` Add option to define local address +- [#15228](https://github.com/influxdata/telegraf/pull/15228) `outputs.influxdb_v2` Add option to set local address +- [#15475](https://github.com/influxdata/telegraf/pull/15475) `outputs.influxdb_v2` Preserve custom query parameters on write +- [#15429](https://github.com/influxdata/telegraf/pull/15429) `outputs.mqtt` Add client trace logging, resolve MQTT5 reconnect login +- [#15041](https://github.com/influxdata/telegraf/pull/15041) `outputs.postgresql` Add secret store support +- [#15073](https://github.com/influxdata/telegraf/pull/15073) `outputs.postgresql` Allow configuration of startup error handling +- [#14884](https://github.com/influxdata/telegraf/pull/14884) `outputs` Add framework to retry on startup errors +- [#14952](https://github.com/influxdata/telegraf/pull/14952) `parser.prometheusremotewrite` Parse and generate histogram buckets +- [#14961](https://github.com/influxdata/telegraf/pull/14961) `parsers.binary` Allow base64-encoded input data +- [#15328](https://github.com/influxdata/telegraf/pull/15328) `processors.parser` Add base64 decode for fields +- [#15434](https://github.com/influxdata/telegraf/pull/15434) `processors.printer` Embed Influx serializer options +- [#15170](https://github.com/influxdata/telegraf/pull/15170) `processors.starlark` Allow persistence of global state +- [#15220](https://github.com/influxdata/telegraf/pull/15220) `serializers.influx` Add option to omit timestamp +- [#14975](https://github.com/influxdata/telegraf/pull/14975) `snmp` Add secret support for auth_password and priv_password + +### Bugfixes + +- [#15402](https://github.com/influxdata/telegraf/pull/15402) `agent` Warn on multiple agent configuration tables seen +- [#15440](https://github.com/influxdata/telegraf/pull/15440) `inputs.cloudwatch` Add accounts when enabled +- [#15428](https://github.com/influxdata/telegraf/pull/15428) `inputs.cloudwatch` Ensure account list is larger than index +- [#15456](https://github.com/influxdata/telegraf/pull/15456) `inputs.ecs` Check for nil pointer before use +- [#15401](https://github.com/influxdata/telegraf/pull/15401) `inputs.postgresql_extensible` Use same timestamp for each gather +- [#15260](https://github.com/influxdata/telegraf/pull/15260) `inputs.procstat` Do not report dead processes as running for orphan PID files +- [#15332](https://github.com/influxdata/telegraf/pull/15332) `inputs.smartctl` Add additional fields +- [#15466](https://github.com/influxdata/telegraf/pull/15466) `processors.snmp_lookup` Return empty tag-map on error to avoid panic + +### Dependency Updates + +- [#15385](https://github.com/influxdata/telegraf/pull/15385) `deps` Bump cloud.google.com/go/storage from 1.40.0 to 1.41.0 +- [#15446](https://github.com/influxdata/telegraf/pull/15446) `deps` Bump github.com/awnumar/memguard from 0.22.4 to 0.22.5 +- [#15413](https://github.com/influxdata/telegraf/pull/15413) `deps` Bump github.com/fatih/color from 1.16.0 to 1.17.0 +- [#15410](https://github.com/influxdata/telegraf/pull/15410) `deps` Bump github.com/jhump/protoreflect from 1.15.6 to 1.16.0 +- [#15441](https://github.com/influxdata/telegraf/pull/15441) `deps` Bump github.com/lxc/incus v0.4.0 to v6.2.0 +- [#15381](https://github.com/influxdata/telegraf/pull/15381) `deps` Bump github.com/miekg/dns from 1.1.58 to 1.1.59 +- [#15444](https://github.com/influxdata/telegraf/pull/15444) `deps` Bump github.com/openzipkin/zipkin-go from 0.4.2 to 0.4.3 +- [#15412](https://github.com/influxdata/telegraf/pull/15412) `deps` Bump github.com/prometheus/common from 0.52.2 to 0.53.0 +- [#15362](https://github.com/influxdata/telegraf/pull/15362) `deps` Bump github.com/showwin/speedtest-go from 1.7.5 to 1.7.6 +- [#15382](https://github.com/influxdata/telegraf/pull/15382) `deps` Bump github.com/showwin/speedtest-go from 1.7.6 to 1.7.7 +- [#15384](https://github.com/influxdata/telegraf/pull/15384) `deps` Bump github.com/snowflakedb/gosnowflake from 1.7.2 to 1.10.0 +- [#15470](https://github.com/influxdata/telegraf/pull/15470) `deps` Bump go from v1.22.3 to v1.22.4 +- [#15411](https://github.com/influxdata/telegraf/pull/15411) `deps` Bump golang.org/x/crypto from 0.22.0 to 0.23.0 +- [#15447](https://github.com/influxdata/telegraf/pull/15447) `deps` Bump golang.org/x/net from 0.24.0 to 0.25.0 +- [#15383](https://github.com/influxdata/telegraf/pull/15383) `deps` Bump k8s.io/* from 0.29.3 to 0.30.1 +- [#15445](https://github.com/influxdata/telegraf/pull/15445) `deps` Bump modernc.org/sqlite from 1.29.10 to 1.30.0 +- [#15409](https://github.com/influxdata/telegraf/pull/15409) `deps` Bump modernc.org/sqlite from 1.29.5 to 1.29.10 +- [#15386](https://github.com/influxdata/telegraf/pull/15386) `deps` Bump super-linter/super-linter from 6.4.1 to 6.5.0 +- [#15408](https://github.com/influxdata/telegraf/pull/15408) `deps` Bump super-linter/super-linter from 6.5.0 to 6.5.1 +- [#15393](https://github.com/influxdata/telegraf/pull/15393) `deps` Switch to github.com/leodido/go-syslog +- [#15403](https://github.com/influxdata/telegraf/pull/15403) `deps` Update OpenTelemetry dependencies + +## v1.30.3 [2024-05-20] + +### Bugfixes + +- [#15213](https://github.com/influxdata/telegraf/pull/15213) `http` Stop plugins from leaking file descriptors on telegraf reload +- [#15312](https://github.com/influxdata/telegraf/pull/15312) `input.redis` Discard invalid errorstat lines +- [#15317](https://github.com/influxdata/telegraf/pull/15317) `inputs.cloudwatch` Option to produce dense metrics +- [#15259](https://github.com/influxdata/telegraf/pull/15259) `inputs.gnmi` Ensure path contains elements to avoid panic +- [#15239](https://github.com/influxdata/telegraf/pull/15239) `inputs.http_listener_v2` Wrap timestamp parsing error messages +- [#15323](https://github.com/influxdata/telegraf/pull/15323) `inputs.netflow` Log unknown fields only once +- [#15212](https://github.com/influxdata/telegraf/pull/15212) `inputs.sysstat` Prevent default sadc_interval from increasing on reload +- [#15223](https://github.com/influxdata/telegraf/pull/15223) `makefile` Use go's dependency checker for per platform builds +- [#15224](https://github.com/influxdata/telegraf/pull/15224) `outputs.graphite` Handle local address without port correctly +- [#15277](https://github.com/influxdata/telegraf/pull/15277) `outputs.loki` Option to sanitize label names +- [#15346](https://github.com/influxdata/telegraf/pull/15346) `windows` Make sure to log the final error message on exit + +### Dependency Updates + +- [#15262](https://github.com/influxdata/telegraf/pull/15262) `deps` Bump cloud.google.com/go/bigquery from 1.59.1 to 1.61.0 +- [#15308](https://github.com/influxdata/telegraf/pull/15308) `deps` Bump github.com/Azure/azure-kusto-go from 0.15.0 to 0.15.2 +- [#15203](https://github.com/influxdata/telegraf/pull/15203) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go from 1.62.713 to 1.62.721 +- [#15349](https://github.com/influxdata/telegraf/pull/15349) `deps` Bump github.com/antchfx/xmlquery from 1.3.18 to 1.4.0 +- [#15263](https://github.com/influxdata/telegraf/pull/15263) `deps` Bump github.com/antchfx/xpath from 1.2.5 to 1.3.0 +- [#15348](https://github.com/influxdata/telegraf/pull/15348) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.27.9 to 1.27.13 +- [#15202](https://github.com/influxdata/telegraf/pull/15202) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.9 to 1.17.11 +- [#15350](https://github.com/influxdata/telegraf/pull/15350) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.151.1 to 1.161.1 +- [#15307](https://github.com/influxdata/telegraf/pull/15307) `deps` Bump github.com/coocood/freecache from 1.2.3 to 1.2.4 +- [#15205](https://github.com/influxdata/telegraf/pull/15205) `deps` Bump github.com/google/cel-go from 0.18.1 to 0.20.1 +- [#15276](https://github.com/influxdata/telegraf/pull/15276) `deps` Bump github.com/grid-x/modbus from v0.0.0-20211113184042-7f2251c342c9 to v0.0.0-20240503115206-582f2ab60a18 +- [#15347](https://github.com/influxdata/telegraf/pull/15347) `deps` Bump github.com/nats-io/nats-server/v2 from 2.10.9 to 2.10.14 +- [#15310](https://github.com/influxdata/telegraf/pull/15310) `deps` Bump github.com/pion/dtls/v2 from 2.2.10 to 2.2.11 +- [#15265](https://github.com/influxdata/telegraf/pull/15265) `deps` Bump github.com/prometheus/procfs from 0.13.0 to 0.14.0 +- [#15272](https://github.com/influxdata/telegraf/pull/15272) `deps` Bump github.com/shirou/gopsutil/v3 from v3.24.3 to v3.24.4 +- [#15264](https://github.com/influxdata/telegraf/pull/15264) `deps` Bump github.com/testcontainers/testcontainers-go/modules/kafka from 0.26.1-0.20231116140448-68d5f8983d09 to 0.30.0 +- [#15351](https://github.com/influxdata/telegraf/pull/15351) `deps` Bump github.com/vmware/govmomi from 0.37.0 to 0.37.2 +- [#15327](https://github.com/influxdata/telegraf/pull/15327) `deps` Bump go from v1.22.2 to v1.22.3 +- [#15206](https://github.com/influxdata/telegraf/pull/15206) `deps` Bump golang.org/x/mod from 0.16.0 to 0.17.0 +- [#15266](https://github.com/influxdata/telegraf/pull/15266) `deps` Bump golang.org/x/sync from 0.6.0 to 0.7.0 +- [#15303](https://github.com/influxdata/telegraf/pull/15303) `deps` Bump golangci-lint from v1.57.2 to v1.58.0 +- [#15309](https://github.com/influxdata/telegraf/pull/15309) `deps` Bump google.golang.org/api from 0.171.0 to 0.177.0 +- [#15207](https://github.com/influxdata/telegraf/pull/15207) `deps` Bump super-linter/super-linter from 6.3.1 to 6.4.1 +- [#15316](https://github.com/influxdata/telegraf/pull/15316) `deps` Migrate to maintained gopacket library + +## v1.30.2 [2024-04-22] + +### Important Changes + +- [PR #15108](https://github.com/influxdata/telegraf/pull/15108) reverts the + behavior of `inputs.systemd_units` back to pre-v1.30.0 to only collect units + already loaded by systemd, i.e. not collecting disabled or static units. This + was necessary because using unspecific filters will cause significant load on + the system as systemd needs to read all unit-files matching the pattern in + each gather cycle. If you use specific patterns and want to collect non-loaded + units, please set the `collect_disabled_units` option to `true`. + +### Bugfixes + +- [#15054](https://github.com/influxdata/telegraf/pull/15054) `agent` Ensure import of required package for pprof support +- [#15155](https://github.com/influxdata/telegraf/pull/15155) `inputs.diskio` Update path from /sys/block to /sys/class/block +- [#15146](https://github.com/influxdata/telegraf/pull/15146) `inputs.modbus` Avoid overflow when calculating with uint16 addresses +- [#15144](https://github.com/influxdata/telegraf/pull/15144) `inputs.nvidia` Include power limit field for v11 +- [#15178](https://github.com/influxdata/telegraf/pull/15178) `inputs.opcua` Make sure to always create a request +- [#15176](https://github.com/influxdata/telegraf/pull/15176) `inputs.phpfpm` Check for error before continue processing +- [#15195](https://github.com/influxdata/telegraf/pull/15195) `inputs.prometheus` Correctly handle host header +- [#15078](https://github.com/influxdata/telegraf/pull/15078) `inputs.prometheus` Remove duplicate response_timeout option +- [#15154](https://github.com/influxdata/telegraf/pull/15154) `inputs.sqlserver` Honor timezone on backup metrics +- [#15129](https://github.com/influxdata/telegraf/pull/15129) `inputs.systemd_units` Reconnect if connection is lost +- [#15108](https://github.com/influxdata/telegraf/pull/15108) `inputs.systemd_units` Revert to only gather loaded units by default +- [#15132](https://github.com/influxdata/telegraf/pull/15132) `inputs.win_eventlog` Handle empty query correctly +- [#15157](https://github.com/influxdata/telegraf/pull/15157) `outputs.opensearch` Correctly error during failures or disconnect +- [#15196](https://github.com/influxdata/telegraf/pull/15196) `outputs.sql` Enable the use of krb5 with mssql driver +- [#15168](https://github.com/influxdata/telegraf/pull/15168) `systemd` Remove 5 second timeout, use default (90 seconds) + +### Dependency Updates + +- [#15087](https://github.com/influxdata/telegraf/pull/15087) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go from 1.62.563 to 1.62.708 +- [#15163](https://github.com/influxdata/telegraf/pull/15163) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go from 1.62.708 to 1.62.713 +- [#15086](https://github.com/influxdata/telegraf/pull/15086) `deps` Bump github.com/apache/iotdb-client-go from 0.12.2-0.20220722111104-cd17da295b46 to 1.2.0-tsbs +- [#15125](https://github.com/influxdata/telegraf/pull/15125) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.36.1 to 1.37.0 +- [#15164](https://github.com/influxdata/telegraf/pull/15164) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.27.1 to 1.27.4 +- [#15161](https://github.com/influxdata/telegraf/pull/15161) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.25.2 to 1.25.5 +- [#15162](https://github.com/influxdata/telegraf/pull/15162) `deps` Bump github.com/go-sql-driver/mysql from 1.7.1 to 1.8.1 +- [#15084](https://github.com/influxdata/telegraf/pull/15084) `deps` Bump github.com/gophercloud/gophercloud from 1.9.0 to 1.11.0 +- [#15126](https://github.com/influxdata/telegraf/pull/15126) `deps` Bump github.com/jackc/pgtype from 1.14.2 to 1.14.3 +- [#15100](https://github.com/influxdata/telegraf/pull/15100) `deps` Bump github.com/prometheus/client_golang from 1.18.0 to 1.19.0 +- [#15127](https://github.com/influxdata/telegraf/pull/15127) `deps` Bump github.com/redis/go-redis/v9 from 9.2.1 to 9.5.1 +- [#15082](https://github.com/influxdata/telegraf/pull/15082) `deps` Bump github.com/shirou/gopsutil from v3.23.11 to v3.24.3 +- [#15085](https://github.com/influxdata/telegraf/pull/15085) `deps` Bump github.com/testcontainers/testcontainers-go from 0.27.0 to 0.29.1 +- [#15160](https://github.com/influxdata/telegraf/pull/15160) `deps` Bump github.com/vmware/govmomi from 0.33.1 to 0.37.0 +- [#15193](https://github.com/influxdata/telegraf/pull/15193) `deps` Bump golang.org/x/net from 0.22.0 to 0.23.0 +- [#15128](https://github.com/influxdata/telegraf/pull/15128) `deps` Bump golang.org/x/oauth2 from 0.18.0 to 0.19.0 +- [#15124](https://github.com/influxdata/telegraf/pull/15124) `deps` Bump k8s.io/client-go from 0.29.2 to 0.29.3 +- [#15123](https://github.com/influxdata/telegraf/pull/15123) `deps` Bump super-linter/super-linter from 6.3.0 to 6.3.1 +- [#15083](https://github.com/influxdata/telegraf/pull/15083) `deps` Bump tj-actions/changed-files from 43 to 44 + +## v1.30.1 [2024-04-01] + +### Bugfixes + +- [#14966](https://github.com/influxdata/telegraf/pull/14966) `inputs.chrony` Remove chronyc dependency in documentation +- [#15003](https://github.com/influxdata/telegraf/pull/15003) `inputs.diskio` Add missing udev properties +- [#14979](https://github.com/influxdata/telegraf/pull/14979) `inputs.dns_query` Fill out additional record fields +- [#15025](https://github.com/influxdata/telegraf/pull/15025) `inputs.dns_query` Include the canonical CNAME target +- [#15007](https://github.com/influxdata/telegraf/pull/15007) `inputs.knx_listener` Ignore GroupValueRead requests +- [#14959](https://github.com/influxdata/telegraf/pull/14959) `inputs.knx_listener` Reconnect after connection loss +- [#15063](https://github.com/influxdata/telegraf/pull/15063) `inputs.mysql` Parse boolean values in metric v1 correctly +- [#15012](https://github.com/influxdata/telegraf/pull/15012) `inputs.mysql` Use correct column-types for Percona 8 user stats +- [#15023](https://github.com/influxdata/telegraf/pull/15023) `inputs.nvidia_smi` Add process info metrics +- [#14977](https://github.com/influxdata/telegraf/pull/14977) `inputs.openstack` Resolve regression in block storage and server info +- [#15036](https://github.com/influxdata/telegraf/pull/15036) `inputs.phpfpm` Add timeout for fcgi +- [#15011](https://github.com/influxdata/telegraf/pull/15011) `inputs.ping` Add option to force ipv4 +- [#15021](https://github.com/influxdata/telegraf/pull/15021) `inputs.prometheus` Initialize logger of parser +- [#14996](https://github.com/influxdata/telegraf/pull/14996) `inputs.smart` Improve regexp to support flags with a plus +- [#14987](https://github.com/influxdata/telegraf/pull/14987) `inputs.systemd_units` Handle disabled multi-instance units correctly +- [#14958](https://github.com/influxdata/telegraf/pull/14958) `outputs.bigquery` Add scope to bigquery and remove timeout context +- [#14991](https://github.com/influxdata/telegraf/pull/14991) `secrets` Avoid count underflow by only counting initialized secrets +- [#15040](https://github.com/influxdata/telegraf/pull/15040) `windows` Ensure watch-config is passed to Windows service + +### Dependency Updates + +- [#15071](https://github.com/influxdata/telegraf/pull/15071) `deps` Bump github.com/IBM/sarama from v1.42.2 to v1.43.1 +- [#15017](https://github.com/influxdata/telegraf/pull/15017) `deps` Bump github.com/aws/aws-sdk-go-v2 from 1.25.3 to 1.26.0 +- [#15058](https://github.com/influxdata/telegraf/pull/15058) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.27.5 to 1.27.9 +- [#15060](https://github.com/influxdata/telegraf/pull/15060) `deps` Bump github.com/aws/aws-sdk-go-v2/feature/ec2/imds from 1.15.2 to 1.16.0 +- [#14969](https://github.com/influxdata/telegraf/pull/14969) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.34.2 to 1.34.3 +- [#15014](https://github.com/influxdata/telegraf/pull/15014) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.149.3 to 1.151.1 +- [#14971](https://github.com/influxdata/telegraf/pull/14971) `deps` Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.28.2 to 1.28.4 +- [#15029](https://github.com/influxdata/telegraf/pull/15029) `deps` Bump github.com/docker/docker from 25.0.0+incompatible to 25.0.5+incompatible +- [#15016](https://github.com/influxdata/telegraf/pull/15016) `deps` Bump github.com/jackc/pgtype from 1.14.0 to 1.14.2 +- [#14978](https://github.com/influxdata/telegraf/pull/14978) `deps` Bump github.com/jackc/pgx/v4 from 4.18.1 to 4.18.2 +- [#14968](https://github.com/influxdata/telegraf/pull/14968) `deps` Bump github.com/klauspost/compress from 1.17.6 to 1.17.7 +- [#14967](https://github.com/influxdata/telegraf/pull/14967) `deps` Bump github.com/pion/dtls/v2 from 2.2.8 to 2.2.10 +- [#15059](https://github.com/influxdata/telegraf/pull/15059) `deps` Bump github.com/prometheus-community/pro-bing from 0.3.0 to 0.4.0 +- [#14970](https://github.com/influxdata/telegraf/pull/14970) `deps` Bump github.com/prometheus/procfs from 0.12.0 to 0.13.0 +- [#15009](https://github.com/influxdata/telegraf/pull/15009) `deps` Bump github.com/stretchr/testify v1.8.4 to v1.9.0 +- [#15061](https://github.com/influxdata/telegraf/pull/15061) `deps` Bump go.step.sm/crypto from 0.43.0 to 0.44.1 +- [#15018](https://github.com/influxdata/telegraf/pull/15018) `deps` Bump golang.org/x/crypto from 0.20.0 to 0.21.0 +- [#15015](https://github.com/influxdata/telegraf/pull/15015) `deps` Bump gonum.org/v1/gonum from 0.14.0 to 0.15.0 +- [#15057](https://github.com/influxdata/telegraf/pull/15057) `deps` Bump google.golang.org/api from 0.165.0 to 0.171.0 +- [#14989](https://github.com/influxdata/telegraf/pull/14989) `deps` Bump google.golang.org/protobuf from 1.32.0 to 1.33.0 +- [#15013](https://github.com/influxdata/telegraf/pull/15013) `deps` Bump tj-actions/changed-files from 42 to 43 + +## v1.30.0 [2024-03-11] + +### Deprecation Removals + +This release removes the following deprecated plugins: + +- `inputs.cassandra` in [#14859](https://github.com/influxdata/telegraf/pull/14859) +- `inputs.httpjson` in [#14860](https://github.com/influxdata/telegraf/pull/14860) +- `inputs.io` in [#14861](https://github.com/influxdata/telegraf/pull/14861) +- `inputs.jolokia` in [#14862](https://github.com/influxdata/telegraf/pull/14862) +- `inputs.kafka_consumer_legacy` in [#14863](https://github.com/influxdata/telegraf/pull/14863) +- `inputs.snmp_legacy` in [#14864](https://github.com/influxdata/telegraf/pull/14864) +- `inputs.tcp_listener` in [#14865](https://github.com/influxdata/telegraf/pull/14865) +- `inputs.udp_listener` in [#14866](https://github.com/influxdata/telegraf/pull/14866) +- `outputs.riemann_legacy` in [#14867](https://github.com/influxdata/telegraf/pull/14867) + +Furthermore, the following deprecated plugin options are removed: + +- `mountpoints` of `inputs.disk` in [#14913](https://github.com/influxdata/telegraf/pull/14913) +- `metric_buffer` of `inputs.mqtt_consumer` in [#14914](https://github.com/influxdata/telegraf/pull/14914) +- `metric_buffer` of `inputs.nats_consumer` in [#14915](https://github.com/influxdata/telegraf/pull/14915) +- `url` of `outputs.influxdb` in [#14916](https://github.com/influxdata/telegraf/pull/14916) + +Replacements do exist, so please migrate your configuration in case you are +still using one of those plugins. The `telegraf config migrate` command might +be able to assist with the procedure. + +### Important Changes + +- The default read-timeout of `inputs.syslog` of five seconds is not a sensible + default as the plugin will close the connection if the time between + consecutive messages exceeds the timeout. + [#14837](https://github.com/influxdata/telegraf/pull/14828) sets the timeout + to infinite (i.e zero) as this is the expected behavior. +- With correctly sanitizing PostgreSQL addresses ([PR #14829](https://github.com/influxdata/telegraf/pull/14829)) + the `server` tag value for a URI-format address might change in case it + contains spaces, backslashes or single-quotes in non-redacted parameters. + +### New Plugins + +- [#13739](https://github.com/influxdata/telegraf/pull/13739) `outputs.zabbix` Add Zabbix plugin +- [#14474](https://github.com/influxdata/telegraf/pull/14474) `serializers.binary` Add binary serializer +- [#14223](https://github.com/influxdata/telegraf/pull/14223) `processors.snmp_lookup` Add SNMP lookup processor + +### Features + +- [#14491](https://github.com/influxdata/telegraf/pull/14491) Add loongarch64 nightly and release builds +- [#14882](https://github.com/influxdata/telegraf/pull/14882) `agent` Add option to skip re-running processors after aggregators +- [#14676](https://github.com/influxdata/telegraf/pull/14676) `common.opcua` Add debug info for nodes not in server namespace +- [#14743](https://github.com/influxdata/telegraf/pull/14743) `http` Allow secrets in headers +- [#14806](https://github.com/influxdata/telegraf/pull/14806) `inputs.aerospike` Deprecate plugin +- [#14872](https://github.com/influxdata/telegraf/pull/14872) `inputs.amd_rocm_smi` Add startup_error_behavior config option +- [#14673](https://github.com/influxdata/telegraf/pull/14673) `inputs.chrony` Allow to collect additional metrics +- [#14629](https://github.com/influxdata/telegraf/pull/14629) `inputs.chrony` Remove chronyc dependency +- [#14585](https://github.com/influxdata/telegraf/pull/14585) `inputs.kafka_consumer` Mark messages that failed parsing +- [#14507](https://github.com/influxdata/telegraf/pull/14507) `inputs.kernel` Add Pressure Stall Information +- [#14764](https://github.com/influxdata/telegraf/pull/14764) `inputs.modbus` Add workaround for unusual string-byte locations +- [#14625](https://github.com/influxdata/telegraf/pull/14625) `inputs.net` Add speed metric +- [#14680](https://github.com/influxdata/telegraf/pull/14680) `inputs.nvidia_smi` Add startup_error_behavior config option +- [#14424](https://github.com/influxdata/telegraf/pull/14424) `inputs.prometheus` Add internal metrics +- [#14661](https://github.com/influxdata/telegraf/pull/14661) `inputs.prometheus` Add option to limit body length +- [#14702](https://github.com/influxdata/telegraf/pull/14702) `inputs.redfish` Allow secrets for username/password configuration +- [#14613](https://github.com/influxdata/telegraf/pull/14613) `inputs.smart` Add a device_type tag to differentiate disks behind a RAID controller +- [#14792](https://github.com/influxdata/telegraf/pull/14792) `inputs.sqlserver` Add stolen target memory ratio +- [#14814](https://github.com/influxdata/telegraf/pull/14814) `inputs.systemd_units` Allow to query unloaded/disabled units +- [#14539](https://github.com/influxdata/telegraf/pull/14539) `inputs.systemd_units` Introduce show subcommand for additional data +- [#14684](https://github.com/influxdata/telegraf/pull/14684) `inputs.win_services` Make service selection case-insensitive +- [#14628](https://github.com/influxdata/telegraf/pull/14628) `outputs.graphite` Allow to set the local address to bind +- [#14236](https://github.com/influxdata/telegraf/pull/14236) `outputs.nats` Introduce NATS Jetstream option +- [#14658](https://github.com/influxdata/telegraf/pull/14658) `outputs.nebius_cloud_monitoring` Add service configuration setting +- [#14836](https://github.com/influxdata/telegraf/pull/14836) `outputs.websocket` Allow specifying secrets in headers +- [#14870](https://github.com/influxdata/telegraf/pull/14870) `serializers.csv` Allow specifying fixed column order + +### Bugfixes + +- [#14840](https://github.com/influxdata/telegraf/pull/14840) `agent` Catch panics in inputs goroutine +- [#14858](https://github.com/influxdata/telegraf/pull/14858) `config` Reword error message about missing config option +- [#14874](https://github.com/influxdata/telegraf/pull/14874) `inputs.docker_log` Use correct name when matching container +- [#14951](https://github.com/influxdata/telegraf/pull/14951) `inputs.gnmi` Add option to guess path tag from subscription +- [#14953](https://github.com/influxdata/telegraf/pull/14953) `inputs.gnmi` Handle canonical field-name correctly +- [#14910](https://github.com/influxdata/telegraf/pull/14910) `inputs.netflow` Fallback to IPFIX mappings for Netflow v9 +- [#14852](https://github.com/influxdata/telegraf/pull/14852) `inputs.phpfpm` Continue despite erroneous sockets +- [#14871](https://github.com/influxdata/telegraf/pull/14871) `inputs.prometheus` List namespaces only when filtering by namespace +- [#14606](https://github.com/influxdata/telegraf/pull/14606) `parsers.prometheus` Do not touch input data for protocol-buffers +- [#14880](https://github.com/influxdata/telegraf/pull/14880) `processors.override` Correct TOML tag name +- [#14937](https://github.com/influxdata/telegraf/pull/14937) `statefile` Ensure valid statefile in package + +### Dependency Updates + +- [#14931](https://github.com/influxdata/telegraf/pull/14931) `deps` Bump all github.com/aws/aws-sdk-go-v2 dependencies +- [#14894](https://github.com/influxdata/telegraf/pull/14894) `deps` Bump cloud.google.com/go/bigquery from 1.58.0 to 1.59.1 +- [#14932](https://github.com/influxdata/telegraf/pull/14932) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.27.0 to 1.30.2 +- [#14949](https://github.com/influxdata/telegraf/pull/14949) `deps` Bump github.com/cloudevents/sdk-go/v2 from 2.15.0 to 2.15.2 +- [#14929](https://github.com/influxdata/telegraf/pull/14929) `deps` Bump github.com/eclipse/paho.golang from 0.20.0 to 0.21.0 +- [#14892](https://github.com/influxdata/telegraf/pull/14892) `deps` Bump github.com/microsoft/go-mssqldb from 1.6.0 to 1.7.0 +- [#14923](https://github.com/influxdata/telegraf/pull/14923) `deps` Bump github.com/netsampler/goflow2 from v1.3.6 to v2.1.2 +- [#14895](https://github.com/influxdata/telegraf/pull/14895) `deps` Bump github.com/peterbourgon/unixtransport from 0.0.3 to 0.0.4 +- [#14933](https://github.com/influxdata/telegraf/pull/14933) `deps` Bump github.com/prometheus/client_model from 0.5.0 to 0.6.0 +- [#14857](https://github.com/influxdata/telegraf/pull/14857) `deps` Bump github.com/srebhan/cborquery from v0.0.0-20230626165538-38be85b82316 to v1.0.1 +- [#14918](https://github.com/influxdata/telegraf/pull/14918) `deps` Bump github.com/vapourismo/knx-go from v0.0.0-20240107135439-816b70397a00 to v0.0.0-20240217175130-922a0d50c241 +- [#14893](https://github.com/influxdata/telegraf/pull/14893) `deps` Bump go.mongodb.org/mongo-driver from 1.13.1 to 1.14.0 +- [#14891](https://github.com/influxdata/telegraf/pull/14891) `deps` Bump golang.org/x/crypto from 0.19.0 to 0.20.0 +- [#14930](https://github.com/influxdata/telegraf/pull/14930) `deps` Bump modernc.org/sqlite from 1.28.0 to 1.29.2 +- [#14897](https://github.com/influxdata/telegraf/pull/14897) `deps` Bump super-linter/super-linter from 6.1.1 to 6.2.0 +- [#14934](https://github.com/influxdata/telegraf/pull/14934) `deps` Bump super-linter/super-linter from 6.2.0 to 6.3.0 + +## v1.29.5 [2024-02-20] + +### Bugfixes + +- [#14669](https://github.com/influxdata/telegraf/pull/14669) `inputs.filecount` Respect symlink files with FollowSymLinks +- [#14838](https://github.com/influxdata/telegraf/pull/14838) `inputs.gnmi` Normalize path for inline origin handling +- [#14679](https://github.com/influxdata/telegraf/pull/14679) `inputs.kafka_consumer` Fix typo of msg_headers_as_tags +- [#14707](https://github.com/influxdata/telegraf/pull/14707) `inputs.postgresql_extensible` Add support for bool tags +- [#14659](https://github.com/influxdata/telegraf/pull/14659) `inputs.redfish` Resolve iLO4 fan data +- [#14665](https://github.com/influxdata/telegraf/pull/14665) `inputs.snmp_trap` Enable SHA ciphers +- [#14635](https://github.com/influxdata/telegraf/pull/14635) `inputs.vsphere` Use guest.guestId value if set for guest name +- [#14752](https://github.com/influxdata/telegraf/pull/14752) `outputs.mqtt` Retry metrics for server timeout +- [#14770](https://github.com/influxdata/telegraf/pull/14770) `processors.execd` Accept tracking metrics instead of dropping them +- [#14832](https://github.com/influxdata/telegraf/pull/14832) `processors.unpivot` Handle tracking metrics correctly +- [#14654](https://github.com/influxdata/telegraf/pull/14654) `rpm` Ensure telegraf is installed after useradd + +### Dependency Updates + +- [#14690](https://github.com/influxdata/telegraf/pull/14690) `deps` Bump cloud.google.com/go/bigquery from 1.57.1 to 1.58.0 +- [#14772](https://github.com/influxdata/telegraf/pull/14772) `deps` Bump cloud.google.com/go/pubsub from 1.33.0 to 1.36.1 +- [#14819](https://github.com/influxdata/telegraf/pull/14819) `deps` Bump cloud.google.com/go/storage from 1.36.0 to 1.38.0 +- [#14688](https://github.com/influxdata/telegraf/pull/14688) `deps` Bump github.com/Azure/azure-event-hubs-go/v3 from 3.6.1 to 3.6.2 +- [#14845](https://github.com/influxdata/telegraf/pull/14845) `deps` Bump github.com/DATA-DOG/go-sqlmock from 1.5.0 to 1.5.2 +- [#14820](https://github.com/influxdata/telegraf/pull/14820) `deps` Bump github.com/IBM/sarama from 1.42.1 to 1.42.2 +- [#14774](https://github.com/influxdata/telegraf/pull/14774) `deps` Bump github.com/awnumar/memguard from 0.22.4-0.20231204102859-fce56aae03b8 to 0.22.4 +- [#14687](https://github.com/influxdata/telegraf/pull/14687) `deps` Bump github.com/cloudevents/sdk-go/v2 from 2.14.0 to 2.15.0 +- [#14769](https://github.com/influxdata/telegraf/pull/14769) `deps` Bump github.com/eclipse/paho.golang from 0.11.0 to 0.20.0 +- [#14775](https://github.com/influxdata/telegraf/pull/14775) `deps` Bump github.com/google/uuid from 1.5.0 to 1.6.0 +- [#14686](https://github.com/influxdata/telegraf/pull/14686) `deps` Bump github.com/gopcua/opcua from 0.4.0 to 0.5.3 +- [#14848](https://github.com/influxdata/telegraf/pull/14848) `deps` Bump github.com/gophercloud/gophercloud from 1.7.0 to 1.9.0 +- [#14755](https://github.com/influxdata/telegraf/pull/14755) `deps` Bump github.com/gwos/tcg/sdk from v0.0.0-20220621192633-df0eac0a1a4c to v8.7.2 +- [#14816](https://github.com/influxdata/telegraf/pull/14816) `deps` Bump github.com/jhump/protoreflect from 1.15.4 to 1.15.6 +- [#14773](https://github.com/influxdata/telegraf/pull/14773) `deps` Bump github.com/klauspost/compress from 1.17.4 to 1.17.6 +- [#14817](https://github.com/influxdata/telegraf/pull/14817) `deps` Bump github.com/miekg/dns from 1.1.57 to 1.1.58 +- [#14766](https://github.com/influxdata/telegraf/pull/14766) `deps` Bump github.com/showwin/speedtest-go from 1.6.7 to 1.6.10 +- [#14765](https://github.com/influxdata/telegraf/pull/14765) `deps` Bump github.com/urfave/cli/v2 from 2.25.7 to 2.27.1 +- [#14818](https://github.com/influxdata/telegraf/pull/14818) `deps` Bump go.opentelemetry.io/collector/pdata from 1.0.1 to 1.1.0 +- [#14768](https://github.com/influxdata/telegraf/pull/14768) `deps` Bump golang.org/x/oauth2 from 0.16.0 to 0.17.0 +- [#14849](https://github.com/influxdata/telegraf/pull/14849) `deps` Bump google.golang.org/api from 0.162.0 to 0.165.0 +- [#14847](https://github.com/influxdata/telegraf/pull/14847) `deps` Bump google.golang.org/grpc from 1.61.0 to 1.61.1 +- [#14689](https://github.com/influxdata/telegraf/pull/14689) `deps` Bump k8s.io/apimachinery from 0.29.0 to 0.29.1 +- [#14767](https://github.com/influxdata/telegraf/pull/14767) `deps` Bump k8s.io/client-go from 0.29.0 to 0.29.1 +- [#14846](https://github.com/influxdata/telegraf/pull/14846) `deps` Bump k8s.io/client-go from 0.29.1 to 0.29.2 +- [#14850](https://github.com/influxdata/telegraf/pull/14850) `deps` Bump super-linter/super-linter from 6.0.0 to 6.1.1 +- [#14771](https://github.com/influxdata/telegraf/pull/14771) `deps` Bump tj-actions/changed-files from 41 to 42 +- [#14757](https://github.com/influxdata/telegraf/pull/14757) `deps` Get rid of golang.org/x/exp and use stable versions instead +- [#14753](https://github.com/influxdata/telegraf/pull/14753) `deps` Use github.com/coreos/go-systemd/v22 instead of git version + +## v1.29.4 [2024-01-31] + +### Bugfixes + +- [#14619](https://github.com/influxdata/telegraf/pull/14619) `inputs.snmp_trap` Handle octet strings +- [#14649](https://github.com/influxdata/telegraf/pull/14649) `inputs.temp` Fix regression in metric formats +- [#14655](https://github.com/influxdata/telegraf/pull/14655) `processors.parser` Drop tracking metrics when not carried forward + +### Dependency Updates + +- [#14651](https://github.com/influxdata/telegraf/pull/14651) `deps` Bump all AWS dependencies +- [#14642](https://github.com/influxdata/telegraf/pull/14642) `deps` Bump github.com/compose-spec/compose-go from 1.20.0 to 1.20.2 +- [#14641](https://github.com/influxdata/telegraf/pull/14641) `deps` Bump github.com/gosnmp/gosnmp from 1.36.1 to 1.37.0 +- [#14643](https://github.com/influxdata/telegraf/pull/14643) `deps` Bump github.com/microsoft/go-mssqldb from 1.5.0 to 1.6.0 +- [#14644](https://github.com/influxdata/telegraf/pull/14644) `deps` Bump github.com/nats-io/nats-server/v2 from 2.10.6 to 2.10.9 +- [#14640](https://github.com/influxdata/telegraf/pull/14640) `deps` Bump github.com/yuin/goldmark from 1.5.6 to 1.6.0 + +## v1.29.3 [2024-01-29] + +### Bugfixes + +- [#14627](https://github.com/influxdata/telegraf/pull/14627) `common.encoding` Remove locally-defined errors and use upstream ones +- [#14553](https://github.com/influxdata/telegraf/pull/14553) `inputs.gnmi` Refactor alias handling to prevent clipping +- [#14575](https://github.com/influxdata/telegraf/pull/14575) `inputs.temp` Recover pre-v1.22.4 temperature sensor readings +- [#14526](https://github.com/influxdata/telegraf/pull/14526) `inputs.win_perf_counters` Check errors post-collection for skip +- [#14570](https://github.com/influxdata/telegraf/pull/14570) `inputs.win_perf_counters` Ignore PdhCstatusNoInstance as well +- [#14519](https://github.com/influxdata/telegraf/pull/14519) `outputs.iotdb` Handle paths that contain illegal characters +- [#14604](https://github.com/influxdata/telegraf/pull/14604) `outputs.loki` Do not close body before reading it +- [#14582](https://github.com/influxdata/telegraf/pull/14582) `outputs.mqtt` Preserve leading slash in topic + +### Dependency Updates + +- [#14578](https://github.com/influxdata/telegraf/pull/14578) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.29.5 to 1.31.0 +- [#14576](https://github.com/influxdata/telegraf/pull/14576) `deps` Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.26.5 to 1.26.7 +- [#14577](https://github.com/influxdata/telegraf/pull/14577) `deps` Bump github.com/clarify/clarify-go from 0.2.4 to 0.3.1 +- [#14607](https://github.com/influxdata/telegraf/pull/14607) `deps` Bump github.com/docker/docker from 24.0.7+incompatible to 25.0.0+incompatible +- [#14545](https://github.com/influxdata/telegraf/pull/14545) `deps` Bump github.com/docker/go-connections from 0.4.0 to 0.5.0 +- [#14609](https://github.com/influxdata/telegraf/pull/14609) `deps` Bump github.com/fatih/color from 1.15.0 to 1.16.0 +- [#14546](https://github.com/influxdata/telegraf/pull/14546) `deps` Bump github.com/gorilla/mux from 1.8.0 to 1.8.1 +- [#14562](https://github.com/influxdata/telegraf/pull/14562) `deps` Bump github.com/intel/powertelemetry from 1.0.0 to 1.0.1 +- [#14611](https://github.com/influxdata/telegraf/pull/14611) `deps` Bump github.com/nats-io/nats.go from 1.31.0 to 1.32.0 +- [#14544](https://github.com/influxdata/telegraf/pull/14544) `deps` Bump github.com/prometheus/common from 0.44.0 to 0.45.0 +- [#14608](https://github.com/influxdata/telegraf/pull/14608) `deps` Bump github.com/testcontainers/testcontainers-go from 0.26.0 to 0.27.0 +- [#14573](https://github.com/influxdata/telegraf/pull/14573) `deps` Bump github.com/vapourismo/knx-go from v0.0.0-20220829185957-fb5458a5389d to 20240107135439-816b70397a00 +- [#14574](https://github.com/influxdata/telegraf/pull/14574) `deps` Bump go.opentelemetry.io/collector/pdata from 1.0.0-rcv0016 to 1.0.1 +- [#14541](https://github.com/influxdata/telegraf/pull/14541) `deps` Bump go.starlark.net from go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd to v0.0.0-20231121155337-90ade8b19d09 +- [#14543](https://github.com/influxdata/telegraf/pull/14543) `deps` Bump k8s.io/client-go from 0.28.3 to 0.29.0 +- [#14610](https://github.com/influxdata/telegraf/pull/14610) `deps` Bump modernc.org/sqlite from 1.24.0 to 1.28.0 + +## v1.29.2 [2024-01-08] + +### Bugfixes + +- [#14522](https://github.com/influxdata/telegraf/pull/14522) `common.kafka` Correctly set gssapi username/password +- [#14462](https://github.com/influxdata/telegraf/pull/14462) `inputs.phpfpm` Add pid field to differentiate metrics +- [#14489](https://github.com/influxdata/telegraf/pull/14489) `inputs.phpfpm` Use logger without causing panic +- [#14493](https://github.com/influxdata/telegraf/pull/14493) `inputs.procstat` Correctly set tags on procstat_lookup +- [#14447](https://github.com/influxdata/telegraf/pull/14447) `inputs.upsd` Add additional fields to upsd from NUT +- [#14463](https://github.com/influxdata/telegraf/pull/14463) `inputs.vsphere` Resolve occasional serverFault +- [#14458](https://github.com/influxdata/telegraf/pull/14458) `outputs.bigquery` Ignore fields containing NaN or infinity +- [#14481](https://github.com/influxdata/telegraf/pull/14481) `outputs.influxdb` Support setting Host header +- [#14481](https://github.com/influxdata/telegraf/pull/14481) `outputs.influxdb_v2` Support setting Host header +- [#14471](https://github.com/influxdata/telegraf/pull/14471) `outputs.prometheus_client` Always default to TCP +- [#14460](https://github.com/influxdata/telegraf/pull/14460) `processors.filter` Rename processors.Filter -> processors.filter +- [#14523](https://github.com/influxdata/telegraf/pull/14523) `processors.starlark` Use tracking ID to identify tracking metrics +- [#14517](https://github.com/influxdata/telegraf/pull/14517) `systemd` Allow notify access from all + +### Dependency Updates + +- [#14525](https://github.com/influxdata/telegraf/pull/14525) `deps` Bump collectd.org from v0.5.0 to v0.6.0 +- [#14506](https://github.com/influxdata/telegraf/pull/14506) `deps` Bump github.com/Azure/azure-kusto-go from 0.13.1 to 0.15.0 +- [#14483](https://github.com/influxdata/telegraf/pull/14483) `deps` Bump github.com/containerd/containerd from 1.7.7 to 1.7.11 +- [#14476](https://github.com/influxdata/telegraf/pull/14476) `deps` Bump github.com/djherbis/times from 1.5.0 to 1.6.0 +- [#14496](https://github.com/influxdata/telegraf/pull/14496) `deps` Bump github.com/dvsekhvalnov/jose2go from v1.5.0 to v1.5.1-0.20231206184617-48ba0b76bc88 +- [#14478](https://github.com/influxdata/telegraf/pull/14478) `deps` Bump github.com/google/uuid from 1.4.0 to 1.5.0 +- [#14477](https://github.com/influxdata/telegraf/pull/14477) `deps` Bump github.com/jhump/protoreflect from 1.15.3 to 1.15.4 +- [#14504](https://github.com/influxdata/telegraf/pull/14504) `deps` Bump github.com/pion/dtls/v2 from 2.2.7 to 2.2.8 +- [#14503](https://github.com/influxdata/telegraf/pull/14503) `deps` Bump github.com/prometheus/prometheus from 0.48.0 to 0.48.1 +- [#14515](https://github.com/influxdata/telegraf/pull/14515) `deps` Bump github.com/sijms/go-ora/v2 from 2.7.18 to 2.8.4 +- [#14475](https://github.com/influxdata/telegraf/pull/14475) `deps` Bump go.mongodb.org/mongo-driver from 1.12.1 to 1.13.1 +- [#14480](https://github.com/influxdata/telegraf/pull/14480) `deps` Bump golang.org/x/crypto from 0.16.0 to 0.17.0 +- [#14479](https://github.com/influxdata/telegraf/pull/14479) `deps` Bump golang.org/x/net from 0.17.0 to 0.19.0 +- [#14505](https://github.com/influxdata/telegraf/pull/14505) `deps` Bump google.golang.org/protobuf from 1.31.1-0.20231027082548-f4a6c1f6e5c1 to 1.32.0 + +## v1.29.1 [2023-12-13] + +### Bugfixes + +- [#14443](https://github.com/influxdata/telegraf/pull/14443) `inputs.clickhouse` Omit zookeeper metrics on clickhouse cloud +- [#14430](https://github.com/influxdata/telegraf/pull/14430) `inputs.php-fpm` Parse JSON output +- [#14440](https://github.com/influxdata/telegraf/pull/14440) `inputs.procstat` Revert unintended renaming of systemd_unit option + +### Dependency Updates + +- [#14435](https://github.com/influxdata/telegraf/pull/14435) `deps` Bump github.com/go-ldap/ldap/v3 from 3.4.5 to 3.4.6 +- [#14433](https://github.com/influxdata/telegraf/pull/14433) `deps` Bump github.com/klauspost/compress from 1.17.3 to 1.17.4 +- [#14432](https://github.com/influxdata/telegraf/pull/14432) `deps` Bump github.com/openzipkin/zipkin-go from 0.4.1 to 0.4.2 +- [#14431](https://github.com/influxdata/telegraf/pull/14431) `deps` Bump github.com/tidwall/gjson from 1.14.4 to 1.17.0 +- [#14441](https://github.com/influxdata/telegraf/pull/14441) `deps` Update all github.com/aws/aws-sdk-go-v2 dependencies + +## v1.29.0 [2023-12-11] + +### Important Changes + +- Removed useless, all-zero fields in `inputs.procstat`. Up to now, Telegraf + reports the fields `cpu_time_guest`, `cpu_time_guest_nice`, `cpu_time_idle`, + `cpu_time_irq`, `cpu_time_nice`, `cpu_time_soft_irq` and `cpu_time_steal` + which are never set by the underlying library. As a consequence those fields + were always zero. [#14224](https://github.com/influxdata/telegraf/pull/14224) + removes those useless fields. In case you reference them, please adapt your + queries! + +### New Plugins + +- [#13995](https://github.com/influxdata/telegraf/pull/13995) `inputs.ldap` Add LDAP input plugin supporting OpenLDAP and 389ds +- [#11958](https://github.com/influxdata/telegraf/pull/11958) `outputs.opensearch` Add OpenSearch output plugin +- [#14330](https://github.com/influxdata/telegraf/pull/14330) `processors.filter` Add filter processor plugin +- [#13657](https://github.com/influxdata/telegraf/pull/13657) `secretstores` Add systemd-credentials plugin + +### Features + +- [#14361](https://github.com/influxdata/telegraf/pull/14361) `agent` Allow separators for namepass and namedrop filters +- [#14062](https://github.com/influxdata/telegraf/pull/14062) `aggregators.final` Allow to specify output strategy +- [#14103](https://github.com/influxdata/telegraf/pull/14103) `common.http` Add support for connecting over unix-socket +- [#14345](https://github.com/influxdata/telegraf/pull/14345) `common.opcua` Add option to include OPC-UA DataType as a field +- [#14012](https://github.com/influxdata/telegraf/pull/14012) `config` Deprecate `fieldpass` and `fielddrop` modifiers +- [#14004](https://github.com/influxdata/telegraf/pull/14004) `input.intel_pmt` Add pci_bdf tag to uniquely identify GPUs and other peripherals +- [#14001](https://github.com/influxdata/telegraf/pull/14001) `inputs.amqp_consumer` Add secretstore support for username and password +- [#13894](https://github.com/influxdata/telegraf/pull/13894) `inputs.docker` Add disk usage +- [#14308](https://github.com/influxdata/telegraf/pull/14308) `inputs.dpdk` Add options to customize error-behavior and metric layout +- [#14207](https://github.com/influxdata/telegraf/pull/14207) `inputs.elasticsearch` Use HTTPClientConfig struct +- [#14207](https://github.com/influxdata/telegraf/pull/14207) `inputs.elasticsearch_query` Use HTTPClientConfig struct +- [#14091](https://github.com/influxdata/telegraf/pull/14091) `inputs.gnmi` Rework plugin +- [#14189](https://github.com/influxdata/telegraf/pull/14189) `inputs.http_response` Add body form config option +- [#14363](https://github.com/influxdata/telegraf/pull/14363) `inputs.intel_powerstat` Extract business logic to external library +- [#13924](https://github.com/influxdata/telegraf/pull/13924) `inputs.kafka_consumer` Add message headers as metric tags +- [#14320](https://github.com/influxdata/telegraf/pull/14320) `inputs.kafka_consumer` Add option to set metric name from message header +- [#14207](https://github.com/influxdata/telegraf/pull/14207) `inputs.kibana` Use HTTPClientConfig struct +- [#13993](https://github.com/influxdata/telegraf/pull/13993) `inputs.kube_inventory` Support filtering pods and nodes by node name +- [#13996](https://github.com/influxdata/telegraf/pull/13996) `inputs.kube_inventory` Support using kubelet to get pods data +- [#14092](https://github.com/influxdata/telegraf/pull/14092) `inputs.ldap` Collect additional fields +- [#14207](https://github.com/influxdata/telegraf/pull/14207) `inputs.logstash` Use HTTPClientConfig struct +- [#14145](https://github.com/influxdata/telegraf/pull/14145) `inputs.modbus` Add support for string fields +- [#14375](https://github.com/influxdata/telegraf/pull/14375) `inputs.nats_consumer` Add nkey-seed-file authentication +- [#13923](https://github.com/influxdata/telegraf/pull/13923) `inputs.opcua_listener` Add monitoring params +- [#14214](https://github.com/influxdata/telegraf/pull/14214) `inputs.openweathermap` Add per-city query scheme for current weather +- [#13417](https://github.com/influxdata/telegraf/pull/13417) `inputs.procstat` Obtain process information through supervisor +- [#13991](https://github.com/influxdata/telegraf/pull/13991) `inputs.rabbitmq` Add secretstore support for username and password +- [#14143](https://github.com/influxdata/telegraf/pull/14143) `inputs.redfish` Allow specifying which metrics to collect +- [#14111](https://github.com/influxdata/telegraf/pull/14111) `inputs.snmp` Hint to use source tag +- [#14172](https://github.com/influxdata/telegraf/pull/14172) `inputs.socket_listener` Add vsock support to socket listener and writer +- [#13978](https://github.com/influxdata/telegraf/pull/13978) `inputs.sql` Add Oracle driver +- [#14200](https://github.com/influxdata/telegraf/pull/14200) `inputs.sql` Add IBM Netezza driver +- [#14073](https://github.com/influxdata/telegraf/pull/14073) `inputs.win_service` Reduce required rights to GENERIC_READ +- [#14401](https://github.com/influxdata/telegraf/pull/14401) `migrations` Add migration for fieldpass and fielddrop +- [#14114](https://github.com/influxdata/telegraf/pull/14114) `migrations` Add migration for inputs.jolokia +- [#14122](https://github.com/influxdata/telegraf/pull/14122) `migrations` Add migration for inputs.kafka_consumer_legacy +- [#14123](https://github.com/influxdata/telegraf/pull/14123) `migrations` Add migration for inputs.snmp_legacy +- [#14119](https://github.com/influxdata/telegraf/pull/14119) `migrations` Add migration for inputs.tcp_listener +- [#14120](https://github.com/influxdata/telegraf/pull/14120) `migrations` Add migration for inputs.udp_listener +- [#14121](https://github.com/influxdata/telegraf/pull/14121) `migrations` Add migration for outputs.riemann_legacy +- [#14141](https://github.com/influxdata/telegraf/pull/14141) `migrations` Add option migration for inputs.disk +- [#14233](https://github.com/influxdata/telegraf/pull/14233) `migrations` Add option migration for inputs.mqtt_consumer +- [#14234](https://github.com/influxdata/telegraf/pull/14234) `migrations` Add option migration for inputs.nats_consumer +- [#14341](https://github.com/influxdata/telegraf/pull/14341) `migrations` Add option migration for outputs.influxdb +- [#14047](https://github.com/influxdata/telegraf/pull/14047) `outputs.azure_data_explorer` Set user agent string +- [#14342](https://github.com/influxdata/telegraf/pull/14342) `outputs.bigquery` Allow to add metrics in one compact table +- [#14086](https://github.com/influxdata/telegraf/pull/14086) `outputs.bigquery` Make project no longer a required field +- [#13672](https://github.com/influxdata/telegraf/pull/13672) `outputs.exec` Add ability to exec command once per metric +- [#14108](https://github.com/influxdata/telegraf/pull/14108) `outputs.prometheus_client` Support listening on vsock +- [#14172](https://github.com/influxdata/telegraf/pull/14172) `outputs.socket_writer` Add vsock support to socket listener and writer +- [#14017](https://github.com/influxdata/telegraf/pull/14017) `outputs.stackdriver` Add metric type config options +- [#14275](https://github.com/influxdata/telegraf/pull/14275) `outputs.stackdriver` Enable histogram support +- [#14136](https://github.com/influxdata/telegraf/pull/14136) `outputs.wavefront` Use common/http to configure http client +- [#13903](https://github.com/influxdata/telegraf/pull/13903) `parsers.avro` Allow connection to https schema registry +- [#13914](https://github.com/influxdata/telegraf/pull/13914) `parsers.avro` Get metric name from the message field +- [#13945](https://github.com/influxdata/telegraf/pull/13945) `parsers.avro` Support multiple modes for union handling +- [#14065](https://github.com/influxdata/telegraf/pull/14065) `processors.dedup` Add state persistence between runs +- [#13971](https://github.com/influxdata/telegraf/pull/13971) `processors.regex` Allow batch transforms using named groups +- [#13998](https://github.com/influxdata/telegraf/pull/13998) `secrets` Add unprotected secret implementation + +### Bugfixes + +- [#14331](https://github.com/influxdata/telegraf/pull/14331) `common.oauth` Initialize EndpointParams to avoid panic with audience settings +- [#14350](https://github.com/influxdata/telegraf/pull/14350) `inputs.http` Use correct token variable +- [#14420](https://github.com/influxdata/telegraf/pull/14420) `inputs.intel_powerstat` Fix unit tests to work on every CPU/platform +- [#14388](https://github.com/influxdata/telegraf/pull/14388) `inputs.modbus` Split large request correctly at field borders +- [#14373](https://github.com/influxdata/telegraf/pull/14373) `inputs.netflow` Handle malformed inputs gracefully +- [#14394](https://github.com/influxdata/telegraf/pull/14394) `inputs.s7comm` Reconnect if query fails +- [#14357](https://github.com/influxdata/telegraf/pull/14357) `inputs.tail` Retry opening file after permission denied +- [#14419](https://github.com/influxdata/telegraf/pull/14419) `license` Correct spelling of jmhodges/clock license +- [#14416](https://github.com/influxdata/telegraf/pull/14416) `outputs.bigquery` Correct use of auto-detected project ID +- [#14340](https://github.com/influxdata/telegraf/pull/14340) `outputs.opensearch` Expose TLS setting correctly +- [#14021](https://github.com/influxdata/telegraf/pull/14021) `outputs.opensearch` Migrate to new secrets API +- [#14232](https://github.com/influxdata/telegraf/pull/14232) `outputs.prometheus_client` Ensure v1 collector data expires promptly +- [#13961](https://github.com/influxdata/telegraf/pull/13961) `parsers.avro` Clean up Warnf error wrapping error +- [#13939](https://github.com/influxdata/telegraf/pull/13939) `parsers.avro` Attempt to read CA cert file only if filename is not empty string +- [#14351](https://github.com/influxdata/telegraf/pull/14351) `parsers.json v2` Correct wrong name of config option +- [#14344](https://github.com/influxdata/telegraf/pull/14344) `parsers.json_v2` Reset state before parsing +- [#14395](https://github.com/influxdata/telegraf/pull/14395) `processors.starlark` Avoid negative refcounts for tracking metrics +- [#14137](https://github.com/influxdata/telegraf/pull/14137) `processors.starlark` Maintain tracking information post-apply + +### Dependency Updates + +- [#14352](https://github.com/influxdata/telegraf/pull/14352) `deps` Bump cloud.google.com/go/bigquery from 1.56.0 to 1.57.1 +- [#14324](https://github.com/influxdata/telegraf/pull/14324) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.26.0 to 1.27.2 +- [#14323](https://github.com/influxdata/telegraf/pull/14323) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor from 0.10.1 to 0.10.2 +- [#14354](https://github.com/influxdata/telegraf/pull/14354) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor from 0.10.2 to 0.11.0 +- [#14355](https://github.com/influxdata/telegraf/pull/14355) `deps` Bump github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources from 1.1.1 to 1.2.0 +- [#14382](https://github.com/influxdata/telegraf/pull/14382) `deps` Bump github.com/golang-jwt/jwt/v5 from 5.0.0 to 5.2.0 +- [#14385](https://github.com/influxdata/telegraf/pull/14385) `deps` Bump github.com/IBM/sarama from 1.41.3 to 1.42.1 +- [#14384](https://github.com/influxdata/telegraf/pull/14384) `deps` Bump github.com/influxdata/tail from 1.0.1-0.20210707231403-b283181d1fa7 to 1.0.1-0.20221130111531-19b97bffd978 +- [#14383](https://github.com/influxdata/telegraf/pull/14383) `deps` Bump github.com/jackc/pgconn from 1.14.0 to 1.14.1 +- [#14386](https://github.com/influxdata/telegraf/pull/14386) `deps` Bump github.com/nats-io/nats-server/v2 from 2.9.23 to 2.10.6 +- [#14321](https://github.com/influxdata/telegraf/pull/14321) `deps` Bump github.com/prometheus/prometheus from 0.46.0 to 0.48.0 +- [#14325](https://github.com/influxdata/telegraf/pull/14325) `deps` Bump github.com/vmware/govmomi from 0.32.0 to 0.33.1 +- [#14353](https://github.com/influxdata/telegraf/pull/14353) `deps` Bump golang.org/x/text from 0.13.0 to 0.14.0 +- [#14322](https://github.com/influxdata/telegraf/pull/14322) `deps` Bump k8s.io/api from 0.28.3 to 0.28.4 +- [#14349](https://github.com/influxdata/telegraf/pull/14349) `deps` Point kafka dependency to IBM organization + +## v1.28.5 [2023-11-15] + +### Bugfixes + +- [#14294](https://github.com/influxdata/telegraf/pull/14294) `inputs.ecs` Correct v4 metadata URLs +- [#14274](https://github.com/influxdata/telegraf/pull/14274) `inputs.intel_rdt` Do not fail on missing PIDs +- [#14283](https://github.com/influxdata/telegraf/pull/14283) `inputs.s7comm` Truncate strings to reported length +- [#14296](https://github.com/influxdata/telegraf/pull/14296) `parsers.json_v2` Log inner errors + +### Dependency Updates + +- [#14287](https://github.com/influxdata/telegraf/pull/14287) `deps` Bump github.com/gosnmp/gosnmp from 1.35.1-0.20230602062452-f30602b8dad6 to 1.36.1 +- [#14286](https://github.com/influxdata/telegraf/pull/14286) `deps` Bump github.com/Masterminds/semver/v3 from 3.2.0 to 3.2.1 +- [#14285](https://github.com/influxdata/telegraf/pull/14285) `deps` Bump golang.org/x/sync from 0.4.0 to 0.5.0 +- [#14289](https://github.com/influxdata/telegraf/pull/14289) `deps` Bump golang.org/x/mod from 0.13.0 to 0.14.0 +- [#14288](https://github.com/influxdata/telegraf/pull/14288) `deps` Bump google.golang.org/api from 0.149.0 to 0.150.0 + +## v1.28.4 [2023-11-13] + +### Bugfixes + +- [#14240](https://github.com/influxdata/telegraf/pull/14240) `config` Fix comment removal in TOML files +- [#14187](https://github.com/influxdata/telegraf/pull/14187) `inputs.cgroup` Escape backslashes in path +- [#14267](https://github.com/influxdata/telegraf/pull/14267) `inputs.disk` Add inodes_used_percent field +- [#14197](https://github.com/influxdata/telegraf/pull/14197) `inputs.ecs` Fix cgroupv2 CPU metrics +- [#14194](https://github.com/influxdata/telegraf/pull/14194) `inputs.ecs` Test for v4 metadata endpoint +- [#14262](https://github.com/influxdata/telegraf/pull/14262) `inputs.ipset` Parse lines with timeout +- [#14243](https://github.com/influxdata/telegraf/pull/14243) `inputs.mqtt_consumer` Resolve could not mark message delivered +- [#14195](https://github.com/influxdata/telegraf/pull/14195) `inputs.netflow` Fix sFlow metric timestamp +- [#14191](https://github.com/influxdata/telegraf/pull/14191) `inputs.prometheus` Read bearer token from file every time +- [#14068](https://github.com/influxdata/telegraf/pull/14068) `inputs.s7comm` Fix bit queries +- [#14241](https://github.com/influxdata/telegraf/pull/14241) `inputs.win_perf_counter` Do not rely on returned buffer size +- [#14176](https://github.com/influxdata/telegraf/pull/14176) `inputs.zfs` Parse metrics correctly on FreeBSD 14 +- [#14280](https://github.com/influxdata/telegraf/pull/14280) `inputs.zfs` Support gathering metrics on zfs 2.2.0 and later +- [#14115](https://github.com/influxdata/telegraf/pull/14115) `outputs.elasticsearch` Print error status value +- [#14213](https://github.com/influxdata/telegraf/pull/14213) `outputs.timestream` Clip uint64 values +- [#14149](https://github.com/influxdata/telegraf/pull/14149) `parsers.json_v2` Prevent race condition in parse function + +### Dependency Updates + +- [#14253](https://github.com/influxdata/telegraf/pull/14253) `deps` Bump cloud.google.com/go/storage from 1.30.1 to 1.34.1 +- [#14218](https://github.com/influxdata/telegraf/pull/14218) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.18.42 to 1.19.1 +- [#14167](https://github.com/influxdata/telegraf/pull/14167) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.13.40 to 1.13.43 +- [#14249](https://github.com/influxdata/telegraf/pull/14249) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.23.5 to 1.26.0 +- [#14166](https://github.com/influxdata/telegraf/pull/14166) `deps` Bump github.com/antchfx/xmlquery from 1.3.17 to 1.3.18 +- [#14217](https://github.com/influxdata/telegraf/pull/14217) `deps` Bump github.com/antchfx/xpath from 1.2.5-0.20230505064641-588960cceeac to 1.2.5 +- [#14219](https://github.com/influxdata/telegraf/pull/14219) `deps` Bump github.com/benbjohnson/clock from 1.3.3 to 1.3.5 +- [#14216](https://github.com/influxdata/telegraf/pull/14216) `deps` Bump github.com/compose-spec/compose-go from 1.16.0 to 1.20.0 +- [#14211](https://github.com/influxdata/telegraf/pull/14211) `deps` Bump github.com/docker/docker from 24.0.6 to 24.0.7 +- [#14164](https://github.com/influxdata/telegraf/pull/14164) `deps` Bump github.com/hashicorp/consul/api from 1.24.0 to 1.25.1 +- [#14251](https://github.com/influxdata/telegraf/pull/14251) `deps` Bump github.com/hashicorp/consul/api from 1.25.1 to 1.26.1 +- [#14225](https://github.com/influxdata/telegraf/pull/14225) `deps` Bump github.com/nats-io/nkeys from 0.4.5 to 0.4.6 +- [#14168](https://github.com/influxdata/telegraf/pull/14168) `deps` Bump github.com/prometheus/client_golang from 1.16.0 to 1.17.0 +- [#14252](https://github.com/influxdata/telegraf/pull/14252) `deps` Bump github.com/rabbitmq/amqp091-go from 1.8.1 to 1.9.0 +- [#14250](https://github.com/influxdata/telegraf/pull/14250) `deps` Bump github.com/showwin/speedtest-go from 1.6.6 to 1.6.7 +- [#14192](https://github.com/influxdata/telegraf/pull/14192) `deps` Bump google.golang.org/grpc from 1.58.2 to 1.58.3 +- [#14165](https://github.com/influxdata/telegraf/pull/14165) `deps` Bump k8s.io/client-go from 0.28.2 to 0.28.3 + +## v1.28.3 [2023-10-23] + +### Bugfixes + +- [#14049](https://github.com/influxdata/telegraf/pull/14049) `inputs.infiniband` Handle devices without counters +- [#14105](https://github.com/influxdata/telegraf/pull/14105) `inputs.jenkins` Filter after searching sub-folders +- [#14132](https://github.com/influxdata/telegraf/pull/14132) `inputs.jolokia2_agent` Trim quotes around tags +- [#14041](https://github.com/influxdata/telegraf/pull/14041) `inputs.mqtt` Reference correct password variable +- [#14010](https://github.com/influxdata/telegraf/pull/14010) `inputs.postgresql_extensible` Restore default db name +- [#14045](https://github.com/influxdata/telegraf/pull/14045) `inputs.s7comm` Allow PDU-size to be set as config option +- [#14153](https://github.com/influxdata/telegraf/pull/14153) `inputs.vault` Use http client to handle redirects correctly +- [#14131](https://github.com/influxdata/telegraf/pull/14131) `metricpass` Use correct logic expression in benchmark +- [#14154](https://github.com/influxdata/telegraf/pull/14154) `outputs.kafka` Simplify send-error handling +- [#14135](https://github.com/influxdata/telegraf/pull/14135) `outputs.nebius_cloud_monitoring` Use correct endpoint +- [#14060](https://github.com/influxdata/telegraf/pull/14060) `outputs.redistimeseries` Handle string fields correctly +- [#14150](https://github.com/influxdata/telegraf/pull/14150) `serializers.json` Append newline for batch-serialization + +### Dependency Updates + +- [#14036](https://github.com/influxdata/telegraf/pull/14036) `deps` Bump github.com/apache/arrow/go/v13 from 13.0.0-git to 13.0.0 +- [#14125](https://github.com/influxdata/telegraf/pull/14125) `deps` Bump github.com/google/cel-go from 0.14.1-git to 0.18.1 +- [#14127](https://github.com/influxdata/telegraf/pull/14127) `deps` Bump github.com/google/go-cmp from 0.5.9 to 0.6.0 +- [#14085](https://github.com/influxdata/telegraf/pull/14085) `deps` Bump github.com/jhump/protoreflect from 1.15.1 to 1.15.3 +- [#14039](https://github.com/influxdata/telegraf/pull/14039) `deps` Bump github.com/klauspost/compress from 1.16.7 to 1.17.0 +- [#14077](https://github.com/influxdata/telegraf/pull/14077) `deps` Bump github.com/miekg/dns from 1.1.55 to 1.1.56 +- [#14124](https://github.com/influxdata/telegraf/pull/14124) `deps` Bump github.com/nats-io/nats.go from 1.28.0 to 1.31.0 +- [#14146](https://github.com/influxdata/telegraf/pull/14146) `deps` Bump github.com/nats-io/nats-server/v2 from 2.9.9 to 2.9.23 +- [#14037](https://github.com/influxdata/telegraf/pull/14037) `deps` Bump github.com/netsampler/goflow2 from 1.3.3 to 1.3.6 +- [#14040](https://github.com/influxdata/telegraf/pull/14040) `deps` Bump github.com/signalfx/golib/v3 from 3.3.50 to 3.3.53 +- [#14076](https://github.com/influxdata/telegraf/pull/14076) `deps` Bump github.com/testcontainers/testcontainers-go from 0.22.0 to 0.25.0 +- [#14038](https://github.com/influxdata/telegraf/pull/14038) `deps` Bump github.com/yuin/goldmark from 1.5.4 to 1.5.6 +- [#14075](https://github.com/influxdata/telegraf/pull/14075) `deps` Bump golang.org/x/mod from 0.12.0 to 0.13.0 +- [#14095](https://github.com/influxdata/telegraf/pull/14095) `deps` Bump golang.org/x/net from 0.15.0 to 0.17.0 +- [#14074](https://github.com/influxdata/telegraf/pull/14074) `deps` Bump golang.org/x/oauth2 from 0.11.0 to 0.13.0 +- [#14078](https://github.com/influxdata/telegraf/pull/14078) `deps` Bump gonum.org/v1/gonum from 0.13.0 to 0.14.0 +- [#14126](https://github.com/influxdata/telegraf/pull/14126) `deps` Bump google.golang.org/api from 0.139.0 to 0.147.0 + +## v1.28.2 [2023-10-02] + +### Bugfixes + +- [#13963](https://github.com/influxdata/telegraf/pull/13963) `inputs.cisco_telemetry_mdt` Print string message on decode failure +- [#13937](https://github.com/influxdata/telegraf/pull/13937) `inputs.exec` Clean up grandchildren processes +- [#13977](https://github.com/influxdata/telegraf/pull/13977) `inputs.intel_pmt` Handle telem devices without numa_node attribute +- [#13958](https://github.com/influxdata/telegraf/pull/13958) `inputs.jti_openconfig_telemetry` Do not block gRPC dial +- [#13997](https://github.com/influxdata/telegraf/pull/13997) `inputs.mock` Align plugin with documentation +- [#13982](https://github.com/influxdata/telegraf/pull/13982) `inputs.nfsclient` Avoid panics, better error messages +- [#13962](https://github.com/influxdata/telegraf/pull/13962) `inputs.nvidia_smi` Add legacy power readings to v12 schema +- [#14011](https://github.com/influxdata/telegraf/pull/14011) `inputs.openstack` Handle dependencies between enabled services and available endpoints +- [#13972](https://github.com/influxdata/telegraf/pull/13972) `inputs.postgresql_extensible` Restore outputaddress behavior +- [#13927](https://github.com/influxdata/telegraf/pull/13927) `inputs.smart` Remove parsing error message +- [#13915](https://github.com/influxdata/telegraf/pull/13915) `inputs.systemd_units` Add missing upstream states +- [#13930](https://github.com/influxdata/telegraf/pull/13930) `outputs.cloudwatch` Increase number of metrics per write +- [#14009](https://github.com/influxdata/telegraf/pull/14009) `outputs.stackdriver` Do not shallow copy map +- [#13931](https://github.com/influxdata/telegraf/pull/13931) `outputs.stackdriver` Drop metrics on InvalidArgument gRPC error +- [#14008](https://github.com/influxdata/telegraf/pull/14008) `parsers.json_v2` Handle optional fields properly +- [#13947](https://github.com/influxdata/telegraf/pull/13947) `processors.template` Handle tracking metrics correctly + +### Dependency Updates + +- [#13941](https://github.com/influxdata/telegraf/pull/13941) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go from 1.62.470 to 1.62.563 +- [#13988](https://github.com/influxdata/telegraf/pull/13988) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.18.27 to 1.18.42 +- [#13943](https://github.com/influxdata/telegraf/pull/13943) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.20.9 to 1.23.5 +- [#13986](https://github.com/influxdata/telegraf/pull/13986) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.80.1 to 1.120.0 +- [#13987](https://github.com/influxdata/telegraf/pull/13987) `deps` Bump github.com/aws/aws-sdk-go-v2/feature/ec2/imds from 1.13.8 to 1.13.11 +- [#13985](https://github.com/influxdata/telegraf/pull/13985) `deps` Bump github.com/eclipse/paho.mqtt.golang from 1.4.2 to 1.4.3 +- [#13989](https://github.com/influxdata/telegraf/pull/13989) `deps` Bump github.com/google/uuid from 1.3.0 to 1.3.1 +- [#13942](https://github.com/influxdata/telegraf/pull/13942) `deps` Bump github.com/shirou/gopsutil/v3 from 3.23.6 to 3.23.8 +- [#14022](https://github.com/influxdata/telegraf/pull/14022) `deps` Bump github.com/vmware/govmomi from 0.28.0 to 0.32.0 +- [#13940](https://github.com/influxdata/telegraf/pull/13940) `deps` Bump golang.org/x/net from 0.14.0 to 0.15.0 +- [#13944](https://github.com/influxdata/telegraf/pull/13944) `deps` Bump k8s.io/api from 0.28.1 to 0.28.2 + +## v1.28.1 [2023-09-12] + +### Bugfixes + +- [#13909](https://github.com/influxdata/telegraf/pull/13909) `packaging` Revert permission change on package configs +- [#13910](https://github.com/influxdata/telegraf/pull/13910) `inputs.redis` Fix password typo +- [#13907](https://github.com/influxdata/telegraf/pull/13907) `inputs.vsphere` Fix config name typo in example + +## v1.28.0 [2023-09-11] + +### Important Changes + +- [#13791](https://github.com/influxdata/telegraf/pull/13791) `metricpass` +Removed the Python compatibility support for "not", "and", and "or" keywords. +This support was incorrectly removing these keywords from actual data. Users +should instead use the standard "!", "&&", and "||" operators. +- [#13856](https://github.com/influxdata/telegraf/pull/13856) `parsers.avro` +The avro processor will no longer create a timestamp field by default unless +explicitly provided in the parser config. +- [#13778](https://github.com/influxdata/telegraf/pull/13778) `packaging` +The default permissions on `/etc/telegraf/telegraf.conf` and +`/etc/telegraf/telegraf.d` on new installs will drop read access for other. +Updates and upgrades do not change permissions. + +### New Plugins + +- [#13801](https://github.com/influxdata/telegraf/pull/13801) `inputs.intel_pmt` Intel PMT +- [#13731](https://github.com/influxdata/telegraf/pull/13731) `inputs.s7comm` S7comm +- [#12747](https://github.com/influxdata/telegraf/pull/12747) `inputs.tacacs` Tacacs +- [#13785](https://github.com/influxdata/telegraf/pull/13785) `processors.split` Split metrics +- [#13621](https://github.com/influxdata/telegraf/pull/13621) `secretstores.oauth2` OAuth2 services +- [#13656](https://github.com/influxdata/telegraf/pull/13656) `serializers.template` Template based serializer + +### Features + +- [#13605](https://github.com/influxdata/telegraf/pull/13605) `agent` Add option to avoid filtering of global tags +- [#13774](https://github.com/influxdata/telegraf/pull/13774) `agent` Watch default config files if none specified +- [#13787](https://github.com/influxdata/telegraf/pull/13787) `cli` Add plugins subcommand to list available and deprecated +- [#13496](https://github.com/influxdata/telegraf/pull/13496) `inputs.amqp_consumer` Add support to rabbitmq stream queue +- [#13877](https://github.com/influxdata/telegraf/pull/13877) `inputs.cisco_telemetry_mdt` Add microbust support +- [#13825](https://github.com/influxdata/telegraf/pull/13825) `inputs.couchbase` Add failover metrics +- [#13452](https://github.com/influxdata/telegraf/pull/13452) `inputs.fail2ban` Allow specification of socket +- [#13754](https://github.com/influxdata/telegraf/pull/13754) `inputs.fibaro` Support HC3 device types +- [#13622](https://github.com/influxdata/telegraf/pull/13622) `inputs.http` Rework token options +- [#13610](https://github.com/influxdata/telegraf/pull/13610) `inputs.influxdb_listener` Add token based authentication +- [#13793](https://github.com/influxdata/telegraf/pull/13793) `inputs.internal` Add Go metric collection option +- [#13649](https://github.com/influxdata/telegraf/pull/13649) `inputs.jenkins` Add option for node labels as tag +- [#13709](https://github.com/influxdata/telegraf/pull/13709) `inputs.jti_openconfig_telemetry` Add keep-alive setting +- [#13728](https://github.com/influxdata/telegraf/pull/13728) `inputs.kernel` Collect KSM metrics +- [#13507](https://github.com/influxdata/telegraf/pull/13507) `inputs.modbus` Add per-metric configuration style +- [#13733](https://github.com/influxdata/telegraf/pull/13733) `inputs.nvidia_smi` Add Nvidia DCGM MIG usage values +- [#13783](https://github.com/influxdata/telegraf/pull/13783) `inputs.nvidia_smi` Add additional fields +- [#13678](https://github.com/influxdata/telegraf/pull/13678) `inputs.nvidia_smi` Support newer data schema versions +- [#13443](https://github.com/influxdata/telegraf/pull/13443) `inputs.openstack` Gather cinder services +- [#13846](https://github.com/influxdata/telegraf/pull/13846) `inputs.opentelemetry` Add configurable log record dimensions +- [#13436](https://github.com/influxdata/telegraf/pull/13436) `inputs.pgbouncer` Add show_commands to select the collected pgbouncer metrics +- [#13620](https://github.com/influxdata/telegraf/pull/13620) `inputs.postgresql_extensible` Introduce max_version for query +- [#13505](https://github.com/influxdata/telegraf/pull/13505) `inputs.procstat` Add status field +- [#13624](https://github.com/influxdata/telegraf/pull/13624) `inputs.prometheus` Always apply kubernetes label and field selectors +- [#13433](https://github.com/influxdata/telegraf/pull/13433) `inputs.ravendb` Add new disk metrics fields +- [#13727](https://github.com/influxdata/telegraf/pull/13727) `inputs.redfish` Add additional chassis tags +- [#13866](https://github.com/influxdata/telegraf/pull/13866) `inputs.redis` Add additional commandstat fields +- [#13723](https://github.com/influxdata/telegraf/pull/13723) `inputs.redis` Support of redis 6.2 ERRORSTATS +- [#13864](https://github.com/influxdata/telegraf/pull/13864) `inputs.redis_sentinel` Allow username and password +- [#13699](https://github.com/influxdata/telegraf/pull/13699) `inputs.solr` Support version 7.x to 9.3 +- [#13448](https://github.com/influxdata/telegraf/pull/13448) `inputs.sqlserver` Add IsHadrEnabled server property +- [#13890](https://github.com/influxdata/telegraf/pull/13890) `inputs.vsphere` Allow to set vSAN sampling interval +- [#13720](https://github.com/influxdata/telegraf/pull/13720) `inputs.vsphere` Support explicit proxy setting +- [#13471](https://github.com/influxdata/telegraf/pull/13471) `internal` Add gather_timeouts metric +- [#13423](https://github.com/influxdata/telegraf/pull/13423) `internal` Add zstd to internal content_coding +- [#13411](https://github.com/influxdata/telegraf/pull/13411) `kafka` Set and send SASL extensions +- [#13532](https://github.com/influxdata/telegraf/pull/13532) `migrations` Add migration for inputs.httpjson +- [#13536](https://github.com/influxdata/telegraf/pull/13536) `migrations` Add migration for inputs.io +- [#13673](https://github.com/influxdata/telegraf/pull/13673) `outputs.execd` Add option for batch format +- [#13245](https://github.com/influxdata/telegraf/pull/13245) `outputs.file` Add compression +- [#13651](https://github.com/influxdata/telegraf/pull/13651) `outputs.http` Allow PATCH method +- [#13763](https://github.com/influxdata/telegraf/pull/13763) `outputs.postgresql` Add option to create time column with timezone +- [#13750](https://github.com/influxdata/telegraf/pull/13750) `outputs.postgresql` Add option to rename time column +- [#13899](https://github.com/influxdata/telegraf/pull/13899) `outputs.prometheus_client` Add secretstore support for basic_password +- [#13857](https://github.com/influxdata/telegraf/pull/13857) `outputs.wavefront` Add more auth options and update SDK +- [#13607](https://github.com/influxdata/telegraf/pull/13607) `parsers.avro` Add support for JSON format +- [#13419](https://github.com/influxdata/telegraf/pull/13419) `parsers.influx` Allow a user to set the timestamp precision +- [#13506](https://github.com/influxdata/telegraf/pull/13506) `parsers.value` Add support for automatic fallback for numeric types +- [#13480](https://github.com/influxdata/telegraf/pull/13480) `parsers.xpath` Add Concise Binary Object Representation parser +- [#13690](https://github.com/influxdata/telegraf/pull/13690) `parsers.xpath` Add option to store fields as base64 +- [#13553](https://github.com/influxdata/telegraf/pull/13553) `processors.parser` Allow also non-string fields +- [#13606](https://github.com/influxdata/telegraf/pull/13606) `processors.template` Unify template metric +- [#13874](https://github.com/influxdata/telegraf/pull/13874) `prometheus` Allow to specify metric type + +### Bugfixes + +- [#13849](https://github.com/influxdata/telegraf/pull/13849) Change the systemd KillMode from control-group to mixed +- [#13777](https://github.com/influxdata/telegraf/pull/13777) `inputs.amqp_consumer` Print error on connection failure +- [#13886](https://github.com/influxdata/telegraf/pull/13886) `inputs.kafka_consumer` Use per-message parser to avoid races +- [#13840](https://github.com/influxdata/telegraf/pull/13840) `inputs.opcua` Verify groups or root nodes included in config +- [#13602](https://github.com/influxdata/telegraf/pull/13602) `inputs.postgresql` Fix default database definition +- [#13779](https://github.com/influxdata/telegraf/pull/13779) `inputs.procstat` Collect swap via /proc/$pid/smaps +- [#13870](https://github.com/influxdata/telegraf/pull/13870) `inputs.sqlserver` Cast max_size to bigint +- [#13833](https://github.com/influxdata/telegraf/pull/13833) `inputs.sysstat` Remove tmpfile to avoid file-descriptor leak +- [#13791](https://github.com/influxdata/telegraf/pull/13791) `metricpass` Remove python logic compatibility +- [#13875](https://github.com/influxdata/telegraf/pull/13875) `outputs.sql` Move conversion_style config option to the right place +- [#13856](https://github.com/influxdata/telegraf/pull/13856) `parsers.avro` Do not force addition of timestamp as a field +- [#13855](https://github.com/influxdata/telegraf/pull/13855) `parsers.avro` Handle timestamp format checking correctly +- [#13865](https://github.com/influxdata/telegraf/pull/13865) `sql` Allow sqlite on Windows (amd64 and arm64) + +### Dependency Updates + +- [#13808](https://github.com/influxdata/telegraf/pull/13808) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.18.2 to 1.18.5 +- [#13811](https://github.com/influxdata/telegraf/pull/13811) `deps` Bump github.com/hashicorp/consul/api from 1.20.0 to 1.24.0 +- [#13809](https://github.com/influxdata/telegraf/pull/13809) `deps` Bump github.com/nats-io/nats.go from 1.27.0 to 1.28.0 +- [#13765](https://github.com/influxdata/telegraf/pull/13765) `deps` Bump github.com/prometheus/prometheus from 0.42.0 to 0.46.0 +- [#13895](https://github.com/influxdata/telegraf/pull/13895) `deps` Bump github.com/showwin/speedtest-go from 1.6.2 to 1.6.6 +- [#13810](https://github.com/influxdata/telegraf/pull/13810) `deps` Bump k8s.io/api from 0.27.4 to 0.28.1 + +## v1.27.4 [2023-08-21] + +### Bugfixes + +- [#13693](https://github.com/influxdata/telegraf/pull/13693) `inputs.cisco_telemetry_mdt` Fix MDT source field overwrite +- [#13682](https://github.com/influxdata/telegraf/pull/13682) `inputs.opcua` Register node IDs again on reconnect +- [#13742](https://github.com/influxdata/telegraf/pull/13742) `inputs.opcua_listener` Avoid segfault when subscription was not successful +- [#13745](https://github.com/influxdata/telegraf/pull/13745) `outputs.stackdriver` Regenerate time interval for unknown metrics +- [#13719](https://github.com/influxdata/telegraf/pull/13719) `parsers.xpath` Handle protobuf maps correctly +- [#13722](https://github.com/influxdata/telegraf/pull/13722) `serializers.nowmetric` Add option for JSONv2 format + +### Dependency Updates + +- [#13766](https://github.com/influxdata/telegraf/pull/13766) `deps` Bump cloud.google.com/go/pubsub from 1.32.0 to 1.33.0 +- [#13767](https://github.com/influxdata/telegraf/pull/13767) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.13.26 to 1.13.32 +- [#13703](https://github.com/influxdata/telegraf/pull/13703) `deps` Bump github.com/aws/aws-sdk-go-v2/feature/ec2/imds from 1.13.4 to 1.13.7 +- [#13702](https://github.com/influxdata/telegraf/pull/13702) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.17.14 to 1.18.0 +- [#13769](https://github.com/influxdata/telegraf/pull/13769) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.18.0 to 1.18.2 +- [#13734](https://github.com/influxdata/telegraf/pull/13734) `deps` Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.19.3 to 1.21.2 +- [#13735](https://github.com/influxdata/telegraf/pull/13735) `deps` Bump github.com/gophercloud/gophercloud from 1.2.0 to 1.5.0 +- [#13737](https://github.com/influxdata/telegraf/pull/13737) `deps` Bump github.com/microsoft/go-mssqldb from 1.3.1-0.20230630170514-78ad89164253 to 1.5.0 +- [#13768](https://github.com/influxdata/telegraf/pull/13768) `deps` Bump github.com/miekg/dns from 1.1.51 to 1.1.55 +- [#13706](https://github.com/influxdata/telegraf/pull/13706) `deps` Bump github.com/openconfig/gnmi from 0.9.1 to 0.10.0 +- [#13705](https://github.com/influxdata/telegraf/pull/13705) `deps` Bump github.com/santhosh-tekuri/jsonschema/v5 from 5.3.0 to 5.3.1 +- [#13736](https://github.com/influxdata/telegraf/pull/13736) `deps` Bump go.mongodb.org/mongo-driver from 1.11.6 to 1.12.1 +- [#13738](https://github.com/influxdata/telegraf/pull/13738) `deps` Bump golang.org/x/oauth2 from 0.10.0 to 0.11.0 +- [#13704](https://github.com/influxdata/telegraf/pull/13704) `deps` Bump google.golang.org/api from 0.129.0 to 0.134.0 + +## v1.27.3 [2023-07-31] + +### Bugfixes + +- [#13614](https://github.com/influxdata/telegraf/pull/13614) `agent` Respect processor order in file +- [#13675](https://github.com/influxdata/telegraf/pull/13675) `config` Handle escaping and quotation correctly +- [#13671](https://github.com/influxdata/telegraf/pull/13671) `config` Setup logger for secret-stores +- [#13646](https://github.com/influxdata/telegraf/pull/13646) `inputs.docker` Add restart count +- [#13647](https://github.com/influxdata/telegraf/pull/13647) `inputs.jti_openconfig_telemetry` Reauthenticate connection on reconnect +- [#13663](https://github.com/influxdata/telegraf/pull/13663) `inputs.mqtt_consumer` Add client trace logs via option +- [#13629](https://github.com/influxdata/telegraf/pull/13629) `inputs.prometheus` Do not collect metrics from finished pods +- [#13627](https://github.com/influxdata/telegraf/pull/13627) `inputs.prometheus` Fix missing metrics when multiple plugin instances specified +- [#13597](https://github.com/influxdata/telegraf/pull/13597) `outputs.nebius_cloud_monitoring` Replace reserved label names +- [#13292](https://github.com/influxdata/telegraf/pull/13292) `outputs.opentelemetry` Group metrics by age and timestamp +- [#13575](https://github.com/influxdata/telegraf/pull/13575) `outputs.stackdriver` Add tag as resource label option +- [#13662](https://github.com/influxdata/telegraf/pull/13662) `parsers.xpath` Ensure precedence of explicitly defined tags and fields +- [#13665](https://github.com/influxdata/telegraf/pull/13665) `parsers.xpath` Fix field-names for arrays of simple types +- [#13660](https://github.com/influxdata/telegraf/pull/13660) `parsers.xpath` Improve handling of complex-type nodes +- [#13604](https://github.com/influxdata/telegraf/pull/13604) `tools.custom_builder` Ignore non-plugin sections during configuration + +### Dependency Updates + +- [#13668](https://github.com/influxdata/telegraf/pull/13668) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go 1.62.389 to 1.62.470 +- [#13640](https://github.com/influxdata/telegraf/pull/13640) `deps` Bump github.com/antchfx/jsonquery from 1.3.1 to 1.3.2 +- [#13639](https://github.com/influxdata/telegraf/pull/13639) `deps` Bump github.com/antchfx/xmlquery from 1.3.15 to 1.3.17 +- [#13679](https://github.com/influxdata/telegraf/pull/13679) `deps` Bump github.com/antchfx/xpath from v1.2.4 to latest master +- [#13589](https://github.com/influxdata/telegraf/pull/13589) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.17.3 to 1.20.0 +- [#13669](https://github.com/influxdata/telegraf/pull/13669) `deps` Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.19.2 to 1.19.3 +- [#13670](https://github.com/influxdata/telegraf/pull/13670) `deps` Bump github.com/eclipse/paho.golang from 0.10.0 to 0.11.0 +- [#13588](https://github.com/influxdata/telegraf/pull/13588) `deps` Bump github.com/go-ldap/ldap/v3 from 3.4.4 to 3.4.5 +- [#13603](https://github.com/influxdata/telegraf/pull/13603) `deps` Bump github.com/jaegertracing/jaeger from 1.38.0 to 1.47.0 +- [#13586](https://github.com/influxdata/telegraf/pull/13586) `deps` Bump github.com/opensearch-project/opensearch-go/v2 from 2.2.0 to 2.3.0 +- [#13585](https://github.com/influxdata/telegraf/pull/13585) `deps` Bump github.com/prometheus-community/pro-bing from 0.2.0 to 0.3.0 +- [#13666](https://github.com/influxdata/telegraf/pull/13666) `deps` Bump github.com/shirou/gopsutil/v3 from 3.23.5 to 3.23.6 +- [#13638](https://github.com/influxdata/telegraf/pull/13638) `deps` Bump github.com/thomasklein94/packer-plugin-libvirt from 0.3.4 to 0.5.0 +- [#13667](https://github.com/influxdata/telegraf/pull/13667) `deps` Bump k8s.io/api from 0.27.2 to 0.27.4 +- [#13587](https://github.com/influxdata/telegraf/pull/13587) `deps` Bump k8s.io/apimachinery from 0.27.2 to 0.27.3 +- [#13641](https://github.com/influxdata/telegraf/pull/13641) `deps` Bump modernc.org/sqlite from 1.23.1 to 1.24.0 + +## v1.27.2 [2023-07-10] + +### Bugfixes + +- [#13570](https://github.com/influxdata/telegraf/pull/13570) `config` Replace environment variables if existing but empty +- [#13525](https://github.com/influxdata/telegraf/pull/13525) `inputs.cloud_pubsub` Properly lock for decompression +- [#13517](https://github.com/influxdata/telegraf/pull/13517) `inputs.gnmi` Add option to explicitly trim field-names +- [#13497](https://github.com/influxdata/telegraf/pull/13497) `inputs.internet_speed` Add location as a field +- [#13485](https://github.com/influxdata/telegraf/pull/13485) `inputs.modbus` Check number of register for datatype +- [#13486](https://github.com/influxdata/telegraf/pull/13486) `inputs.modbus` Fix optimization of overlapping requests and add warning +- [#13478](https://github.com/influxdata/telegraf/pull/13478) `inputs.mqtt_consumer` Correctly handle semaphores on messages +- [#13574](https://github.com/influxdata/telegraf/pull/13574) `inputs.mqtt_consumer` Print warning on no metrics generated +- [#13514](https://github.com/influxdata/telegraf/pull/13514) `inputs.opcua` Ensure connection after reconnect +- [#13495](https://github.com/influxdata/telegraf/pull/13495) `inputs.phpfpm` Check address length to avoid crash +- [#13542](https://github.com/influxdata/telegraf/pull/13542) `inputs.snmp_trap` Copy GoSNMP global defaults to prevent side-effects +- [#13557](https://github.com/influxdata/telegraf/pull/13557) `inputs.vpshere` Compare versions as a string +- [#13527](https://github.com/influxdata/telegraf/pull/13527) `outputs.graphite` Rework connection handling +- [#13562](https://github.com/influxdata/telegraf/pull/13562) `outputs.influxdb_v2` Expose HTTP/2 client timeouts +- [#13454](https://github.com/influxdata/telegraf/pull/13454) `outputs.stackdriver` Options to use official path and types +- [#13522](https://github.com/influxdata/telegraf/pull/13522) `outputs.sumologic` Unwrap serializer for type check +- [#13547](https://github.com/influxdata/telegraf/pull/13547) `parsers.binary` Fix binary parser example in README.md +- [#13526](https://github.com/influxdata/telegraf/pull/13526) `parsers.grok` Use UTC as the default timezone +- [#13550](https://github.com/influxdata/telegraf/pull/13550) `parsers.xpath` Handle explicitly defined fields correctly +- [#13564](https://github.com/influxdata/telegraf/pull/13564) `processors.printer` Convert output to string +- [#13489](https://github.com/influxdata/telegraf/pull/13489) `secretstores` Skip dbus connection with kwallet +- [#13511](https://github.com/influxdata/telegraf/pull/13511) `serializers.splunkmetric` Fix TOML option name for multi-metric +- [#13563](https://github.com/influxdata/telegraf/pull/13563) `tools.custom_builder` Error out for unknown plugins in configuration + +### Dependency Updates + +- [#13524](https://github.com/influxdata/telegraf/pull/13524) Replace github.com/denisenkom/go-mssqldb with github.com/microsoft/go-mssqldb +- [#13501](https://github.com/influxdata/telegraf/pull/13501) `deps` Bump cloud.google.com/go/bigquery from 1.51.1 to 1.52.0 +- [#13500](https://github.com/influxdata/telegraf/pull/13500) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go from 1.62.337 to 1.62.389 +- [#13504](https://github.com/influxdata/telegraf/pull/13504) `deps` Bump github.com/aws/aws-sdk-go-v2/config from 1.18.8 to 1.18.27 +- [#13537](https://github.com/influxdata/telegraf/pull/13537) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.17.8 to 1.17.14 +- [#13509](https://github.com/influxdata/telegraf/pull/13509) `deps` Bump github.com/gopcua/opcua from 0.3.7 to 0.4.0 +- [#13502](https://github.com/influxdata/telegraf/pull/13502) `deps` Bump github.com/prometheus/client_golang from 1.15.1 to 1.16.0 +- [#13544](https://github.com/influxdata/telegraf/pull/13544) `deps` Bump github.com/snowflakedb/gosnowflake from 1.6.13 to 1.6.22 +- [#13541](https://github.com/influxdata/telegraf/pull/13541) `deps` Bump github.com/urfave/cli/v2 from 2.25.5 to 2.25.7 +- [#13538](https://github.com/influxdata/telegraf/pull/13538) `deps` Bump golang.org/x/text from 0.9.0 to 0.10.0 +- [#13554](https://github.com/influxdata/telegraf/pull/13554) `deps` Bump golang.org/x/text from 0.10.0 to 0.11.0 +- [#13540](https://github.com/influxdata/telegraf/pull/13540) `deps` Bump google.golang.org/api from 0.126.0 to 0.129.0 + +## v1.27.1 [2023-06-21] + +### Bugfixes + +- [#13434](https://github.com/influxdata/telegraf/pull/13434) Handle compression level correctly for different algorithms +- [#13457](https://github.com/influxdata/telegraf/pull/13457) `config` Restore old environment var behavior with option +- [#13446](https://github.com/influxdata/telegraf/pull/13446) `custom_builder` Correctly handle serializers and parsers + +### Dependency Updates + +- [#13469](https://github.com/influxdata/telegraf/pull/13469) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.13.20 to 1.13.26 +- [#13468](https://github.com/influxdata/telegraf/pull/13468) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.25.9 to 1.26.2 +- [#13465](https://github.com/influxdata/telegraf/pull/13465) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.16.0 to 1.17.2 +- [#13466](https://github.com/influxdata/telegraf/pull/13466) `deps` Bump github.com/go-sql-driver/mysql from 1.6.0 to 1.7.1 +- [#13427](https://github.com/influxdata/telegraf/pull/13427) `deps` Bump github.com/jackc/pgx/v4 from 4.17.1 to 4.18.1 +- [#13429](https://github.com/influxdata/telegraf/pull/13429) `deps` Bump github.com/nats-io/nats.go from 1.24.0 to 1.27.0 +- [#13467](https://github.com/influxdata/telegraf/pull/13467) `deps` Bump github.com/prometheus-community/pro-bing from 0.1.0 to 0.2.0 +- [#13428](https://github.com/influxdata/telegraf/pull/13428) `deps` Bump golang.org/x/crypto from 0.8.0 to 0.9.0 +- [#13431](https://github.com/influxdata/telegraf/pull/13431) `deps` Bump golang.org/x/term from 0.8.0 to 0.9.0 +- [#13430](https://github.com/influxdata/telegraf/pull/13430) `deps` Bump modernc.org/sqlite from 1.21.0 to 1.23.1 + +## v1.27.0 [2023-06-12] + +### Important Changes + +- Fix parsing of timezone abbreviations such as `MST`. Up to now, when parsing + times with abbreviated timezones (i.e. the format ) the timezone information + is ignored completely and the _timestamp_ is located in UTC. This is a golang + issue (see [#9617](https://github.com/golang/go/issues/9617) or + [#56528](https://github.com/golang/go/issues/56528)). If you worked around + that issue, please remove the workaround before using v1.27+. In case you + experience issues with abbreviated timezones please file an issue! +- Removal of old-style parser creation. This should not directly affect users as + it is an API change. All parsers in Telegraf are already ported to the new + framework. If you experience any issues with not being able to create parsers + let us know! + +### New Plugins + +- [#11155](https://github.com/influxdata/telegraf/pull/11155) `inputs.ctrlx_datalayer` ctrlX Data Layer +- [#13397](https://github.com/influxdata/telegraf/pull/13397) `inputs.intel_baseband` Intel Baseband Accelerator +- [#13220](https://github.com/influxdata/telegraf/pull/13220) `outputs.clarify` Clarify +- [#13379](https://github.com/influxdata/telegraf/pull/13379) `outputs.nebius_cloud_monitoring` Nebius Cloud Monitoring +- [#13061](https://github.com/influxdata/telegraf/pull/13061) `processors.scale` Scale +- [#13035](https://github.com/influxdata/telegraf/pull/13035) `secretstores.docker` Docker Store +- [#13150](https://github.com/influxdata/telegraf/pull/13150) `secretstores.http` HTTP Store +- [#13224](https://github.com/influxdata/telegraf/pull/13224) `serializers.cloudevents` CloudEvents + +### Features + +- [#13144](https://github.com/influxdata/telegraf/pull/13144) Add common expression language metric filtering +- [#13364](https://github.com/influxdata/telegraf/pull/13364) `agent` Add option to avoid filtering of explicit plugin tags +- [#13118](https://github.com/influxdata/telegraf/pull/13118) `aggregators.basicstats` Add percentage change +- [#13094](https://github.com/influxdata/telegraf/pull/13094) `cloud_pubsub` Add support for gzip compression +- [#12863](https://github.com/influxdata/telegraf/pull/12863) `common.opcua` Add support for secret-store secrets +- [#13262](https://github.com/influxdata/telegraf/pull/13262) `common.tls` Add support for passphrase-protected private key +- [#13377](https://github.com/influxdata/telegraf/pull/13377) `config` Add framework for migrating deprecated plugins +- [#13229](https://github.com/influxdata/telegraf/pull/13229) `config` Support shell like syntax for environment variable substitution +- [#12448](https://github.com/influxdata/telegraf/pull/12448) `inputs.cloudwatch` Add support for cross account observability +- [#13089](https://github.com/influxdata/telegraf/pull/13089) `inputs.directory_monitor` Improve internal stats +- [#13163](https://github.com/influxdata/telegraf/pull/13163) `inputs.filecount` Add oldestFileTimestamp and newestFileTimestamp +- [#13326](https://github.com/influxdata/telegraf/pull/13326) `inputs.gnmi` Allow canonical field names +- [#13116](https://github.com/influxdata/telegraf/pull/13116) `inputs.gnmi` Support Juniper GNMI Extension Header +- [#12797](https://github.com/influxdata/telegraf/pull/12797) `inputs.internet_speed` Support multi-server test +- [#11831](https://github.com/influxdata/telegraf/pull/11831) `inputs.kafka_consumer` Add regular expression support for topics +- [#13040](https://github.com/influxdata/telegraf/pull/13040) `inputs.kubernetes` Extend kube_inventory plugin to include and extend resource quota, secret, node, and pod measurement +- [#13293](https://github.com/influxdata/telegraf/pull/13293) `inputs.nats_consumer` Add receiver subject as tag +- [#13047](https://github.com/influxdata/telegraf/pull/13047) `inputs.netflow` Add sFlow decoder +- [#13360](https://github.com/influxdata/telegraf/pull/13360) `inputs.netflow` Allow custom PEN field mappings +- [#13133](https://github.com/influxdata/telegraf/pull/13133) `inputs.nvidia_smi` Add additional memory related fields +- [#13404](https://github.com/influxdata/telegraf/pull/13404) `inputs.opentelemetry` Add configurable span dimensions +- [#12851](https://github.com/influxdata/telegraf/pull/12851) `inputs.prometheus` Control which pod metadata is added as tags +- [#13289](https://github.com/influxdata/telegraf/pull/13289) `inputs.sql` Add disconnected_servers_behavior field in the configuration +- [#13091](https://github.com/influxdata/telegraf/pull/13091) `inputs.sql` Add FlightSQL support +- [#13261](https://github.com/influxdata/telegraf/pull/13261) `inputs.sqlserver` Add Azure Arc-enabled SQL MI support +- [#13284](https://github.com/influxdata/telegraf/pull/13284) `inputs.sqlserver` Check SQL Server encryptionEnforce with xp_instance_regread +- [#13087](https://github.com/influxdata/telegraf/pull/13087) `inputs.statsd` Add optional temporality and start_time tag for statsd metrics +- [#13048](https://github.com/influxdata/telegraf/pull/13048) `inputs.suricata` Add ability to parse drop or rejected +- [#11955](https://github.com/influxdata/telegraf/pull/11955) `inputs.vsphere` Add vSAN extension +- [#13316](https://github.com/influxdata/telegraf/pull/13316) `internal` Add additional faster compression options +- [#13157](https://github.com/influxdata/telegraf/pull/13157) `outputs.loki` Add option for metric name label +- [#13349](https://github.com/influxdata/telegraf/pull/13349) `outputs.wavefront` Add TLS and HTTP Timeout configuration fields +- [#13167](https://github.com/influxdata/telegraf/pull/13167) `parsers.opentsdb` Add OpenTSDB data format parser +- [#13075](https://github.com/influxdata/telegraf/pull/13075) `processors.aws_ec2` Add caching of imds and ec2 tags +- [#13147](https://github.com/influxdata/telegraf/pull/13147) `processors.parser` Add merge with timestamp option +- [#13227](https://github.com/influxdata/telegraf/pull/13227) `processors.scale` Add scaling by factor and offset +- [#13253](https://github.com/influxdata/telegraf/pull/13253) `processors.template` Allow `tag` to be a template +- [#12971](https://github.com/influxdata/telegraf/pull/12971) `serializer.prometheusremote` Improve performance +- [#13275](https://github.com/influxdata/telegraf/pull/13275) `test` Allow to capture all messages during test + +### Bugfixes + +- [#13238](https://github.com/influxdata/telegraf/pull/13238) `inputs.cloud_pubsub` Fix gzip decompression +- [#13304](https://github.com/influxdata/telegraf/pull/13304) `inputs.gnmi` Allow optional origin for update path +- [#13332](https://github.com/influxdata/telegraf/pull/13332) `inputs.gnmi` Handle canonical field-name correctly for non-explicit subscriptions +- [#13350](https://github.com/influxdata/telegraf/pull/13350) `inputs.mqtt` ACK messages when persistence is enabled +- [#13361](https://github.com/influxdata/telegraf/pull/13361) `inputs.mysql` Update MariaDB Dialect regex version check +- [#13325](https://github.com/influxdata/telegraf/pull/13325) `inputs.netflow` Fix field mappings +- [#13320](https://github.com/influxdata/telegraf/pull/13320) `inputs.netflow` Handle PEN messages correctly +- [#13231](https://github.com/influxdata/telegraf/pull/13231) `inputs.prometheus` Avoid race when creating informer factory +- [#13288](https://github.com/influxdata/telegraf/pull/13288) `inputs.socket_listener` Avoid noisy logs on closed connection +- [#13307](https://github.com/influxdata/telegraf/pull/13307) `inputs.temp` Ignore warnings and instead return only errors +- [#13412](https://github.com/influxdata/telegraf/pull/13412) `inputs.upsd` Handle float battery.runtime value +- [#13363](https://github.com/influxdata/telegraf/pull/13363) `internal` Fix time parsing for abbreviated timezones +- [#13408](https://github.com/influxdata/telegraf/pull/13408) `outputs.sql` Use config.duration to correctly to parse toml config +- [#13252](https://github.com/influxdata/telegraf/pull/13252) `outputs.wavefront` Flush metric buffer before reaching overflow +- [#13301](https://github.com/influxdata/telegraf/pull/13301) `processors.lookup` Do not strip tracking info +- [#13164](https://github.com/influxdata/telegraf/pull/13164) `serializers.influx` Restore disabled uint support by default +- [#13394](https://github.com/influxdata/telegraf/pull/13394) `tests` Replace last 'cat' instance in tests + +### Dependency Updates + +- [#13359](https://github.com/influxdata/telegraf/pull/13359) `deps` Bump cloud.google.com/go/monitoring from 1.13.0 to 1.14.0 +- [#13312](https://github.com/influxdata/telegraf/pull/13312) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go from 1.62.193 to 1.62.337 +- [#13390](https://github.com/influxdata/telegraf/pull/13390) `deps` Bump github.com/aws/aws-sdk-go-v2/feature/ec2/imds from 1.13.2 to 1.13.3 +- [#13391](https://github.com/influxdata/telegraf/pull/13391) `deps` Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.18.9 to 1.19.0 +- [#13313](https://github.com/influxdata/telegraf/pull/13313) `deps` Bump github.com/Azure/azure-event-hubs-go/v3 from 3.4.0 to 3.5.0 +- [#13314](https://github.com/influxdata/telegraf/pull/13314) `deps` Bump github.com/Azure/go-autorest/autorest from 0.11.28 to 0.11.29 +- [#13265](https://github.com/influxdata/telegraf/pull/13265) `deps` Bump github.com/influxdata/influxdb-observability libraries from 0.3.3 to 0.3.15 +- [#13311](https://github.com/influxdata/telegraf/pull/13311) `deps` Bump github.com/jackc/pgconn from 1.13.0 to 1.14.0 +- [#13357](https://github.com/influxdata/telegraf/pull/13357) `deps` Bump github.com/jackc/pgtype from 1.12.0 to 1.14.0 +- [#13392](https://github.com/influxdata/telegraf/pull/13392) `deps` Bump github.com/Mellanox/rdmamap to 1.1.0 +- [#13356](https://github.com/influxdata/telegraf/pull/13356) `deps` Bump github.com/pion/dtls/v2 from 2.2.6 to 2.2.7 +- [#13389](https://github.com/influxdata/telegraf/pull/13389) `deps` Bump github.com/prometheus/common from 0.43.0 to 0.44.0 +- [#13355](https://github.com/influxdata/telegraf/pull/13355) `deps` Bump github.com/rabbitmq/amqp091-go from 1.8.0 to 1.8.1 +- [#13396](https://github.com/influxdata/telegraf/pull/13396) `deps` Bump github.com/shirou/gopsutil from 3.23.4 to 3.23.5 +- [#13369](https://github.com/influxdata/telegraf/pull/13369) `deps` Bump github.com/showwin/speedtest-go from 1.5.2 to 1.6.2 +- [#13388](https://github.com/influxdata/telegraf/pull/13388) `deps` Bump github.com/urfave/cli/v2 from 2.23.5 to 2.25.5 +- [#13315](https://github.com/influxdata/telegraf/pull/13315) `deps` Bump k8s.io/client-go from 0.26.2 to 0.27.2 + +## v1.26.3 [2023-05-22] + +### Bugfixes + +- [#13149](https://github.com/influxdata/telegraf/pull/13149) `inputs.gnmi` Create selfstat to track connection state +- [#13139](https://github.com/influxdata/telegraf/pull/13139) `inputs.intel_pmu` Fix handling of the json perfmon format +- [#13056](https://github.com/influxdata/telegraf/pull/13056) `inputs.socket_listener` Fix loss of connection tracking +- [#13300](https://github.com/influxdata/telegraf/pull/13300) `inputs.socket_listener` Fix race in tests +- [#13286](https://github.com/influxdata/telegraf/pull/13286) `inputs.vsphere` Specify the correct option for disconnected_servers_behavior +- [#13239](https://github.com/influxdata/telegraf/pull/13239) `outputs.graphite` Fix logic to reconnect with servers that were not up on agent startup +- [#13169](https://github.com/influxdata/telegraf/pull/13169) `outputs.prometheus_client` Fix export_timestamp for v1 metric type +- [#13168](https://github.com/influxdata/telegraf/pull/13168) `outputs.stackdriver` Allow for custom metric type prefix +- [#12994](https://github.com/influxdata/telegraf/pull/12994) `outputs.stackdriver` Group batches by timestamp +- [#13126](https://github.com/influxdata/telegraf/pull/13126) `outputs.warp10` Support Infinity/-Infinity/NaN values +- [#13156](https://github.com/influxdata/telegraf/pull/13156) `processors.starlark` Do not reject tracking metrics twice + +### Dependency Updates + +- [#13256](https://github.com/influxdata/telegraf/pull/13256) `deps` Bump cloud.google.com/go/pubsub from 1.30.0 to 1.30.1 +- [#13258](https://github.com/influxdata/telegraf/pull/13258) `deps` Bump github.com/aerospike/aerospike-client-go/v5 from 5.10.0 to 5.11.0 +- [#13242](https://github.com/influxdata/telegraf/pull/13242) `deps` Bump github.com/antchfx/xpath to latest master for string-join() +- [#13255](https://github.com/influxdata/telegraf/pull/13255) `deps` Bump github.com/aws/aws-sdk-go-v2 from 1.17.8 to 1.18.0 +- [#13215](https://github.com/influxdata/telegraf/pull/13215) `deps` Bump github.com/Azure/go-autorest/autorest/adal from 0.9.22 to 0.9.23 +- [#13254](https://github.com/influxdata/telegraf/pull/13254) `deps` Bump github.com/benbjohnson/clock from 1.3.0 to 1.3.3 +- [#13269](https://github.com/influxdata/telegraf/pull/13269) `deps` Bump github.com/docker/distribution from 2.8.1 to 2.8.2 +- [#13216](https://github.com/influxdata/telegraf/pull/13216) `deps` Bump github.com/fatih/color from 1.13.0 to 1.15.0 +- [#13104](https://github.com/influxdata/telegraf/pull/13104) `deps` Bump github.com/netsampler/goflow2 from 1.1.1 to 1.3.3 +- [#13138](https://github.com/influxdata/telegraf/pull/13138) `deps` Bump github.com/yuin/goldmark from 1.5.3 to 1.5.4 +- [#13257](https://github.com/influxdata/telegraf/pull/13257) `deps` Bump go.opentelemetry.io/collector/pdata from 1.0.0-rc7 to 1.0.0-rcv0011 +- [#13137](https://github.com/influxdata/telegraf/pull/13137) `deps` Bump golang.org/x/net from 0.8.0 to 0.9.0 +- [#13276](https://github.com/influxdata/telegraf/pull/13276) `deps` Bump golang.org/x/net from 0.9.0 to 0.10.0 +- [#13217](https://github.com/influxdata/telegraf/pull/13217) `deps` Bump golang.org/x/oauth2 from 0.5.0 to 0.7.0 +- [#13170](https://github.com/influxdata/telegraf/pull/13170) `deps` Bump google.golang.org/api from 0.106.0 to 0.120.0 +- [#13223](https://github.com/influxdata/telegraf/pull/13223) `deps` Bump govulncheck-action from 0.10.0 to 0.10.1 +- [#13225](https://github.com/influxdata/telegraf/pull/13225) `deps` Bump prometheus from v1.8.2 to v2.42.0 +- [#13230](https://github.com/influxdata/telegraf/pull/13230) `deps` Bump signalfx/golib from 3.3.46 to 3.3.50 + +## v1.26.2 [2023-04-24] + +### Bugfixes + +- [#13020](https://github.com/influxdata/telegraf/pull/13020) `agent` Pass quiet flag earlier +- [#13063](https://github.com/influxdata/telegraf/pull/13063) `inputs.prometheus` Add namespace option in k8s informer factory +- [#13059](https://github.com/influxdata/telegraf/pull/13059) `inputs.socket_listener` Fix tracking of unix sockets +- [#13078](https://github.com/influxdata/telegraf/pull/13078) `parsers.grok` Fix nil metric for multiline inputs +- [#13092](https://github.com/influxdata/telegraf/pull/13092) `processors.lookup` Fix tracking metrics + +### Dependency Updates + +- [#13106](https://github.com/influxdata/telegraf/pull/13106) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.13.15 to 1.13.20 +- [#13072](https://github.com/influxdata/telegraf/pull/13072) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch from 1.21.6 to 1.25.9 +- [#13107](https://github.com/influxdata/telegraf/pull/13107) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.15.13 to 1.20.9 +- [#13027](https://github.com/influxdata/telegraf/pull/13027) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.15.19 to 1.17.8 +- [#13069](https://github.com/influxdata/telegraf/pull/13069) `deps` Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.18.5 to 1.18.9 +- [#13105](https://github.com/influxdata/telegraf/pull/13105) `deps` Bump github.com/docker/docker from 23.0.0 to 23.0.4 +- [#13024](https://github.com/influxdata/telegraf/pull/13024) `deps` Bump github.com/openconfig/gnmi from 0.0.0-20220920173703-480bf53a74d2 to 0.9.1 +- [#13026](https://github.com/influxdata/telegraf/pull/13026) `deps` Bump github.com/prometheus/common from 0.41.0 to 0.42.0 +- [#13025](https://github.com/influxdata/telegraf/pull/13025) `deps` Bump github.com/safchain/ethtool from 0.2.0 to 0.3.0 +- [#13023](https://github.com/influxdata/telegraf/pull/13023) `deps` Bump github.com/tinylib/msgp from 1.1.6 to 1.1.8 +- [#13071](https://github.com/influxdata/telegraf/pull/13071) `deps` Bump github.com/vishvananda/netns from 0.0.2 to 0.0.4 +- [#13070](https://github.com/influxdata/telegraf/pull/13070) `deps` Bump github.com/wavefronthq/wavefront-sdk-go from 0.11.0 to 0.12.0 + +## v1.26.1 [2023-04-03] + +### Bugfixes + +- [#12880](https://github.com/influxdata/telegraf/pull/12880) `config` Return error on order set as string +- [#12867](https://github.com/influxdata/telegraf/pull/12867) `inputs.ethtool` Check for nil +- [#12935](https://github.com/influxdata/telegraf/pull/12935) `inputs.execd` Add option to set buffer size +- [#12877](https://github.com/influxdata/telegraf/pull/12877) `inputs.internet_speed` Rename host tag to source +- [#12918](https://github.com/influxdata/telegraf/pull/12918) `inputs.kubernetes` Apply timeout for the whole HTTP request +- [#13006](https://github.com/influxdata/telegraf/pull/13006) `inputs.netflow` Use correct name in the build tag +- [#13015](https://github.com/influxdata/telegraf/pull/13015) `inputs.procstat` Return tags of pids if lookup_error +- [#12864](https://github.com/influxdata/telegraf/pull/12864) `inputs.prometheus` Correctly set timeout param +- [#12907](https://github.com/influxdata/telegraf/pull/12907) `inputs.prometheus` Use set over add for custom headers +- [#12961](https://github.com/influxdata/telegraf/pull/12961) `inputs.upsd` Include ups.real_power +- [#12908](https://github.com/influxdata/telegraf/pull/12908) `outputs.graphite` Add custom regex to outputs +- [#13012](https://github.com/influxdata/telegraf/pull/13012) `secrets` Add function to set a secret +- [#13002](https://github.com/influxdata/telegraf/pull/13002) `secrets` Minimize secret holding time +- [#12993](https://github.com/influxdata/telegraf/pull/12993) `secrets` Warn if OS limit for locked memory is too low +- [#12919](https://github.com/influxdata/telegraf/pull/12919) `secrets` Handle array of secrets correctly +- [#12835](https://github.com/influxdata/telegraf/pull/12835) `serializers.graphite` Allow for specifying regex to sanitize +- [#12990](https://github.com/influxdata/telegraf/pull/12990) `systemd` Increase lock memory for service to 8192kb + +### Dependency Updates + +- [#12857](https://github.com/influxdata/telegraf/pull/12857) `deps` Bump github.com/antchfx/xpath from 1.2.3 to 1.2.4 +- [#12909](https://github.com/influxdata/telegraf/pull/12909) `deps` Bump github.com/apache/thrift from 0.16.0 to 0.18.1 +- [#12856](https://github.com/influxdata/telegraf/pull/12856) `deps` Bump github.com/Azure/azure-event-hubs-go/v3 from 3.3.20 to 3.4.0 +- [#12966](https://github.com/influxdata/telegraf/pull/12966) `deps` Bump github.com/Azure/go-autorest/autorest/azure/auth from 0.5.11 to 0.5.12 +- [#12964](https://github.com/influxdata/telegraf/pull/12964) `deps` Bump github.com/golang-jwt/jwt/v4 from 4.4.2 to 4.5.0 +- [#12967](https://github.com/influxdata/telegraf/pull/12967) `deps` Bump github.com/jhump/protoreflect from 1.8.3-0.20210616212123-6cc1efa697ca to 1.15.1 +- [#12855](https://github.com/influxdata/telegraf/pull/12855) `deps` Bump github.com/nats-io/nats.go from 1.19.0 to 1.24.0 +- [#12981](https://github.com/influxdata/telegraf/pull/12981) `deps` Bump github.com/opencontainers/runc from 1.1.4 to 1.1.5 +- [#12913](https://github.com/influxdata/telegraf/pull/12913) `deps` Bump github.com/pion/dtls/v2 from 2.2.4 to 2.2.6 +- [#12968](https://github.com/influxdata/telegraf/pull/12968) `deps` Bump github.com/rabbitmq/amqp091-go from 1.7.0 to 1.8.0 +- [#13017](https://github.com/influxdata/telegraf/pull/13017) `deps` Bump github.com/shirou/gopsutil from 3.23.2 to 3.23.3 +- [#12853](https://github.com/influxdata/telegraf/pull/12853) `deps` Bump github.com/Shopify/sarama from 1.37.2 to 1.38.1 +- [#12854](https://github.com/influxdata/telegraf/pull/12854) `deps` Bump github.com/sensu/sensu-go/api/core/v2 from 2.15.0 to 2.16.0 +- [#12911](https://github.com/influxdata/telegraf/pull/12911) `deps` Bump github.com/tidwall/gjson from 1.14.3 to 1.14.4 +- [#12912](https://github.com/influxdata/telegraf/pull/12912) `deps` Bump golang.org/x/net from 0.7.0 to 0.8.0 +- [#12910](https://github.com/influxdata/telegraf/pull/12910) `deps` Bump modernc.org/sqlite from 1.19.2 to 1.21.0 + +## v1.26.0 [2023-03-13] + +### Important Changes + +- Static Builds: Linux builds are now statically built. Other operating systems + were cross-built in the past and as a result, already static. Users should + not notice any change in behavior. The `_static` specific Linux binary is no + longer produced as a result. +- telegraf.d Behavior: The default behavior of reading + `/etc/telegraf/telegraf.conf` now includes any .conf files under + `/etc/telegraf/telegraf.d/`. This change will apply to the official Telegraf + Docker image as well. This will simplify docker usage when using multiple + configuration files. +- Default Configuration: The `telegraf config` command and default config file + provided by Telegraf now includes all plugins and produces the same output + across all operating systems. Plugin comments specify what platforms are + supported or not. +- State Persistence: State persistence is now available in select plugins. This + will allow plugins to start collecting data, where they left off. A + configuration with state persistence cannot change or it will not be able to + recover. + +### New Plugins + +- [#12393](https://github.com/influxdata/telegraf/pull/12393) `inputs.opensearch_query` Opensearch Query +- [#12473](https://github.com/influxdata/telegraf/pull/12473) `inputs.p4runtime` P4Runtime +- [#12736](https://github.com/influxdata/telegraf/pull/12736) `inputs.radius` Radius Auth Response Time +- [#11250](https://github.com/influxdata/telegraf/pull/11250) `inputs.win_wmi` Windows Management Instrumentation (WMI) +- [#12809](https://github.com/influxdata/telegraf/pull/12809) `processors.lookup` Lookup + +### Features + +- [#12600](https://github.com/influxdata/telegraf/pull/12600) Always disable cgo support (static builds) +- [#12166](https://github.com/influxdata/telegraf/pull/12166) Plugin state-persistence +- [#12608](https://github.com/influxdata/telegraf/pull/12608) `agent` Add /etc/telegraf/telegraf.d to default config locations +- [#12827](https://github.com/influxdata/telegraf/pull/12827) `agent` Print loaded configs +- [#12821](https://github.com/influxdata/telegraf/pull/12821) `common.oauth` Add audience parameter +- [#12727](https://github.com/influxdata/telegraf/pull/12727) `common.tls` Add enable flag +- [#12579](https://github.com/influxdata/telegraf/pull/12579) `config` Accept durations given in days (e.g. 7d) +- [#12798](https://github.com/influxdata/telegraf/pull/12798) `inputs.cgroup` Added support for cpu.stat +- [#12345](https://github.com/influxdata/telegraf/pull/12345) `inputs.cisco_telemetry_mdt` Include delete field +- [#12696](https://github.com/influxdata/telegraf/pull/12696) `inputs.disk` Add label as tag +- [#12519](https://github.com/influxdata/telegraf/pull/12519) `inputs.dns_query` Add IP field(s) +- [#12775](https://github.com/influxdata/telegraf/pull/12775) `inputs.docker_log` Add state-persistence capabilities +- [#12814](https://github.com/influxdata/telegraf/pull/12814) `inputs.ethtool` Add support for link speed, duplex, etc. +- [#12550](https://github.com/influxdata/telegraf/pull/12550) `inputs.example` Add secret-store sample code +- [#12495](https://github.com/influxdata/telegraf/pull/12495) `inputs.gnmi` Set max gRPC message size +- [#12680](https://github.com/influxdata/telegraf/pull/12680) `inputs.haproxy` Add support for tcp endpoints in haproxy plugin +- [#12645](https://github.com/influxdata/telegraf/pull/12645) `inputs.http_listener_v2` Add custom server http headers +- [#12506](https://github.com/influxdata/telegraf/pull/12506) `inputs.icinga2` Support collecting hosts, services, and endpoint metrics +- [#12493](https://github.com/influxdata/telegraf/pull/12493) `inputs.influxdb` Collect uptime statistics +- [#12452](https://github.com/influxdata/telegraf/pull/12452) `inputs.intel_powerstat` Add CPU base frequency metric and add support for new platforms +- [#12707](https://github.com/influxdata/telegraf/pull/12707) `inputs.internet_speed` Add the best server selection via latency and jitter field +- [#12617](https://github.com/influxdata/telegraf/pull/12617) `inputs.internet_speed` Server ID include and exclude filter +- [#12730](https://github.com/influxdata/telegraf/pull/12730) `inputs.jti_openconfig_telemetry` Set timestamp from data +- [#12786](https://github.com/influxdata/telegraf/pull/12786) `inputs.modbus` Add RS485 specific config options +- [#12408](https://github.com/influxdata/telegraf/pull/12408) `inputs.modbus` Add workaround to enforce reads from zero for coil registers +- [#12825](https://github.com/influxdata/telegraf/pull/12825) `inputs.modbus` Allow to convert coil and discrete registers to boolean +- [#12591](https://github.com/influxdata/telegraf/pull/12591) `inputs.mysql` Add secret-store support +- [#12466](https://github.com/influxdata/telegraf/pull/12466) `inputs.openweathermap` Add snow parameter +- [#12628](https://github.com/influxdata/telegraf/pull/12628) `inputs.processes` Add use_sudo option for BSD +- [#12777](https://github.com/influxdata/telegraf/pull/12777) `inputs.prometheus` Use namespace annotations to filter pods to be scraped +- [#12496](https://github.com/influxdata/telegraf/pull/12496) `inputs.redfish` Add power control metric +- [#12400](https://github.com/influxdata/telegraf/pull/12400) `inputs.sqlserver` Get database pages performance counter +- [#12377](https://github.com/influxdata/telegraf/pull/12377) `inputs.stackdriver` Allow filtering by resource metadata labels +- [#12318](https://github.com/influxdata/telegraf/pull/12318) `inputs.statsd` Add pending messages stat and allow to configure number of threads +- [#12828](https://github.com/influxdata/telegraf/pull/12828) `inputs.vsphere` Flag for more lenient behavior when connect fails on startup +- [#12790](https://github.com/influxdata/telegraf/pull/12790) `inputs.win_eventlog` Add state-persistence capabilities +- [#12556](https://github.com/influxdata/telegraf/pull/12556) `inputs.win_perf_counters` Add remote system support +- [#12729](https://github.com/influxdata/telegraf/pull/12729) `inputs.wireguard` Add allowed_peer_cidr field +- [#12444](https://github.com/influxdata/telegraf/pull/12444) `inputs.x509_cert` Add OCSP stapling information for leaf certificates (#10550) +- [#12656](https://github.com/influxdata/telegraf/pull/12656) `inputs.x509_cert` Add tag for certificate type-classification +- [#12697](https://github.com/influxdata/telegraf/pull/12697) `outputs.mqtt` Add option to specify topic layouts +- [#12678](https://github.com/influxdata/telegraf/pull/12678) `outputs.mqtt` Add support for MQTT 5 publish properties +- [#12224](https://github.com/influxdata/telegraf/pull/12224) `outputs.mqtt` Enhance routing capabilities +- [#11816](https://github.com/influxdata/telegraf/pull/11816) `parsers.avro` Add Apache Avro parser +- [#12820](https://github.com/influxdata/telegraf/pull/12820) `parsers.xpath` Add timezone handling +- [#12767](https://github.com/influxdata/telegraf/pull/12767) `processors.converter` Convert tag or field as metric timestamp +- [#12659](https://github.com/influxdata/telegraf/pull/12659) `processors.unpivot` Add mode to create new metrics +- [#12812](https://github.com/influxdata/telegraf/pull/12812) `secretstores` Add command-line option to specify password +- [#12067](https://github.com/influxdata/telegraf/pull/12067) `secretstores` Add support for additional input plugins +- [#12497](https://github.com/influxdata/telegraf/pull/12497) `secretstores` Convert many output plugins + +### Bugfixes + +- [#12781](https://github.com/influxdata/telegraf/pull/12781) `agent` Allow graceful shutdown on interrupt (e.g. Ctrl-C) +- [#12740](https://github.com/influxdata/telegraf/pull/12740) `agent` Only rotate log on SIGHUP if needed +- [#12818](https://github.com/influxdata/telegraf/pull/12818) `inputs.amqp_consumer` Avoid deprecations when handling defaults +- [#12817](https://github.com/influxdata/telegraf/pull/12817) `inputs.amqp_consumer` Fix panic on Stop() if not connected successfully +- [#12815](https://github.com/influxdata/telegraf/pull/12815) `inputs.ethtool` Close namespace file to prevent crash +- [#12778](https://github.com/influxdata/telegraf/pull/12778) `inputs.statsd` On close, verify listener is not nil + +### Dependency Updates + +- [#12805](https://github.com/influxdata/telegraf/pull/12805) `deps` Bump cloud.google.com/go/storage from 1.28.1 to 1.29.0 +- [#12804](https://github.com/influxdata/telegraf/pull/12804) `deps` Bump github.com/Azure/go-autorest/autorest/adal from 0.9.21 to 0.9.22 +- [#12757](https://github.com/influxdata/telegraf/pull/12757) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go from 1.62.77 to 1.62.193 +- [#12808](https://github.com/influxdata/telegraf/pull/12808) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.13.2 to 1.13.15 +- [#12756](https://github.com/influxdata/telegraf/pull/12756) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.14.5 to 1.16.0 +- [#12754](https://github.com/influxdata/telegraf/pull/12754) `deps` Bump github.com/coocood/freecache from 1.2.2 to 1.2.3 +- [#12852](https://github.com/influxdata/telegraf/pull/12852) `deps` Bump github.com/opencontainers/runc from 1.1.3 to 1.1.4 +- [#12806](https://github.com/influxdata/telegraf/pull/12806) `deps` Bump github.com/opensearch-project/opensearch-go/v2 from 2.1.0 to 2.2.0 +- [#12753](https://github.com/influxdata/telegraf/pull/12753) `deps` Bump github.com/openzipkin-contrib/zipkin-go-opentracing from 0.4.5 to 0.5.0 +- [#12755](https://github.com/influxdata/telegraf/pull/12755) `deps` Bump github.com/rabbitmq/amqp091-go from 1.5.0 to 1.7.0 +- [#12822](https://github.com/influxdata/telegraf/pull/12822) `deps` Bump github.com/shirou/gopsutil from v3.22.12 to v3.23.2 +- [#12807](https://github.com/influxdata/telegraf/pull/12807) `deps` Bump github.com/stretchr/testify from 1.8.1 to 1.8.2 +- [#12840](https://github.com/influxdata/telegraf/pull/12840) `deps` Bump OpenTelemetry from 0.3.1 to 0.3.3 +- [#12801](https://github.com/influxdata/telegraf/pull/12801) `deps` Downgrade github.com/karrick/godirwalk from v1.17.0 to v1.16.2 + +## v1.25.3 [2023-02-27] + +### Bugfixes + +- [#12721](https://github.com/influxdata/telegraf/pull/12721) `agent` Fix reload config on config update/SIGHUP +- [#12462](https://github.com/influxdata/telegraf/pull/12462) `inputs.bond` Reset slave stats for each interface +- [#12677](https://github.com/influxdata/telegraf/pull/12677) `inputs.cloudwatch` Verify endpoint is not nil +- [#12725](https://github.com/influxdata/telegraf/pull/12725) `inputs.lvm` Add options to specify path to binaries +- [#12724](https://github.com/influxdata/telegraf/pull/12724) `parsers.xpath` Fix panic for JSON name expansion +- [#12735](https://github.com/influxdata/telegraf/pull/12735) `serializers.json` Fix stateful transformations + +### Dependency Updates + +- [#12714](https://github.com/influxdata/telegraf/pull/12714) `deps` Bump cloud.google.com/go/pubsub from 1.27.1 to 1.28.0 +- [#12693](https://github.com/influxdata/telegraf/pull/12693) `deps` Bump github.com/containerd/containerd from 1.6.8 to 1.6.18 +- [#12715](https://github.com/influxdata/telegraf/pull/12715) `deps` Bump github.com/go-logfmt/logfmt from 0.5.1 to 0.6.0 +- [#12668](https://github.com/influxdata/telegraf/pull/12668) `deps` Bump github.com/gofrs/uuid from 4.3.1 to 5.0.0 +- [#12712](https://github.com/influxdata/telegraf/pull/12712) `deps` Bump github.com/gophercloud/gophercloud from 1.0.0 to 1.2.0 +- [#12667](https://github.com/influxdata/telegraf/pull/12667) `deps` Bump github.com/pion/dtls/v2 from 2.1.5 to 2.2.4 +- [#12699](https://github.com/influxdata/telegraf/pull/12699) `deps` Bump golang.org/x/net from 0.5.0 to 0.7.0 +- [#12670](https://github.com/influxdata/telegraf/pull/12670) `deps` Bump golang.org/x/sys from 0.4.0 to 0.5.0 +- [#12713](https://github.com/influxdata/telegraf/pull/12713) `deps` Bump google.golang.org/grpc from 1.52.3 to 1.53.0 +- [#12669](https://github.com/influxdata/telegraf/pull/12669) `deps` Bump k8s.io/apimachinery from 0.25.3 to 0.25.6 +- [#12698](https://github.com/influxdata/telegraf/pull/12698) `deps` Bump testcontainers from 0.14.0 to 0.18.0 + +## v1.25.2 [2023-02-13] + +### Bugfixes + +- [#12607](https://github.com/influxdata/telegraf/pull/12607) `agent` Only read the config once +- [#12586](https://github.com/influxdata/telegraf/pull/12586) `docs` Fix link to license for Google flatbuffers +- [#12637](https://github.com/influxdata/telegraf/pull/12637) `inputs.cisco_telemetry_mdt` Check subfield sizes to avoid panics +- [#12657](https://github.com/influxdata/telegraf/pull/12657) `inputs.cloudwatch` Enable custom endpoint support +- [#12603](https://github.com/influxdata/telegraf/pull/12603) `inputs.conntrack` Resolve segfault when setting collect field +- [#12512](https://github.com/influxdata/telegraf/pull/12512) `inputs.gnmi` Handle both new-style `tag_subscription` and old-style `tag_only` +- [#12599](https://github.com/influxdata/telegraf/pull/12599) `inputs.mongodb` Improve error logging +- [#12604](https://github.com/influxdata/telegraf/pull/12604) `inputs.mongodb` SIGSEGV when restarting MongoDB node +- [#12576](https://github.com/influxdata/telegraf/pull/12576) `inputs.mysql` Avoid side-effects for TLS between plugin instances +- [#12626](https://github.com/influxdata/telegraf/pull/12626) `inputs.prometheus` Deprecate and rename the timeout variable +- [#12648](https://github.com/influxdata/telegraf/pull/12648) `inputs.tail` Fix typo in the README +- [#12543](https://github.com/influxdata/telegraf/pull/12543) `inputs.upsd` Add additional fields +- [#12629](https://github.com/influxdata/telegraf/pull/12629) `inputs.x509_cert` Fix Windows path handling +- [#12560](https://github.com/influxdata/telegraf/pull/12560) `outputs.prometheus_client` Expire with ticker, not add/collect +- [#12644](https://github.com/influxdata/telegraf/pull/12644) `secretstores` Check store id format and presence + +### Dependency Updates + +- [#12630](https://github.com/influxdata/telegraf/pull/12630) `deps` Bump cloud.google.com/go/bigquery from 1.44.0 to 1.45.0 +- [#12568](https://github.com/influxdata/telegraf/pull/12568) `deps` Bump github.com/99designs/keyring from 1.2.1 to 1.2.2 +- [#12634](https://github.com/influxdata/telegraf/pull/12634) `deps` Bump github.com/antchfx/xmlquery from 1.3.12 to 1.3.15 +- [#12633](https://github.com/influxdata/telegraf/pull/12633) `deps` Bump github.com/antchfx/xpath from 1.2.2 to 1.2.3 +- [#12571](https://github.com/influxdata/telegraf/pull/12571) `deps` Bump github.com/coreos/go-semver from 0.3.0 to 0.3.1 +- [#12632](https://github.com/influxdata/telegraf/pull/12632) `deps` Bump github.com/moby/ipvs from 1.0.2 to 1.1.0 +- [#12572](https://github.com/influxdata/telegraf/pull/12572) `deps` Bump github.com/multiplay/go-ts3 from 1.0.1 to 1.1.0 +- [#12581](https://github.com/influxdata/telegraf/pull/12581) `deps` Bump github.com/prometheus/client_golang from 1.13.1 to 1.14.0 +- [#12580](https://github.com/influxdata/telegraf/pull/12580) `deps` Bump github.com/shirou/gopsutil from 3.22.9 to 3.22.12 +- [#12570](https://github.com/influxdata/telegraf/pull/12570) `deps` Bump go.mongodb.org/mongo-driver from 1.11.0 to 1.11.1 +- [#12582](https://github.com/influxdata/telegraf/pull/12582) `deps` Bump golang/x dependencies +- [#12583](https://github.com/influxdata/telegraf/pull/12583) `deps` Bump google.golang.org/grpc from 1.51.0 to 1.52.0 +- [#12631](https://github.com/influxdata/telegraf/pull/12631) `deps` Bump google.golang.org/grpc from 1.52.0 to 1.52.3 + +## v1.25.1 [2023-01-30] + +### Bugfixes + +- [#12549](https://github.com/influxdata/telegraf/pull/12549) `agent` Catch non-existing commands and error out +- [#12453](https://github.com/influxdata/telegraf/pull/12453) `agent` Correctly reload configuration files +- [#12491](https://github.com/influxdata/telegraf/pull/12491) `agent` Handle float time with fractions of seconds correctly +- [#12457](https://github.com/influxdata/telegraf/pull/12457) `agent` Only set default snmp after reading all configs +- [#12515](https://github.com/influxdata/telegraf/pull/12515) `common.cookie` Allow any 2xx status code +- [#12459](https://github.com/influxdata/telegraf/pull/12459) `common.kafka` Add keep-alive period setting for input and output +- [#12240](https://github.com/influxdata/telegraf/pull/12240) `inputs.cisco_telemetry_mdt` Add operation-metric and class-policy prefix +- [#12533](https://github.com/influxdata/telegraf/pull/12533) `inputs.exec` Restore pre-v1.21 behavior for CSV data_format +- [#12415](https://github.com/influxdata/telegraf/pull/12415) `inputs.gnmi` Update configuration documentation +- [#12536](https://github.com/influxdata/telegraf/pull/12536) `inputs.logstash` Collect opensearch specific stats +- [#12409](https://github.com/influxdata/telegraf/pull/12409) `inputs.mysql` Revert slice declarations with non-zero initial length +- [#12529](https://github.com/influxdata/telegraf/pull/12529) `inputs.opcua` Fix opcua and opcua-listener for servers using password-based auth +- [#12522](https://github.com/influxdata/telegraf/pull/12522) `inputs.prometheus` Correctly track deleted pods +- [#12559](https://github.com/influxdata/telegraf/pull/12559) `inputs.prometheus` Set the timeout for slow running API endpoints correctly +- [#12384](https://github.com/influxdata/telegraf/pull/12384) `inputs.sqlserver` Add more precise version check +- [#12387](https://github.com/influxdata/telegraf/pull/12387) `inputs.sqlserver` Added own SPID filter +- [#12386](https://github.com/influxdata/telegraf/pull/12386) `inputs.sqlserver` SqlRequests include sleeping sessions with open transactions +- [#12528](https://github.com/influxdata/telegraf/pull/12528) `inputs.sqlserver` Suppress error on secondary replicas +- [#12516](https://github.com/influxdata/telegraf/pull/12516) `inputs.upsd` Always convert to float +- [#12486](https://github.com/influxdata/telegraf/pull/12486) `inputs.upsd` Ensure firmware is always a string +- [#12375](https://github.com/influxdata/telegraf/pull/12375) `inputs.win_eventlog` Handle remote events more robustly +- [#12404](https://github.com/influxdata/telegraf/pull/12404) `inputs.x509_cert` Fix off-by-one when adding intermediate certificates +- [#12399](https://github.com/influxdata/telegraf/pull/12399) `outputs.loki` Return response body on error +- [#12440](https://github.com/influxdata/telegraf/pull/12440) `parsers.json_v2` In case of invalid json, log message to debug log +- [#12401](https://github.com/influxdata/telegraf/pull/12401) `secretstores` Cleanup duplicate printing +- [#12468](https://github.com/influxdata/telegraf/pull/12468) `secretstores` Fix handling of "id" and print failing secret-store +- [#12490](https://github.com/influxdata/telegraf/pull/12490) `secretstores` Fix handling of TOML strings + +### Dependency Updates + +- [#12385](https://github.com/influxdata/telegraf/pull/12385) `deps` Bump cloud.google.com/go/storage from 1.23.0 to 1.28.1 +- [#12511](https://github.com/influxdata/telegraf/pull/12511) `deps` Bump github.com/antchfx/jsonquery from 1.3.0 to 1.3.1 +- [#12420](https://github.com/influxdata/telegraf/pull/12420) `deps` Bump github.com/aws/aws-sdk-go-v2 from 1.17.1 to 1.17.3 +- [#12538](https://github.com/influxdata/telegraf/pull/12538) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.54.4 to 1.80.1 +- [#12476](https://github.com/influxdata/telegraf/pull/12476) `deps` Bump github.com/denisenkom/go-mssqldb from 0.12.0 to 0.12.3 +- [#12378](https://github.com/influxdata/telegraf/pull/12378) `deps` Bump github.com/eclipse/paho.mqtt.golang from 1.4.1 to 1.4.2 +- [#12381](https://github.com/influxdata/telegraf/pull/12381) `deps` Bump github.com/hashicorp/consul/api from 1.15.2 to 1.18.0 +- [#12417](https://github.com/influxdata/telegraf/pull/12417) `deps` Bump github.com/karrick/godirwalk from 1.16.1 to 1.17.0 +- [#12418](https://github.com/influxdata/telegraf/pull/12418) `deps` Bump github.com/kardianos/service from 1.2.1 to 1.2.2 +- [#12379](https://github.com/influxdata/telegraf/pull/12379) `deps` Bump github.com/nats-io/nats-server/v2 from 2.9.4 to 2.9.9 + +## v1.25.0 [2022-12-12] + +### New Plugins + +- [#10103](https://github.com/influxdata/telegraf/pull/10103) `inputs.azure_monitor` Azure Monitor +- [#8413](https://github.com/influxdata/telegraf/pull/8413) `inputs.gcs` Google Cloud Storage +- [#11824](https://github.com/influxdata/telegraf/pull/11824) `inputs.intel_dlb` Intel DLB +- [#11814](https://github.com/influxdata/telegraf/pull/11814) `inputs.libvirt` libvirt +- [#12108](https://github.com/influxdata/telegraf/pull/12108) `inputs.netflow` netflow v5, v9, and IPFIX +- [#11786](https://github.com/influxdata/telegraf/pull/11786) `inputs.opcua_listener` OPC UA Event subscriptions + +### Features + +- [#12130](https://github.com/influxdata/telegraf/pull/12130) Add arm64 Windows builds to nightly and CI +- [#11987](https://github.com/influxdata/telegraf/pull/11987) `agent` Add method to inform of deprecated plugin option values +- [#11232](https://github.com/influxdata/telegraf/pull/11232) `agent` Secret-store implementation +- [#12358](https://github.com/influxdata/telegraf/pull/12358) `agent` Deprecate active usage of netsnmp translator +- [#12302](https://github.com/influxdata/telegraf/pull/12302) `agent.tls` Allow setting renegotiation method +- [#12111](https://github.com/influxdata/telegraf/pull/12111) `common.kafka` Add exponential backoff when connecting or reconnecting and allow plugin to start without making initial connection +- [#11860](https://github.com/influxdata/telegraf/pull/11860) `inputs.amqp_consumer` Determine content encoding automatically +- [#12014](https://github.com/influxdata/telegraf/pull/12014) `inputs.apcupsd` Add new fields +- [#12342](https://github.com/influxdata/telegraf/pull/12342) `inputs.cgroups` Do not abort on first error, print message once +- [#8958](https://github.com/influxdata/telegraf/pull/8958) `inputs.conntrack` Parse conntrack stats +- [#11703](https://github.com/influxdata/telegraf/pull/11703) `inputs.diskio` Allow selecting devices by ID +- [#11895](https://github.com/influxdata/telegraf/pull/11895) `inputs.ethtool` Gather statistics from namespaces +- [#12087](https://github.com/influxdata/telegraf/pull/12087) `inputs.ethtool` Possibility to skip gathering metrics for downed interfaces +- [#12324](https://github.com/influxdata/telegraf/pull/12324) `inputs.http_response` Add User-Agent header +- [#12304](https://github.com/influxdata/telegraf/pull/12304) `inputs.kafka_consumer` Add sarama debug logs +- [#11783](https://github.com/influxdata/telegraf/pull/11783) `inputs.knx_listener` Support TCP as transport protocol +- [#12301](https://github.com/influxdata/telegraf/pull/12301) `inputs.kubernetes` Allow fetching kublet metrics remotely + +- [#12255](https://github.com/influxdata/telegraf/pull/12255) `inputs.modbus` Add 8-bit integer types +- [#11983](https://github.com/influxdata/telegraf/pull/11983) `inputs.modbus` Add config option to pause after connect +- [#12340](https://github.com/influxdata/telegraf/pull/12340) `inputs.modbus` Add support for half-precision float (float16) +- [#11106](https://github.com/influxdata/telegraf/pull/11106) `inputs.modbus` Optimize grouped requests +- [#11273](https://github.com/influxdata/telegraf/pull/11273) `inputs.modbus` Optimize requests +- [#11630](https://github.com/influxdata/telegraf/pull/11630) `inputs.opcua` Add use regular reads workaround +- [#9633](https://github.com/influxdata/telegraf/pull/9633) `inputs.powerdns_recursor` Support for new PowerDNS recursor control protocol +- [#12050](https://github.com/influxdata/telegraf/pull/12050) `inputs.prometheus` Add support for custom header +- [#11962](https://github.com/influxdata/telegraf/pull/11962) `inputs.prometheus` Allow explicit scrape configuration without annotations +- [#11729](https://github.com/influxdata/telegraf/pull/11729) `inputs.prometheus` Use system wide proxy settings +- [#12329](https://github.com/influxdata/telegraf/pull/12329) `inputs.smart` Add additional SMART metrics that indicate/predict device failure +- [#11872](https://github.com/influxdata/telegraf/pull/11872) `inputs.snmp` Convert enum values +- [#12187](https://github.com/influxdata/telegraf/pull/12187) `inputs.socket_ listener` Allow to specify message separator for streams +- [#12351](https://github.com/influxdata/telegraf/pull/12351) `inputs.sqlserver` Add @@SERVICENAME and SERVERPROPERTY(IsClustered) in measurement sqlserver_server_properties +- [#12126](https://github.com/influxdata/telegraf/pull/12126) `inputs.sqlserver` Add data and log used space metrics for Azure SQL DB +- [#12292](https://github.com/influxdata/telegraf/pull/12292) `inputs.sqlserver` Add metric available_physical_memory_kb in sqlserver_server_properties +- [#12319](https://github.com/influxdata/telegraf/pull/12319) `inputs.sqlserver` Introduce timeout for query execution +- [#12147](https://github.com/influxdata/telegraf/pull/12147) `inputs.system` Collect unique user count logged in +- [#12281](https://github.com/influxdata/telegraf/pull/12281) `inputs.tail` Add option to preserve newlines for multiline data +- [#11762](https://github.com/influxdata/telegraf/pull/11762) `inputs.tail` Allow handling of quoted strings spanning multiple lines +- [#12170](https://github.com/influxdata/telegraf/pull/12170) `inputs.tomcat` Add source tag +- [#11874](https://github.com/influxdata/telegraf/pull/11874) `outputs.azure_data_explorer` Add support for streaming ingestion for ADX output plugin +- [#11991](https://github.com/influxdata/telegraf/pull/11991) `outputs.event_hubs` Expose max message size batch option +- [#11950](https://github.com/influxdata/telegraf/pull/11950) `outputs.graylog` Implement optional connection retries +- [#11385](https://github.com/influxdata/telegraf/pull/11385) `outputs.timestream` Support ingesting multi-measures +- [#12232](https://github.com/influxdata/telegraf/pull/12232) `parsers.binary` Handle hex-encoded inputs +- [#12008](https://github.com/influxdata/telegraf/pull/12008) `parsers.csv` Add option for overwrite tags +- [#12247](https://github.com/influxdata/telegraf/pull/12247) `parsers.csv` Support null delimiters +- [#12320](https://github.com/influxdata/telegraf/pull/12320) `parsers.grok` Add option to allow multiline messages +- [#11933](https://github.com/influxdata/telegraf/pull/11933) `parsers.xpath` Add option to skip (header) bytes +- [#11999](https://github.com/influxdata/telegraf/pull/11999) `parsers.xpath` Allow to specify byte-array fields to encode in HEX +- [#11552](https://github.com/influxdata/telegraf/pull/11552) `parsers` Add binary parser +- [#12260](https://github.com/influxdata/telegraf/pull/12260) `serializers.json` Support serializing JSON nested in string fields + +### Bugfixes + +- [#12113](https://github.com/influxdata/telegraf/pull/12113) `agent` Run processors in config order +- [#12127](https://github.com/influxdata/telegraf/pull/12127) `agent` Watch for changes in configuration files in config directories +- [#12062](https://github.com/influxdata/telegraf/pull/12062) `inputs.conntrack` Skip gather tests if conntrack kernel module is not loaded +- [#12295](https://github.com/influxdata/telegraf/pull/12295) `inputs.filecount` Revert library version +- [#12284](https://github.com/influxdata/telegraf/pull/12284) `inputs.kube_inventory` Change default token path, use in-cluster config by default +- [#12235](https://github.com/influxdata/telegraf/pull/12235) `inputs.modbus` Add workaround to read field in separate requests +- [#12339](https://github.com/influxdata/telegraf/pull/12339) `inputs.modbus` Fix Windows COM-port path +- [#12367](https://github.com/influxdata/telegraf/pull/12367) `inputs.modbus` Fix default value of transmission mode +- [#12330](https://github.com/influxdata/telegraf/pull/12330) `inputs.mongodb` Fix connection leak triggered by config reload +- [#12101](https://github.com/influxdata/telegraf/pull/12101) `inputs.opcua` Add support for opcua datetime values +- [#12376](https://github.com/influxdata/telegraf/pull/12376) `inputs.opcua` Parse full range of status codes with uint32 +- [#12278](https://github.com/influxdata/telegraf/pull/12278) `inputs.promethes` Respect selectors when scraping pods +- [#12323](https://github.com/influxdata/telegraf/pull/12323) `inputs.sql` Cast measurement_column to string +- [#12259](https://github.com/influxdata/telegraf/pull/12259) `inputs.vsphere` Eliminated duplicate samples +- [#12307](https://github.com/influxdata/telegraf/pull/12307) `inputs.zfs` Unbreak datasets stats gathering in case listsnaps is enabled on a zfs pool +- [#12291](https://github.com/influxdata/telegraf/pull/12291) `outputs.azure_data_explorer` Update test call to NewSerializer +- [#12357](https://github.com/influxdata/telegraf/pull/12357) `processors.parser` Handle empty metric names correctly + +### Dependency Updates + +- [#12334](https://github.com/influxdata/telegraf/pull/12334) `deps` Update github.com/aliyun/alibaba-cloud-sdk-go from 1.61.1836 to 1.62.77 +- [#12355](https://github.com/influxdata/telegraf/pull/12355) `deps` Update github.com/gosnmp/gosnmp from 1.34.0 to 1.35.0 +- [#12372](https://github.com/influxdata/telegraf/pull/12372) `deps` Update OpenTelemetry from 0.2.30 to 0.2.33 + +## v1.24.4 [2022-11-29] + +### Bugfixes + +- [#12177](https://github.com/influxdata/telegraf/pull/12177) `inputs.cloudwatch` Correctly handle multiple namespaces +- [#12294](https://github.com/influxdata/telegraf/pull/12294) `inputs.directory_monitor` Close input file before removal +- [#12140](https://github.com/influxdata/telegraf/pull/12140) `inputs.gnmi` Handle decimal_val as per gnmi v0.8.0 +- [#12275](https://github.com/influxdata/telegraf/pull/12275) `inputs.gnmi` Do not provide empty prefix for subscription request +- [#12258](https://github.com/influxdata/telegraf/pull/12258) `inputs.gnmi` Fix empty name for Sonic devices +- [#12171](https://github.com/influxdata/telegraf/pull/12171) `inputs.ping` Avoid -x/-X on FreeBSD 13 and newer with ping6 +- [#12282](https://github.com/influxdata/telegraf/pull/12282) `inputs.prometheus` Correctly default to port 9102 +- [#12229](https://github.com/influxdata/telegraf/pull/12229) `input.redis_sentinel` Fix sentinel and replica stats gathering +- [#12280](https://github.com/influxdata/telegraf/pull/12280) `inputs.socket_listener` Ensure closed connection +- [#12201](https://github.com/influxdata/telegraf/pull/12201) `output.datadog` Log response in case of non 2XX response from API +- [#12160](https://github.com/influxdata/telegraf/pull/12160) `outputs.prometheus` Expire metrics correctly during adds +- [#12156](https://github.com/influxdata/telegraf/pull/12156) `outputs.yandex_cloud_monitoring` Catch int64 values + +### Dependency Updates + +- [#12132](https://github.com/influxdata/telegraf/pull/12132) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go from 1.61.1818 to 1.61.1836 +- [#12197](https://github.com/influxdata/telegraf/pull/12197) `deps` Bump github.com/prometheus/client_golang from 1.13.0 to 1.13.1 +- [#12196](https://github.com/influxdata/telegraf/pull/12196) `deps` Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.13.12 to 1.14.5 +- [#12198](https://github.com/influxdata/telegraf/pull/12198) `deps` Bump github.com/aws/aws-sdk-go-v2/feature/ec2/imds from 1.12.17 to 1.12.19 +- [#12236](https://github.com/influxdata/telegraf/pull/12236) `deps` Bump github.com/gofrs/uuid from v4.3.0 to v4.3.1 +- [#12237](https://github.com/influxdata/telegraf/pull/12237) `deps` Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.16.19 to 1.17.2 +- [#12238](https://github.com/influxdata/telegraf/pull/12238) `deps` Bump github.com/urfave/cli/v2 from 2.16.3 to 2.23.5 +- [#12239](https://github.com/influxdata/telegraf/pull/12239) `deps` Bump github.com/Azure/azure-event-hubs-go/v3 from 3.3.18 to 3.3.20 +- [#12248](https://github.com/influxdata/telegraf/pull/12248) `deps` Bump github.com/showwin/speedtest-go from 1.1.5 to 1.2.1 +- [#12269](https://github.com/influxdata/telegraf/pull/12269) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.12.21 to 1.13.2 +- [#12268](https://github.com/influxdata/telegraf/pull/12268) `deps` Bump github.com/yuin/goldmark from 1.5.2 to 1.5.3 +- [#12267](https://github.com/influxdata/telegraf/pull/12267) `deps` Bump cloud.google.com/go/pubsub from 1.25.1 to 1.26.0 +- [#12266](https://github.com/influxdata/telegraf/pull/12266) `deps` Bump go.mongodb.org/mongo-driver from 1.10.2 to 1.11.0 + +## v1.24.3 [2022-11-02] + +### Bugfixes + +- [#12063](https://github.com/influxdata/telegraf/pull/12063) Restore warning on unused config option(s) +- [#11941](https://github.com/influxdata/telegraf/pull/11941) Setting `enable_tls` has incorrect default value +- [#12093](https://github.com/influxdata/telegraf/pull/12093) Update systemd unit description +- [#12077](https://github.com/influxdata/telegraf/pull/12077) `agent` Fix panic due to tickers slice was off-by-one in size +- [#12076](https://github.com/influxdata/telegraf/pull/12076) `config` Set default parser +- [#12124](https://github.com/influxdata/telegraf/pull/12124) `inputs.directory_monitor` Allow cross filesystem directories +- [#12064](https://github.com/influxdata/telegraf/pull/12064) `inputs.kafka` Switch to sarama's new consumer group rebalance strategy setting +- [#12038](https://github.com/influxdata/telegraf/pull/12038) `inputs.modbus` Add slave id to failing connection +- [#12109](https://github.com/influxdata/telegraf/pull/12109) `inputs.modbus` Handle field-measurement definitions correctly on duplicate field check +- [#11912](https://github.com/influxdata/telegraf/pull/11912) `inputs.modbus` Improve duplicate field checks +- [#11993](https://github.com/influxdata/telegraf/pull/11993) `inputs.opcua` Add metric tags to node +- [#11997](https://github.com/influxdata/telegraf/pull/11997) `inputs.syslog` Print error when no error or message given +- [#12023](https://github.com/influxdata/telegraf/pull/12023) `inputs.zookeeper` Add the ability to parse floats as floats +- [#11926](https://github.com/influxdata/telegraf/pull/11926) `parsers.json_v2` Remove BOM before parsing +- [#12116](https://github.com/influxdata/telegraf/pull/12116) `processors.parser` Keep name of original metric if parser doesn't return one +- [#12081](https://github.com/influxdata/telegraf/pull/12081) `processors` Correctly setup processors +- [#12016](https://github.com/influxdata/telegraf/pull/12016) `regression` Fixes problem with metrics not exposed by plugins. +- [#12024](https://github.com/influxdata/telegraf/pull/12024) `serializers.splunkmetric` Provide option to remove event metric tag + +### Features + +- [#12075](https://github.com/influxdata/telegraf/pull/12075) `tools` Allow to markdown includes for sections + +### Dependency Updates + +- [#11886](https://github.com/influxdata/telegraf/pull/11886) `deps` Bump github.com/snowflakedb/gosnowflake from 1.6.2 to 1.6.13 +- [#11928](https://github.com/influxdata/telegraf/pull/11928) `deps` Bump github.com/sensu/sensu-go/api/core/v2 from 2.14.0 to 2.15.0 +- [#11935](https://github.com/influxdata/telegraf/pull/11935) `deps` Bump github.com/gofrs/uuid from 4.2.0& to 4.3.0 +- [#11894](https://github.com/influxdata/telegraf/pull/11894) `deps` Bump github.com/hashicorp/consul/api from 1.14.0 to 1.15.2 +- [#11936](https://github.com/influxdata/telegraf/pull/11936) `deps` Bump github.com/aws/aws-sdk-go-v2/credentials from 1.12.5 to 1.12.21 +- [#11972](https://github.com/influxdata/telegraf/pull/11972) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch +- [#11979](https://github.com/influxdata/telegraf/pull/11979) `deps` Bump github.com/aws/aws-sdk-go-v2/config +- [#11938](https://github.com/influxdata/telegraf/pull/11938) `deps` Bump k8s.io/apimachinery from 0.25.1 to 0.25.2 +- [#12001](https://github.com/influxdata/telegraf/pull/12001) `deps` Bump k8s.io/api from 0.25.0 to 0.25.2 +- [#12029](https://github.com/influxdata/telegraf/pull/12029) `deps` Bump k8s.io/api from 0.25.2 to 0.25.3 +- [#12030](https://github.com/influxdata/telegraf/pull/12030) `deps` Bump modernc.org/sqlite from 1.17.3 to 1.19.2 +- [#12034](https://github.com/influxdata/telegraf/pull/12034) `deps` Bump github.com/signalfx/golib/v3 from 3.3.45 to 3.3.46 +- [#12035](https://github.com/influxdata/telegraf/pull/12035) `deps` Bump github.com/yuin/goldmark from 1.4.13 to 1.5.2 +- [#11937](https://github.com/influxdata/telegraf/pull/11937) `deps` Bump cloud.google.com/go/bigquery from 1.40.0 to 1.42.0 +- [#12037](https://github.com/influxdata/telegraf/pull/12037) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis +- [#12036](https://github.com/influxdata/telegraf/pull/12036) `deps` Bump github.com/aliyun/alibaba-cloud-sdk-go +- [#11980](https://github.com/influxdata/telegraf/pull/11980) `deps` Bump github.com/Shopify/sarama from 1.36.0 to 1.37.2 +- [#12039](https://github.com/influxdata/telegraf/pull/12039) `deps` Bump testcontainers-go from 0.13.0 to 0.14.0 and address breaking change +- [#12090](https://github.com/influxdata/telegraf/pull/12090) `deps` Bump modernc.org/libc from v1.20.3 to v1.21.2 +- [#12098](https://github.com/influxdata/telegraf/pull/12098) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb +- [#12096](https://github.com/influxdata/telegraf/pull/12096) `deps` Bump google.golang.org/api from 0.95.0 to 0.100.0 +- [#12095](https://github.com/influxdata/telegraf/pull/12095) `deps` Bump github.com/gopcua/opcua from 0.3.3 to 0.3.7 +- [#12097](https://github.com/influxdata/telegraf/pull/12097) `deps` Bump github.com/prometheus/client_model from 0.2.0 to 0.3.0 +- [#12135](https://github.com/influxdata/telegraf/pull/12135) `deps` Bump cloud.google.com/go/monitoring from 1.5.0 to 1.7.0 +- [#12134](https://github.com/influxdata/telegraf/pull/12134) `deps` Bump github.com/nats-io/nats-server/v2 from 2.8.4 to 2.9.4 + +## v1.24.2 [2022-10-03] + +### Bugfixes + +- [#11806](https://github.com/influxdata/telegraf/pull/11806) Re-allow specifying the influx parser type +- [#11896](https://github.com/influxdata/telegraf/pull/11896) `cli` Support old style of filtering sample configs +- [#11519](https://github.com/influxdata/telegraf/pull/11519) `common.kafka` Enable TLS in Kafka plugins without custom config +- [#11866](https://github.com/influxdata/telegraf/pull/11866) `inputs.influxdb_listener` Error on invalid precision +- [#11877](https://github.com/influxdata/telegraf/pull/11877) `inputs.internet_speed` Rename enable_file_download to match upstream intent +- [#11849](https://github.com/influxdata/telegraf/pull/11849) `inputs.mongodb` Start plugin correctly +- [#10696](https://github.com/influxdata/telegraf/pull/10696) `inputs.mqtt_consumer` Rework connection and message tracking +- [#11696](https://github.com/influxdata/telegraf/pull/11696) `internal.ethtool` Avoid internal name conflict with aws +- [#11875](https://github.com/influxdata/telegraf/pull/11875) `parser.xpath` Handle floating-point times correctly + +### Dependency Updates + +- [#11861](https://github.com/influxdata/telegraf/pull/11861) Update dependencies for OpenBSD support +- [#11840](https://github.com/influxdata/telegraf/pull/11840) `deps` Bump k8s.io/apimachinery from 0.25.0 to 0.25.1 +- [#11844](https://github.com/influxdata/telegraf/pull/11844) `deps` Bump github.com/aerospike/aerospike-client-go/v5 from 5.9.0 to 5.10.0 +- [#11839](https://github.com/influxdata/telegraf/pull/11839) `deps` Bump github.com/nats-io/nats.go from 1.16.0 to 1.17.0 +- [#11836](https://github.com/influxdata/telegraf/pull/11836) `deps` Replace go-ping by pro-bing +- [#11887](https://github.com/influxdata/telegraf/pull/11887) `deps` Bump go.mongodb.org/mongo-driver from 1.10.1 to 1.10.2 +- [#11890](https://github.com/influxdata/telegraf/pull/11890) `deps` Bump github.com/aws/smithy-go from 1.13.2 to 1.13.3 +- [#11891](https://github.com/influxdata/telegraf/pull/11891) `deps` Bump github.com/rabbitmq/amqp091-go from 1.4.0 to 1.5.0 +- [#11893](https://github.com/influxdata/telegraf/pull/11893) `deps` Bump github.com/docker/distribution from v2.7.1 to v2.8.1 + +## v1.24.1 [2022-09-19] + +### Bugfixes + +- [#11787](https://github.com/influxdata/telegraf/pull/11787) Clear error message when provided config is not a text file +- [#11835](https://github.com/influxdata/telegraf/pull/11835) Enable global confirmation for installing mingw +- [#10797](https://github.com/influxdata/telegraf/pull/10797) `inputs.ceph` Modernize Ceph input plugin metrics +- [#11785](https://github.com/influxdata/telegraf/pull/11785) `inputs.modbus` Do not fail if a single slave reports errors +- [#11827](https://github.com/influxdata/telegraf/pull/11827) `inputs.ntpq` Handle pools with "-" when +- [#11825](https://github.com/influxdata/telegraf/pull/11825) `parsers.csv` Remove direct checks for the parser type +- [#11781](https://github.com/influxdata/telegraf/pull/11781) `parsers.xpath` Add array index when expanding names. +- [#11815](https://github.com/influxdata/telegraf/pull/11815) `parsers` Memory leak for plugins using ParserFunc. +- [#11826](https://github.com/influxdata/telegraf/pull/11826) `parsers` Unwrap parser and remove some special handling + +### Features + +- [#11228](https://github.com/influxdata/telegraf/pull/11228) `processors.parser` Add option to parse tags + +### Dependency Updates + +- [#11788](https://github.com/influxdata/telegraf/pull/11788) `deps` Bump cloud.google.com/go/pubsub from 1.24.0 to 1.25.1 +- [#11794](https://github.com/influxdata/telegraf/pull/11794) `deps` Bump github.com/urfave/cli/v2 from 2.14.1 to 2.16.3 +- [#11789](https://github.com/influxdata/telegraf/pull/11789) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 +- [#11799](https://github.com/influxdata/telegraf/pull/11799) `deps` Bump github.com/wavefronthq/wavefront-sdk-go +- [#11796](https://github.com/influxdata/telegraf/pull/11796) `deps` Bump cloud.google.com/go/bigquery from 1.33.0 to 1.40.0 + +## v1.24.0 [2022-09-12] + +### Bugfixes + +- [#11779](https://github.com/influxdata/telegraf/pull/11779) Add missing entry json_transformation to missingTomlField +- [#11288](https://github.com/influxdata/telegraf/pull/11288) Add reset-mode flag for CSV parser +- [#11512](https://github.com/influxdata/telegraf/pull/11512) Add version number to MacOS packages +- [#11489](https://github.com/influxdata/telegraf/pull/11489) Backport sync sample.conf and README.md files +- [#11777](https://github.com/influxdata/telegraf/pull/11777) Do not error out for parsing errors in datadog mode +- [#11521](https://github.com/influxdata/telegraf/pull/11521) Make docs & go.mod cleanup post-redis merge +- [#11656](https://github.com/influxdata/telegraf/pull/11656) Refactor telegraf version +- [#11563](https://github.com/influxdata/telegraf/pull/11563) Remove shell execution for license-checker +- [#11755](https://github.com/influxdata/telegraf/pull/11755) Sort labels in prometheusremotewrite serializer +- [#11440](https://github.com/influxdata/telegraf/pull/11440) Update prometheus parser to be a new style parser plugin +- [#11456](https://github.com/influxdata/telegraf/pull/11456) Update prometheusremotewrite parser to be a new style parser plugin +- [#10570](https://github.com/influxdata/telegraf/pull/10570) Use os-agnositc systemd detection, remove sysv in RPM packaging +- [#11615](https://github.com/influxdata/telegraf/pull/11615) `agent` Add flushBatch method +- [#11692](https://github.com/influxdata/telegraf/pull/11692) `inputs.jolokia2` Add optional origin header +- [#11629](https://github.com/influxdata/telegraf/pull/11629) `inputs.mongodb` Add an option to bypass connection errors on start +- [#11723](https://github.com/influxdata/telegraf/pull/11723) `inputs.opcua` Assign node id correctly +- [#11673](https://github.com/influxdata/telegraf/pull/11673) `inputs.prometheus` Plugin run outside k8s cluster error +- [#11701](https://github.com/influxdata/telegraf/pull/11701) `inputs.sqlserver` Fixing wrong filtering for sqlAzureMIRequests and sqlAzureDBRequests +- [#11471](https://github.com/influxdata/telegraf/pull/11471) `inputs.upsd` Move to new sample.conf style +- [#11613](https://github.com/influxdata/telegraf/pull/11613) `inputs.x509` Multiple sources with non-overlapping DNS entries +- [#11767](https://github.com/influxdata/telegraf/pull/11767) `outputs.execd` Fixing the execd behavior to not throw error when partially unserializable metrics are written +- [#11560](https://github.com/influxdata/telegraf/pull/11560) `outputs.wavefront` Update wavefront sdk and use non-deprecated APIs + +### Features + +- [#11307](https://github.com/influxdata/telegraf/pull/11307) `serializers.csv` Add CSV serializer +- [#11054](https://github.com/influxdata/telegraf/pull/11054) `outputs.redistimeseries` Add RedisTimeSeries plugin +- [#7995](https://github.com/influxdata/telegraf/pull/7995) `outputs.stomp` Add Stomp (Active MQ) output plugin +- [#11300](https://github.com/influxdata/telegraf/pull/11300) Add default appType as config option to groundwork output +- [#11398](https://github.com/influxdata/telegraf/pull/11398) Add license checking tool +- [#11399](https://github.com/influxdata/telegraf/pull/11399) Add proxy support for outputs/cloudwatch +- [#11516](https://github.com/influxdata/telegraf/pull/11516) Added metrics for member and replica-set avg health of MongoDB +- [#11233](https://github.com/influxdata/telegraf/pull/11233) Adding aws metric streams input plugin +- [#9717](https://github.com/influxdata/telegraf/pull/9717) Allow collecting node-level metrics for Couchbase buckets +- [#11282](https://github.com/influxdata/telegraf/pull/11282) Make the command config a subcommand +- [#11367](https://github.com/influxdata/telegraf/pull/11367) Migrate collectd parser to new style +- [#11371](https://github.com/influxdata/telegraf/pull/11371) Migrate dropwizard parser to new style +- [#11381](https://github.com/influxdata/telegraf/pull/11381) Migrate form_urlencoded parser to new style +- [#11405](https://github.com/influxdata/telegraf/pull/11405) Migrate graphite parser to new style +- [#11408](https://github.com/influxdata/telegraf/pull/11408) Migrate grok to new parser style +- [#11432](https://github.com/influxdata/telegraf/pull/11432) Migrate influx and influx_upstream parsers to new style +- [#11226](https://github.com/influxdata/telegraf/pull/11226) Migrate json parser to new style +- [#11343](https://github.com/influxdata/telegraf/pull/11343) Migrate json_v2 parser to new style +- [#11366](https://github.com/influxdata/telegraf/pull/11366) Migrate logfmt parser to new style +- [#11402](https://github.com/influxdata/telegraf/pull/11402) Migrate nagios parser to new style +- [#11700](https://github.com/influxdata/telegraf/pull/11700) Migrate to urfave/cli +- [#11407](https://github.com/influxdata/telegraf/pull/11407) Migrate value parser to new style +- [#11374](https://github.com/influxdata/telegraf/pull/11374) Migrate wavefront parser to new style +- [#11373](https://github.com/influxdata/telegraf/pull/11373) `inputs.nats_consumer` Add simple support for jetstream subjects +- [#9015](https://github.com/influxdata/telegraf/pull/9015) `inputs.supervisor` Add Supervisord input plugin +- [#11524](https://github.com/influxdata/telegraf/pull/11524) Tool to build custom Telegraf builds +- [#11493](https://github.com/influxdata/telegraf/pull/11493) `common.tls` Implement minimum TLS version for clients +- [#11619](https://github.com/influxdata/telegraf/pull/11619) `external` Add nsdp external plugin +- [#9890](https://github.com/influxdata/telegraf/pull/9890) `inputs.upsd` Add upsd implementation +- [#11458](https://github.com/influxdata/telegraf/pull/11458) `inputs.cisco_telemetry_mdt` Add GRPC Keepalive/timeout config options +- [#11784](https://github.com/influxdata/telegraf/pull/11784) `inputs.directory_monitor` Support paths for files_to_ignore and files_to_monitor +- [#11773](https://github.com/influxdata/telegraf/pull/11773) `inputs.directory_monitor` Traverse sub-directories +- [#11220](https://github.com/influxdata/telegraf/pull/11220) `inputs.kafka_consumer` Option to set default fetch message bytes +- [#8988](https://github.com/influxdata/telegraf/pull/8988) `inputs.linux_cpu` Add plugin to collect CPU metrics on Linux +- [#9185](https://github.com/influxdata/telegraf/pull/9185) `inputs.logstash` Record number of failures +- [#11469](https://github.com/influxdata/telegraf/pull/11469) `inputs.modbus` Error out on requests with no fields defined +- [#11426](https://github.com/influxdata/telegraf/pull/11426) `inputs.mqtt_consumer` Add incoming mqtt message size calculation +- [#10874](https://github.com/influxdata/telegraf/pull/10874) `inputs.nginx_plus_api` Gather limit_reqs metrics +- [#11593](https://github.com/influxdata/telegraf/pull/11593) `inputs.ntpq` Add option to specify command flags +- [#11592](https://github.com/influxdata/telegraf/pull/11592) `inputs.ntpq` Add possibility to query remote servers +- [#11594](https://github.com/influxdata/telegraf/pull/11594) `inputs.ntpq` Allow to specify `reach` output format +- [#11572](https://github.com/influxdata/telegraf/pull/11572) `inputs.openstack` Add allow_reauth config option for openstack client +- [#11391](https://github.com/influxdata/telegraf/pull/11391) `inputs.smart` Collect SSD endurance information where available in smartctl +- [#11688](https://github.com/influxdata/telegraf/pull/11688) `inputs.sqlserver` Add db name to io stats for MI +- [#11709](https://github.com/influxdata/telegraf/pull/11709) `inputs.sqlserver` Improved filtering for active requests +- [#11518](https://github.com/influxdata/telegraf/pull/11518) `inputs.statsd` Add median timing calculation to statsd input plugin +- [#9440](https://github.com/influxdata/telegraf/pull/9440) `inputs.syslog` Log remote host as source tag +- [#11271](https://github.com/influxdata/telegraf/pull/11271) `inputs.x509_cert` Add smtp protocol +- [#11284](https://github.com/influxdata/telegraf/pull/11284) `output.mqtt` Add support for MQTT protocol version 5 +- [#11649](https://github.com/influxdata/telegraf/pull/11649) `outputs.amqp` Add proxy support +- [#11439](https://github.com/influxdata/telegraf/pull/11439) `outputs.graphite` Retry connecting to servers with failed send attempts +- [#11443](https://github.com/influxdata/telegraf/pull/11443) `outputs.groundwork` Improve metric parsing to extend output +- [#11557](https://github.com/influxdata/telegraf/pull/11557) `outputs.iotdb` Add new output plugin to support Apache IoTDB +- [#11672](https://github.com/influxdata/telegraf/pull/11672) `outputs.postgresql` Add Postgresql output +- [#11529](https://github.com/influxdata/telegraf/pull/11529) `outputs.redistimeseries` Add integration test +- [#11551](https://github.com/influxdata/telegraf/pull/11551) `outputs.sql` Add settings for go sql.DB settings +- [#11251](https://github.com/influxdata/telegraf/pull/11251) `parsers.json` Allow JSONata based transformations in JSON serializer +- [#11558](https://github.com/influxdata/telegraf/pull/11558) `parsers.xpath` Add support for returning underlying data-types +- [#11306](https://github.com/influxdata/telegraf/pull/11306) `processors.starlark` Add starlark benchmark for tag-concatenation +- [#11475](https://github.com/influxdata/telegraf/pull/11475) `inputs.rabbitmq` Add support for head_message_timestamp metric +- [#9333](https://github.com/influxdata/telegraf/pull/9333) `inputs.redis` Add Redis 6 ACL auth support +- [#11690](https://github.com/influxdata/telegraf/pull/11690) `serializers.prometheus` Provide option to reduce payload size by removing HELP from payload +- [#9319](https://github.com/influxdata/telegraf/pull/9319) `proxy.x509_cert` Add proxy support + +### Dependency Updates + +- [#11671](https://github.com/influxdata/telegraf/pull/11671) Update github.com/jackc/pgx/v4 from 4.16.1 to 4.17.0 +- [#11669](https://github.com/influxdata/telegraf/pull/11669) Update github.com/Azure/go-autorest/autorest from 0.11.24 to 0.11.28 +- [#11670](https://github.com/influxdata/telegraf/pull/11670) Update github.com/aws/aws-sdk-go-v2/service/ec2 from 1.51.2 to 1.52.1 +- [#11675](https://github.com/influxdata/telegraf/pull/11675) Update github.com/urfave/cli/v2 from 2.3.0 to 2.11.2 +- [#11679](https://github.com/influxdata/telegraf/pull/11679) Update github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.13.6 to 1.13.12 +- [#11695](https://github.com/influxdata/telegraf/pull/11695) Update github.com/aliyun/alibaba-cloud-sdk-go from 1.61.1695 to 1.61.1727 +- [#11676](https://github.com/influxdata/telegraf/pull/11676) Update go.mongodb.org/mongo-driver from 1.9.1 to 1.10.1 +- [#11710](https://github.com/influxdata/telegraf/pull/11710) Update github.com/wavefronthq/wavefront-sdk-go from 0.10.1 to 0.10.2 +- [#11711](https://github.com/influxdata/telegraf/pull/11711) Update github.com/aws/aws-sdk-go-v2/service/sts from 1.16.7 to 1.16.13 +- [#11716](https://github.com/influxdata/telegraf/pull/11716) Update github.com/aerospike/aerospike-client-go/v5 from 5.7.0 to 5.9.0 +- [#11717](https://github.com/influxdata/telegraf/pull/11717) Update github.com/hashicorp/consul/api from 1.13.1 to 1.14.0 +- [#11721](https://github.com/influxdata/telegraf/pull/11721) Update github.com/tidwall/gjson from 1.14.1 to 1.14.3 +- [#11699](https://github.com/influxdata/telegraf/pull/11699) Update github.com/rabbitmq/amqp091-go from 1.3.4 to 1.4.0 +- [#11743](https://github.com/influxdata/telegraf/pull/11743) Update github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.15.10 to 1.16.1 +- [#11744](https://github.com/influxdata/telegraf/pull/11744) Update github.com/gophercloud/gophercloud from 0.25.0 to 1.0.0 +- [#11745](https://github.com/influxdata/telegraf/pull/11745) Update k8s.io/client-go from 0.24.3 to 0.25.0 +- [#11747](https://github.com/influxdata/telegraf/pull/11747) Update github.com/aws/aws-sdk-go-v2/feature/ec2/imds from 1.12.11 to 1.12.13 +- [#11763](https://github.com/influxdata/telegraf/pull/11763) Update github.com/urfave/cli/v2 from 2.11.2 to 2.14.1 +- [#11764](https://github.com/influxdata/telegraf/pull/11764) Update gonum.org/v1/gonum from 0.11.0 to 0.12.0 +- [#11770](https://github.com/influxdata/telegraf/pull/11770) Update github.com/Azure/azure-kusto-go from 0.7.0 to 0.8.0 +- [#11746](https://github.com/influxdata/telegraf/pull/11746) Update google.golang.org/grpc from 1.48.0 to 1.49.0 + +### BREAKING CHANGES + +- [#11493](https://github.com/influxdata/telegraf/pull/11493) `common.tls` Set default minimum TLS version to v1.2 for security reasons on both server and client connections. This is a change from the previous defaults (TLS v1.0) on the server configuration and might break clients relying on older TLS versions. You can manually revert to older versions on a per-plugin basis using the `tls_min_version` option in the plugins required + +## v1.23.4 [2022-08-16] + +### Bugfixes + +- [#11647](https://github.com/influxdata/telegraf/pull/11647) Bump github.com/lxc/lxd to be able to run tests +- [#11664](https://github.com/influxdata/telegraf/pull/11664) Sync sql output and input build constraints to handle loong64 in go1.19. +- [#10841](https://github.com/influxdata/telegraf/pull/10841) Updating credentials file to not use endpoint_url parameter +- [#10851](https://github.com/influxdata/telegraf/pull/10851) `inputs.cloudwatch` Customizable batch size when querying +- [#11577](https://github.com/influxdata/telegraf/pull/11577) `inputs.kube_inventory` Send file location to enable token auto-refresh +- [#11578](https://github.com/influxdata/telegraf/pull/11578) `inputs.kubernetes` Refresh token from file at each read +- [#11635](https://github.com/influxdata/telegraf/pull/11635) `inputs.mongodb` Update version check for newer versions +- [#11539](https://github.com/influxdata/telegraf/pull/11539) `inputs.opcua` Return an error with mismatched types +- [#11548](https://github.com/influxdata/telegraf/pull/11548) `inputs.sqlserver` Set lower deadlock priority +- [#11556](https://github.com/influxdata/telegraf/pull/11556) `inputs.stackdriver` Handle when no buckets available +- [#11576](https://github.com/influxdata/telegraf/pull/11576) `inputs` Linter issues +- [#11595](https://github.com/influxdata/telegraf/pull/11595) `outputs` Linter issues +- [#11607](https://github.com/influxdata/telegraf/pull/11607) `parsers` Linter issues + +### Features + +- [#11622](https://github.com/influxdata/telegraf/pull/11622) Add coralogix dialect to opentelemetry + +### Dependency Updates + +- [#11412](https://github.com/influxdata/telegraf/pull/11412) `deps` Bump github.com/testcontainers/testcontainers-go from 0.12.0 to 0.13.0 +- [#11565](https://github.com/influxdata/telegraf/pull/11565) `deps` Bump github.com/apache/thrift from 0.15.0 to 0.16.0 +- [#11567](https://github.com/influxdata/telegraf/pull/11567) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.46.0 to 1.51.0 +- [#11494](https://github.com/influxdata/telegraf/pull/11494) `deps` Update all go.opentelemetry.io dependencies +- [#11569](https://github.com/influxdata/telegraf/pull/11569) `deps` Bump github.com/go-ldap/ldap/v3 from 3.4.1 to 3.4.4 +- [#11574](https://github.com/influxdata/telegraf/pull/11574) `deps` Bump github.com/karrick/godirwalk from 1.16.1 to 1.17.0 +- [#11568](https://github.com/influxdata/telegraf/pull/11568) `deps` Bump github.com/vmware/govmomi from 0.28.0 to 0.29.0 +- [#11347](https://github.com/influxdata/telegraf/pull/11347) `deps` Bump github.com/eclipse/paho.mqtt.golang from 1.3.5 to 1.4.1 +- [#11580](https://github.com/influxdata/telegraf/pull/11580) `deps` Bump github.com/shirou/gopsutil/v3 from 3.22.4 to 3.22.7 +- [#11582](https://github.com/influxdata/telegraf/pull/11582) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs +- [#11583](https://github.com/influxdata/telegraf/pull/11583) `deps` Bump github.com/Azure/go-autorest/autorest/adal +- [#11581](https://github.com/influxdata/telegraf/pull/11581) `deps` Bump github.com/pion/dtls/v2 from 2.0.13 to 2.1.5 +- [#11590](https://github.com/influxdata/telegraf/pull/11590) `deps` Bump github.com/Azure/azure-event-hubs-go/v3 +- [#11586](https://github.com/influxdata/telegraf/pull/11586) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatch +- [#11585](https://github.com/influxdata/telegraf/pull/11585) `deps` Bump github.com/aws/aws-sdk-go-v2/service/kinesis +- [#11584](https://github.com/influxdata/telegraf/pull/11584) `deps` Bump github.com/aws/aws-sdk-go-v2/service/dynamodb +- [#11598](https://github.com/influxdata/telegraf/pull/11598) `deps` Bump github.com/signalfx/golib/v3 from 3.3.43 to 3.3.45 +- [#11605](https://github.com/influxdata/telegraf/pull/11605) `deps` Update github.com/BurntSushi/toml from 0.4.1 to 1.2.0 +- [#11604](https://github.com/influxdata/telegraf/pull/11604) `deps` Update cloud.google.com/go/pubsub from 1.23.0 to 1.24.0 +- [#11602](https://github.com/influxdata/telegraf/pull/11602) `deps` Update k8s.io/apimachinery from 0.24.2 to 0.24.3 +- [#11603](https://github.com/influxdata/telegraf/pull/11603) `deps` Update github.com/Shopify/sarama from 1.34.1 to 1.35.0 +- [#11616](https://github.com/influxdata/telegraf/pull/11616) `deps` Bump github.com/sirupsen/logrus from 1.8.1 to 1.9.0 +- [#11636](https://github.com/influxdata/telegraf/pull/11636) `deps` Bump github.com/emicklei/go-restful from v2.9.5+incompatible to v3.8.0 +- [#11641](https://github.com/influxdata/telegraf/pull/11641) `deps` Bump github.com/hashicorp/consul/api from 1.12.0 to 1.13.1 +- [#11640](https://github.com/influxdata/telegraf/pull/11640) `deps` Bump github.com/prometheus/client_golang from 1.12.2 to 1.13.0 +- [#11643](https://github.com/influxdata/telegraf/pull/11643) `deps` Bump google.golang.org/api from 0.85.0 to 0.91.0 +- [#11644](https://github.com/influxdata/telegraf/pull/11644) `deps` Bump github.com/antchfx/xmlquery from 1.3.9 to 1.3.12 +- [#11651](https://github.com/influxdata/telegraf/pull/11651) `deps` Bump github.com/aws/aws-sdk-go-v2/service/ec2 +- [#11652](https://github.com/influxdata/telegraf/pull/11652) `deps` Bump github.com/aws/aws-sdk-go-v2/feature/ec2/imds +- [#11653](https://github.com/influxdata/telegraf/pull/11653) `deps` Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs + +## v1.23.3 [2022-07-25] + +### Bugfixes + +- [#11481](https://github.com/influxdata/telegraf/pull/11481) `inputs.openstack` Use v3 volume library +- [#11482](https://github.com/influxdata/telegraf/pull/11482) `common.cookie` Use reader over readcloser, regen cookie-jar at reauth +- [#11527](https://github.com/influxdata/telegraf/pull/11527) `inputs.mqtt_consumer` Topic parsing error when topic having prefix '/' +- [#11534](https://github.com/influxdata/telegraf/pull/11534) `inputs.snmp_trap` Nil map panic when use snmp_trap with netsnmp translator +- [#11522](https://github.com/influxdata/telegraf/pull/11522) `inputs.sqlserver` Set lower deadlock priority on queries +- [#11486](https://github.com/influxdata/telegraf/pull/11486) `parsers.prometheus` Histogram infinity bucket must be always present + +### Dependency Updates + +- [#11461](https://github.com/influxdata/telegraf/pull/11461) Bump github.com/antchfx/jsonquery from 1.1.5 to 1.2.0 + +## v1.23.2 [2022-07-11] + +### Bugfixes + +- [#11460](https://github.com/influxdata/telegraf/pull/11460) Deprecation warnings for non-deprecated packages +- [#11472](https://github.com/influxdata/telegraf/pull/11472) `common.http` Allow 201 for cookies, update header docs +- [#11448](https://github.com/influxdata/telegraf/pull/11448) `inputs.sqlserver` Use bigint for backupsize in sqlserver +- [#11011](https://github.com/influxdata/telegraf/pull/11011) `inputs.gnmi` Refactor tag-only subs for complex keys +- [#10331](https://github.com/influxdata/telegraf/pull/10331) `inputs.snmp` Snmp UseUnconnectedUDPSocket when using udp + +### Dependency Updates + +- [#11438](https://github.com/influxdata/telegraf/pull/11438) Bump github.com/docker/docker from 20.10.14 to 20.10.17 + +## v1.23.1 [2022-07-05] + +### Bugfixes + +- [#11335](https://github.com/influxdata/telegraf/pull/11335) Bring back old xpath section names +- [#9315](https://github.com/influxdata/telegraf/pull/9315) `inputs.rabbitmq` Don't require listeners to be present in overview +- [#11280](https://github.com/influxdata/telegraf/pull/11280) Filter out views in mongodb lookup +- [#11311](https://github.com/influxdata/telegraf/pull/11311) Fix race condition in configuration and prevent concurrent map writes to c.UnusedFields +- [#11397](https://github.com/influxdata/telegraf/pull/11397) Resolve jolokia2 panic on null response +- [#11276](https://github.com/influxdata/telegraf/pull/11276) Restore sample configurations broken during initial migration +- [#11413](https://github.com/influxdata/telegraf/pull/11413) Sync back sample.confs for inputs.couchbase and outputs.groundwork. + +### Dependency Updates + +- [#11295](https://github.com/influxdata/telegraf/pull/11295) Bump cloud.google.com/go/monitoring from 1.2.0 to 1.5.0 +- [#11297](https://github.com/influxdata/telegraf/pull/11297) Bump github.com/aws/aws-sdk-go-v2/credentials from 1.12.2 to 1.12.5 +- [#11318](https://github.com/influxdata/telegraf/pull/11318) Bump google.golang.org/grpc from 1.46.2 to 1.47.0 +- [#11223](https://github.com/influxdata/telegraf/pull/11223) Bump k8s.io/client-go from 0.23.3 to 0.24.1 +- [#11299](https://github.com/influxdata/telegraf/pull/11299) Bump github.com/go-logfmt/logfmt from 0.5.0 to 0.5.1 +- [#11328](https://github.com/influxdata/telegraf/pull/11328) Bump github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.15.3 to 1.15.7 +- [#11320](https://github.com/influxdata/telegraf/pull/11320) Bump go.mongodb.org/mongo-driver from 1.9.0 to 1.9.1 +- [#11321](https://github.com/influxdata/telegraf/pull/11321) Bump github.com/gophercloud/gophercloud from 0.24.0 to 0.25.0 +- [#11338](https://github.com/influxdata/telegraf/pull/11338) Bump google.golang.org/api from 0.74.0 to 0.84.0 +- [#11340](https://github.com/influxdata/telegraf/pull/11340) Bump github.com/fatih/color from 1.10.0 to 1.13.0 +- [#11322](https://github.com/influxdata/telegraf/pull/11322) Bump github.com/aws/aws-sdk-go-v2/service/timestreamwrite from 1.3.2 to 1.13.6 +- [#11319](https://github.com/influxdata/telegraf/pull/11319) Bump github.com/Shopify/sarama from 1.32.0 to 1.34.1 +- [#11342](https://github.com/influxdata/telegraf/pull/11342) Bump github.com/dynatrace-oss/dynatrace-metric-utils-go from 0.3.0 to 0.5.0 +- [#11339](https://github.com/influxdata/telegraf/pull/11339) Bump github.com/nats-io/nats.go from 1.15.0 to 1.16.0 +- [#11349](https://github.com/influxdata/telegraf/pull/11349) Bump cloud.google.com/go/pubsub from 1.18.0 to 1.22.2 +- [#11369](https://github.com/influxdata/telegraf/pull/11369) Bump go.opentelemetry.io/collector/pdata from 0.52.0 to 0.54.0 +- [#11346](https://github.com/influxdata/telegraf/pull/11346) Bump github.com/jackc/pgx/v4 from 4.15.0 to 4.16.1 +- [#11379](https://github.com/influxdata/telegraf/pull/11379) Bump cloud.google.com/go/bigquery from 1.8.0 to 1.33.0 +- [#11378](https://github.com/influxdata/telegraf/pull/11378) Bump github.com/Azure/azure-kusto-go from 0.6.0 to 0.7.0 +- [#11394](https://github.com/influxdata/telegraf/pull/11394) Bump cloud.google.com/go/pubsub from 1.22.2 to 1.23.0 +- [#11380](https://github.com/influxdata/telegraf/pull/11380) Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.13.0 to 1.15.7 +- [#11382](https://github.com/influxdata/telegraf/pull/11382) Bump github.com/aws/aws-sdk-go-v2/service/ec2 from 1.1.0 to 1.46.0 +- [#11395](https://github.com/influxdata/telegraf/pull/11395) Bump github.com/golang-jwt/jwt/v4 from 4.4.1 to 4.4.2 +- [#11396](https://github.com/influxdata/telegraf/pull/11396) Bump github.com/vmware/govmomi from 0.27.3 to 0.28.0 +- [#11415](https://github.com/influxdata/telegraf/pull/11415) Bump github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.15.4 to 1.15.8 +- [#11416](https://github.com/influxdata/telegraf/pull/11416) Bump github.com/influxdata/influxdb-observability/otel2influx from 0.2.21 to 0.2.22 +- [#11434](https://github.com/influxdata/telegraf/pull/11434) Bump k8s.io/api from 0.24.1 to 0.24.2 +- [#11437](https://github.com/influxdata/telegraf/pull/11437) Bump github.com/prometheus/client_golang from 1.12.1 to 1.12.2 + +## v1.23.0 [2022-06-13] + +### Bugfixes + +- [#11272](https://github.com/influxdata/telegraf/pull/11272) Add missing build constraints for sqlite +- [#11253](https://github.com/influxdata/telegraf/pull/11253) Always build README-embedder for host-architecture +- [#11140](https://github.com/influxdata/telegraf/pull/11140) Avoid calling sadc with invalid 0 interval +- [#11093](https://github.com/influxdata/telegraf/pull/11093) Check net.Listen() error in tests +- [#11181](https://github.com/influxdata/telegraf/pull/11181) Convert slab plugin to new sample.conf. +- [#10979](https://github.com/influxdata/telegraf/pull/10979) Datadog count metrics +- [#11044](https://github.com/influxdata/telegraf/pull/11044) Deprecate useless database config option +- [#11150](https://github.com/influxdata/telegraf/pull/11150) Doc interval setting for internet speed plugin +- [#11120](https://github.com/influxdata/telegraf/pull/11120) Elasticsearch output float handling test +- [#11151](https://github.com/influxdata/telegraf/pull/11151) Improve slab testing without sudo. +- [#10995](https://github.com/influxdata/telegraf/pull/10995) Log instance name in skip warnings +- [#11069](https://github.com/influxdata/telegraf/pull/11069) Output erroneous namespace and continue instead of error out +- [#11237](https://github.com/influxdata/telegraf/pull/11237) Re-add event to splunk serializer +- [#11143](https://github.com/influxdata/telegraf/pull/11143) Redis plugin goroutine leak triggered by auto reload config mechanism +- [#11082](https://github.com/influxdata/telegraf/pull/11082) Remove any content type from prometheus accept header +- [#11261](https://github.com/influxdata/telegraf/pull/11261) Remove full access permissions +- [#11179](https://github.com/influxdata/telegraf/pull/11179) Search services file in /etc/services and fall back to /usr/etc/services +- [#11217](https://github.com/influxdata/telegraf/pull/11217) Update sample.conf for prometheus +- [#11241](https://github.com/influxdata/telegraf/pull/11241) Upgrade xpath and fix code +- [#11083](https://github.com/influxdata/telegraf/pull/11083) Use readers over closers in http input +- [#11149](https://github.com/influxdata/telegraf/pull/11149) `inputs.burrow` Move Dialer to variable and run `make fmt` +- [#10812](https://github.com/influxdata/telegraf/pull/10812) `outputs.sql` Table existence cache + +### Features + +- [#10880](https://github.com/influxdata/telegraf/pull/10880) Add ANSI color filter for tail input plugin +- [#11188](https://github.com/influxdata/telegraf/pull/11188) Add constant 'algorithm' to the mock plugin +- [#11159](https://github.com/influxdata/telegraf/pull/11159) Add external huebridge input plugin +- [#11076](https://github.com/influxdata/telegraf/pull/11076) Add field key option to set event partition key +- [#10818](https://github.com/influxdata/telegraf/pull/10818) Add fritzbox as external plugin +- [#11037](https://github.com/influxdata/telegraf/pull/11037) Add influx semantic commits checker, checks only last commit. +- [#11039](https://github.com/influxdata/telegraf/pull/11039) Add mount option filtering to disk plugin +- [#11075](https://github.com/influxdata/telegraf/pull/11075) Add slab metrics input plugin +- [#11056](https://github.com/influxdata/telegraf/pull/11056) Allow other fluentd metrics apart from retry_count, buffer_queu… +- [#10918](https://github.com/influxdata/telegraf/pull/10918) Artifactory Webhook Receiver +- [#11000](https://github.com/influxdata/telegraf/pull/11000) Create and push nightly docker images to quay.io +- [#11102](https://github.com/influxdata/telegraf/pull/11102) Do not error if no nodes found for current config with xpath parser +- [#10886](https://github.com/influxdata/telegraf/pull/10886) Generate the plugins sample config +- [#11084](https://github.com/influxdata/telegraf/pull/11084) Google API Auth +- [#10607](https://github.com/influxdata/telegraf/pull/10607) In Lustre input plugin, support collecting per-client stats. +- [#10912](https://github.com/influxdata/telegraf/pull/10912) Migrate aggregator plugins to new sample config format +- [#10924](https://github.com/influxdata/telegraf/pull/10924) Migrate input plugins to new sample config format (A-L) +- [#10926](https://github.com/influxdata/telegraf/pull/10926) Migrate input plugins to new sample config format (M-Z) +- [#10910](https://github.com/influxdata/telegraf/pull/10910) Migrate output plugins to new sample config format +- [#10913](https://github.com/influxdata/telegraf/pull/10913) Migrate processor plugins to new sample config format +- [#11218](https://github.com/influxdata/telegraf/pull/11218) Migrate xpath parser to new style +- [#10885](https://github.com/influxdata/telegraf/pull/10885) Update etc/telegraf.conf and etc/telegraf_windows.conf +- [#6948](https://github.com/influxdata/telegraf/pull/6948) `inputs.burrow` fill more http transport parameters +- [#11141](https://github.com/influxdata/telegraf/pull/11141) `inputs.cpu` Add tags with core id or physical id to cpus +- [#7896](https://github.com/influxdata/telegraf/pull/7896) `inputs.mongodb` Add metrics about files currently open and currently active data handles +- [#10448](https://github.com/influxdata/telegraf/pull/10448) `inputs.nginx_plus_api` Gather slab metrics +- [#11216](https://github.com/influxdata/telegraf/pull/11216) `inputs.sqlserver` Update query store and latch performance counters +- [#10574](https://github.com/influxdata/telegraf/pull/10574) `inputs.vsphere` Collect resource pools metrics and add resource pool tag in VM metrics +- [#11035](https://github.com/influxdata/telegraf/pull/11035) `inputs.intel_powerstat` Add Max Turbo Frequency and introduce improvements +- [#11254](https://github.com/influxdata/telegraf/pull/11254) `inputs.intel_powerstat` Add uncore frequency metrics +- [#10954](https://github.com/influxdata/telegraf/pull/10954) `outputs.http` Support configuration of `MaxIdleConns` and `MaxIdleConnsPerHost` +- [#10853](https://github.com/influxdata/telegraf/pull/10853) `outputs.elasticsearch` Add healthcheck timeout + +### Dependency Updates + +- [#10970](https://github.com/influxdata/telegraf/pull/10970) Update github.com/wavefronthq/wavefront-sdk-go from 0.9.10 to 0.9.11 +- [#11166](https://github.com/influxdata/telegraf/pull/11166) Update github.com/aws/aws-sdk-go-v2/config from 1.15.3 to 1.15.7 +- [#11021](https://github.com/influxdata/telegraf/pull/11021) Update github.com/sensu/sensu-go/api/core/v2 from 2.13.0 to 2.14.0 +- [#11088](https://github.com/influxdata/telegraf/pull/11088) Update go.opentelemetry.io/otel/metric from 0.28.0 to 0.30.0 +- [#11221](https://github.com/influxdata/telegraf/pull/11221) Update github.com/nats-io/nats-server/v2 from 2.7.4 to 2.8.4 +- [#11191](https://github.com/influxdata/telegraf/pull/11191) Update golangci-lint from v1.45.2 to v1.46.2 +- [#11107](https://github.com/influxdata/telegraf/pull/11107) Update gopsutil from v3.22.3 to v3.22.4 to allow for HOST_PROC_MOUNTINFO. +- [#11242](https://github.com/influxdata/telegraf/pull/11242) Update moby/ipvs dependency from v1.0.1 to v1.0.2 +- [#11260](https://github.com/influxdata/telegraf/pull/11260) Update modernc.org/sqlite from v1.10.8 to v1.17.3 +- [#11266](https://github.com/influxdata/telegraf/pull/11266) Update github.com/containerd/containerd from v1.5.11 to v1.5.13 +- [#11264](https://github.com/influxdata/telegraf/pull/11264) Update github.com/tidwall/gjson from 1.10.2 to 1.14.1 + +## v1.22.4 [2022-05-16] + +### Bugfixes + +- [#11045](https://github.com/influxdata/telegraf/pull/11045) `inputs.couchbase` Do not assume metrics will all be of the same length +- [#11043](https://github.com/influxdata/telegraf/pull/11043) `inputs.statsd` Do not error when closing statsd network connection +- [#11030](https://github.com/influxdata/telegraf/pull/11030) `outputs.azure_monitor` Re-init azure monitor http client on context deadline error +- [#11078](https://github.com/influxdata/telegraf/pull/11078) `outputs.wavefront` If no "host" tag is provided do not add "telegraf.host" tag +- [#11042](https://github.com/influxdata/telegraf/pull/11042) Have telegraf service wait for network up in systemd packaging + +### Dependency Updates + +- [#10722](https://github.com/influxdata/telegraf/pull/10722) `inputs.internet_speed` Update github.com/showwin/speedtest-go from 1.1.4 to 1.1.5 +- [#11085](https://github.com/influxdata/telegraf/pull/11085) Update OpenTelemetry plugins to v0.51.0 + +## v1.22.3 [2022-04-28] + +### Bugfixes + +- [#10961](https://github.com/influxdata/telegraf/pull/10961) Update Go to 1.18.1 +- [#10976](https://github.com/influxdata/telegraf/pull/10976) `inputs.influxdb_listener` Remove duplicate influxdb listener writes with upstream parser +- [#11024](https://github.com/influxdata/telegraf/pull/11024) `inputs.gnmi` Use external xpath parser for gnmi +- [#10925](https://github.com/influxdata/telegraf/pull/10925) `inputs.system` Reduce log level in disk plugin back to original level + +## v1.22.2 [2022-04-25] + +### Bugfixes + +- [#11008](https://github.com/influxdata/telegraf/pull/11008) `inputs.gnmi` Add mutex to gnmi lookup map +- [#11010](https://github.com/influxdata/telegraf/pull/11010) `inputs.gnmi` Use sprint to cast to strings in gnmi +- [#11001](https://github.com/influxdata/telegraf/pull/11001) `inputs.consul_agent` Use correct auth token with consul_agent +- [#10486](https://github.com/influxdata/telegraf/pull/10486) `inputs.mysql` Add mariadb_dialect to address the MariaDB differences in INNODB_METRICS +- [#10923](https://github.com/influxdata/telegraf/pull/10923) `inputs.smart` Correctly parse various numeric forms +- [#10850](https://github.com/influxdata/telegraf/pull/10850) `inputs.aliyuncms` Ensure aliyuncms metrics accept array, fix discovery +- [#10930](https://github.com/influxdata/telegraf/pull/10930) `inputs.aerospike` Statistics query bug +- [#10947](https://github.com/influxdata/telegraf/pull/10947) `inputs.cisco_telemetry_mdt` Align the default value for msg size +- [#10959](https://github.com/influxdata/telegraf/pull/10959) `inputs.cisco_telemetry_mdt` Remove overly verbose info message from cisco mdt +- [#10958](https://github.com/influxdata/telegraf/pull/10958) `outputs.influxdb_v2` Improve influxdb_v2 error message +- [#10932](https://github.com/influxdata/telegraf/pull/10932) `inputs.prometheus` Moved from watcher to informer +- [#11013](https://github.com/influxdata/telegraf/pull/11013) Also allow 0 outputs when using test-wait parameter +- [#11015](https://github.com/influxdata/telegraf/pull/11015) Allow Makefile to work on Windows + +### Dependency Updates + +- [#10966](https://github.com/influxdata/telegraf/pull/10966) Update github.com/Azure/azure-kusto-go from 0.5.0 to 0.60 +- [#10963](https://github.com/influxdata/telegraf/pull/10963) Update opentelemetry from v0.2.10 to v0.2.17 +- [#10984](https://github.com/influxdata/telegraf/pull/10984) Update go.opentelemetry.io/collector/pdata from v0.48.0 to v0.49.0 +- [#10998](https://github.com/influxdata/telegraf/pull/10998) Update github.com/aws/aws-sdk-go-v2/config from 1.13.1 to 1.15.3 +- [#10997](https://github.com/influxdata/telegraf/pull/10997) Update github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs +- [#10975](https://github.com/influxdata/telegraf/pull/10975) Update github.com/aws/aws-sdk-go-v2/credentials from 1.8.0 to 1.11.2 +- [#10981](https://github.com/influxdata/telegraf/pull/10981) Update github.com/containerd/containerd from v1.5.9 to v1.5.11 +- [#10973](https://github.com/influxdata/telegraf/pull/10973) Update github.com/miekg/dns from 1.1.46 to 1.1.48 +- [#10974](https://github.com/influxdata/telegraf/pull/10974) Update github.com/gopcua/opcua from v0.3.1 to v0.3.3 +- [#10972](https://github.com/influxdata/telegraf/pull/10972) Update github.com/aws/aws-sdk-go-v2/service/dynamodb +- [#10773](https://github.com/influxdata/telegraf/pull/10773) Update github.com/xdg/scram from 1.0.3 to 1.0.5 +- [#10971](https://github.com/influxdata/telegraf/pull/10971) Update go.mongodb.org/mongo-driver from 1.8.3 to 1.9.0 +- [#10940](https://github.com/influxdata/telegraf/pull/10940) Update starlark 7a1108eaa012->d1966c6b9fcd + +## v1.22.1 [2022-04-06] + +### Bugfixes + +- [#10937](https://github.com/influxdata/telegraf/pull/10937) Update gonum.org/v1/gonum from 0.9.3 to 0.11.0 +- [#10906](https://github.com/influxdata/telegraf/pull/10906) Update github.com/golang-jwt/jwt/v4 from 4.2.0 to 4.4.1 +- [#10931](https://github.com/influxdata/telegraf/pull/10931) Update gopsutil and associated dependencies for improved OpenBSD support +- [#10553](https://github.com/influxdata/telegraf/pull/10553) `inputs.sqlserver` Fix inconsistencies in sql*Requests queries +- [#10883](https://github.com/influxdata/telegraf/pull/10883) `agent` Fix default value for logfile rotation interval +- [#10871](https://github.com/influxdata/telegraf/pull/10871) `inputs.zfs` Fix redundant zfs pool tag +- [#10903](https://github.com/influxdata/telegraf/pull/10903) `inputs.vsphere` Update vsphere info message to debug +- [#10866](https://github.com/influxdata/telegraf/pull/10866) `outputs.azure_monitor` Include body in error message +- [#10830](https://github.com/influxdata/telegraf/pull/10830) `processors.topk` Clarify the k and fields topk params +- [#10858](https://github.com/influxdata/telegraf/pull/10858) `outputs.http` Switch HTTP 100 test case values +- [#10859](https://github.com/influxdata/telegraf/pull/10859) `inputs.intel_pmu` Fix slow running intel-pmu test +- [#10860](https://github.com/influxdata/telegraf/pull/10860) `inputs.cloud_pubsub` Skip longer/integration tests on -short mode +- [#10861](https://github.com/influxdata/telegraf/pull/10861) `inputs.cloud_pubsub_push` Reduce timeouts and sleeps + +### New External Plugins + +- [#10462](https://github.com/influxdata/telegraf/pull/10462) `external.psi` Add psi plugin + +## v1.22.0 + +### Influx Line Protocol Parser + +There is an option to use a faster, more memory-efficient +implementation of the Influx Line Protocol parser. + +### SNMP Translator + +This version introduces an agent setting to select the method of +translating SNMP objects. The agent setting "snmp_translator" can be +"netsnmp" which translates by calling external programs snmptranslate +and snmptable, or "gosmi" which translates using the built-in gosmi +library. + +Before version 1.21.0, Telegraf only used the netsnmp method. Versions +1.21.0 through 1.21.4 only used the gosmi method. Since the +translation method is now configurable and "netsnmp" is the default, +users who wish to continue using "gosmi" must add `snmp_translator = +"gosmi"` in the agent section of their config file. See +[#10802](https://github.com/influxdata/telegraf/pull/10802). + +### New Input Plugins + +- [#3649](https://github.com/influxdata/telegraf/pull/3649) `inputs.socketstat` Add socketstat input plugin +- [#9697](https://github.com/influxdata/telegraf/pull/9697) `inputs.xtremio` Add xtremio input +- [#9782](https://github.com/influxdata/telegraf/pull/9782) `inputs.mock` Add mock input plugin +- [#10042](https://github.com/influxdata/telegraf/pull/10042) `inputs.redis_sentinel` Add redis sentinel input plugin +- [#10106](https://github.com/influxdata/telegraf/pull/10106) `inputs.nomad` Add nomad input plugin +- [#10198](https://github.com/influxdata/telegraf/pull/10198) `inputs.vault` Add vault input plugin +- [#10258](https://github.com/influxdata/telegraf/pull/10258) `inputs.consul_agent` Add consul agent input plugin +- [#10763](https://github.com/influxdata/telegraf/pull/10763) `inputs.hugepages` Add hugepages input plugin + +### New Processor Plugins + +- [#10057](https://github.com/influxdata/telegraf/pull/10057) `processors.noise` Add noise processor plugin + +### Features + +- [#9332](https://github.com/influxdata/telegraf/pull/9332) `agent` HTTP basic auth for webhooks +- [#10307](https://github.com/influxdata/telegraf/pull/10307) `agent` Improve error logging on plugin initialization +- [#10341](https://github.com/influxdata/telegraf/pull/10341) `agent` Check TLSConfig early to catch missing certificates +- [#10404](https://github.com/influxdata/telegraf/pull/10404) `agent` Support headers for http plugin with cookie auth +- [#10545](https://github.com/influxdata/telegraf/pull/10545) `agent` Add a collection offset implementation +- [#10559](https://github.com/influxdata/telegraf/pull/10559) `agent` Add autorestart and restartdelay flags to Windows service +- [#10515](https://github.com/influxdata/telegraf/pull/10515) `aggregators.histogram` Add config option to push only updated values +- [#10520](https://github.com/influxdata/telegraf/pull/10520) `aggregators.histogram` Add expiration option +- [#10137](https://github.com/influxdata/telegraf/pull/10137) `inputs.bond` Add additional stats to bond collector +- [#10382](https://github.com/influxdata/telegraf/pull/10382) `inputs.docker` Update docker client API version +- [#10575](https://github.com/influxdata/telegraf/pull/10575) `inputs.file` Allow for stateful parser handling +- [#7484](https://github.com/influxdata/telegraf/pull/7484) `inputs.gnmi` add dynamic tagging to gnmi plugin +- [#10220](https://github.com/influxdata/telegraf/pull/10220) `inputs.graylog` Add timeout setting option +- [#10530](https://github.com/influxdata/telegraf/pull/10530) `inputs.internet_speed` Add caching to internet_speed +- [#10243](https://github.com/influxdata/telegraf/pull/10243) `inputs.kibana` Add heap_size_limit field +- [#10641](https://github.com/influxdata/telegraf/pull/10641) `inputs.memcached` gather additional stats from memcached +- [#10642](https://github.com/influxdata/telegraf/pull/10642) `inputs.memcached` Support client TLS origination +- [#9279](https://github.com/influxdata/telegraf/pull/9279) `inputs.modbus` Support multiple slaves with gateway +- [#10231](https://github.com/influxdata/telegraf/pull/10231) `inputs.modbus` Add per-request tags +- [#10625](https://github.com/influxdata/telegraf/pull/10625) `inputs.mongodb` Add FsTotalSize and FsUsedSize fields +- [#10787](https://github.com/influxdata/telegraf/pull/10787) `inputs.nfsclient` Add new rtt per op field +- [#10705](https://github.com/influxdata/telegraf/pull/10705) `inputs.openweathermap` Add feels_like field +- [#9710](https://github.com/influxdata/telegraf/pull/9710) `inputs.postgresql` Add option to disable prepared statements for PostgreSQL +- [#10339](https://github.com/influxdata/telegraf/pull/10339) `inputs.snmp_trap` Deprecate unused snmp_trap timeout configuration option +- [#9671](https://github.com/influxdata/telegraf/pull/9671) `inputs.sql` Add ClickHouse driver to sql inputs/outputs plugins +- [#10466](https://github.com/influxdata/telegraf/pull/10466) `inputs.statsd` Add option to sanitize collected metric names +- [#9432](https://github.com/influxdata/telegraf/pull/9432) `inputs.varnish` Create option to reduce potentially high cardinality +- [#6501](https://github.com/influxdata/telegraf/pull/6501) `inputs.win_perf_counters` Implemented support for reading raw values, added tests and doc +- [#10535](https://github.com/influxdata/telegraf/pull/10535) `inputs.win_perf_counters` Allow errors to be ignored +- [#9822](https://github.com/influxdata/telegraf/pull/9822) `inputs.x509_cert` Add exclude_root_certs option to x509_cert plugin +- [#9963](https://github.com/influxdata/telegraf/pull/9963) `outputs.datadog` Add the option to use compression +- [#10505](https://github.com/influxdata/telegraf/pull/10505) `outputs.elasticsearch` Add elastic pipeline flags +- [#10499](https://github.com/influxdata/telegraf/pull/10499) `outputs.groundwork` Process group tags +- [#10186](https://github.com/influxdata/telegraf/pull/10186) `outputs.http` Add optional list of non retryable http status codes +- [#10202](https://github.com/influxdata/telegraf/pull/10202) `outputs.http` Support AWS managed service for prometheus +- [#8192](https://github.com/influxdata/telegraf/pull/8192) `outputs.kafka` Add socks5 proxy support +- [#10673](https://github.com/influxdata/telegraf/pull/10673) `outputs.sql` Add unsigned style config option +- [#10672](https://github.com/influxdata/telegraf/pull/10672) `outputs.websocket` Add socks5 proxy support +- [#10267](https://github.com/influxdata/telegraf/pull/10267) `parsers.csv` Add option to skip errors during parsing +- [#10749](https://github.com/influxdata/telegraf/pull/10749) `parsers.influx` Add new influx line protocol parser via feature flag +- [#10585](https://github.com/influxdata/telegraf/pull/10585) `parsers.xpath` Add tag batch-processing to XPath parser +- [#10316](https://github.com/influxdata/telegraf/pull/10316) `processors.template` Add more functionality to template processor +- [#10252](https://github.com/influxdata/telegraf/pull/10252) `serializers.wavefront` Add option to disable Wavefront prefix conversion + +### Bugfixes + +- [#10803](https://github.com/influxdata/telegraf/pull/10803) `agent` Update parsing logic of config.Duration to correctly require time and duration +- [#10814](https://github.com/influxdata/telegraf/pull/10814) `agent` Update the precision parameter default value +- [#10872](https://github.com/influxdata/telegraf/pull/10872) `agent` Change name of agent snmp translator setting +- [#10876](https://github.com/influxdata/telegraf/pull/10876) `inputs.consul_agent` Rename consul_metrics -> consul_agent +- [#10711](https://github.com/influxdata/telegraf/pull/10711) `inputs.docker` Keep data type of tasks_desired field consistent +- [#10083](https://github.com/influxdata/telegraf/pull/10083) `inputs.http` Add metadata support to CSV parser plugin +- [#10701](https://github.com/influxdata/telegraf/pull/10701) `inputs.mdstat` Fix parsing output when when sync is less than 10% +- [#10385](https://github.com/influxdata/telegraf/pull/10385) `inputs.modbus` Re-enable OpenBSD modbus support +- [#10790](https://github.com/influxdata/telegraf/pull/10790) `inputs.ntpq` Correctly read ntpq long poll output with extra characters +- [#10384](https://github.com/influxdata/telegraf/pull/10384) `inputs.opcua` Accept non-standard OPC UA OK status by implementing a configurable workaround +- [#10465](https://github.com/influxdata/telegraf/pull/10465) `inputs.opcua` Add additional data to error messages +- [#10735](https://github.com/influxdata/telegraf/pull/10735) `inputs.snmp` Log err when loading mibs +- [#10748](https://github.com/influxdata/telegraf/pull/10748) `inputs.snmp` Use the correct path when evaluating symlink +- [#10802](https://github.com/influxdata/telegraf/pull/10802) `inputs.snmp` Add option to select translator +- [#10527](https://github.com/influxdata/telegraf/pull/10527) `inputs.system` Remove verbose logging from disk input plugin +- [#10706](https://github.com/influxdata/telegraf/pull/10706) `outputs.influxdb_v2` Include influxdb bucket name in error messages +- [#10623](https://github.com/influxdata/telegraf/pull/10623) `outputs.groundwork` Set NextCheckTime to LastCheckTime to avoid GroundWork to invent a value +- [#10749](https://github.com/influxdata/telegraf/pull/10749) `parsers.influx` Add new influx line protocol parser via feature flag +- [#10777](https://github.com/influxdata/telegraf/pull/10777) `parsers.json_v2` Allow multiple optional objects +- [#10799](https://github.com/influxdata/telegraf/pull/10799) `parsers.json_v2` Check if gpath exists and support optional in fields/tags +- [#10798](https://github.com/influxdata/telegraf/pull/10798) `parsers.xpath` Correctly handling imports in protocol-buffer definitions +- [#10602](https://github.com/influxdata/telegraf/pull/10602) Update github.com/aws/aws-sdk-go-v2/service/sts from 1.7.2 to 1.14.0 +- [#10604](https://github.com/influxdata/telegraf/pull/10604) Update github.com/aerospike/aerospike-client-go from 1.27.0 to 5.7.0 +- [#10686](https://github.com/influxdata/telegraf/pull/10686) Update github.com/sleepinggenius2/gosmi from v0.4.3 to v0.4.4 +- [#10692](https://github.com/influxdata/telegraf/pull/10692) Update github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.5.0 to 1.13.0 +- [#10693](https://github.com/influxdata/telegraf/pull/10693) Update github.com/gophercloud/gophercloud from 0.16.0 to 0.24.0 +- [#10702](https://github.com/influxdata/telegraf/pull/10702) Update github.com/jackc/pgx/v4 from 4.14.1 to 4.15.0 +- [#10704](https://github.com/influxdata/telegraf/pull/10704) Update github.com/sensu/sensu-go/api/core/v2 from 2.12.0 to 2.13.0 +- [#10713](https://github.com/influxdata/telegraf/pull/10713) Update k8s.io/api from 0.23.3 to 0.23.4 +- [#10714](https://github.com/influxdata/telegraf/pull/10714) Update cloud.google.com/go/pubsub from 1.17.1 to 1.18.0 +- [#10715](https://github.com/influxdata/telegraf/pull/10715) Update github.com/newrelic/newrelic-telemetry-sdk-go from 0.5.1 to 0.8.1 +- [#10717](https://github.com/influxdata/telegraf/pull/10717) Update github.com/ClickHouse/clickhouse-go from 1.5.1 to 1.5.4 +- [#10718](https://github.com/influxdata/telegraf/pull/10718) Update github.com/wavefronthq/wavefront-sdk-go from 0.9.9 to 0.9.10 +- [#10719](https://github.com/influxdata/telegraf/pull/10719) Update github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs from 1.12.0 to 1.13.0 +- [#10720](https://github.com/influxdata/telegraf/pull/10720) Update github.com/aws/aws-sdk-go-v2/config from 1.8.3 to 1.13.1 +- [#10721](https://github.com/influxdata/telegraf/pull/10721) Update github.com/aws/aws-sdk-go-v2/feature/ec2/imds from 1.6.0 to 1.10.0 +- [#10728](https://github.com/influxdata/telegraf/pull/10728) Update github.com/testcontainers/testcontainers-go from 0.11.1 to 0.12.0 +- [#10751](https://github.com/influxdata/telegraf/pull/10751) Update github.com/aws/aws-sdk-go-v2/service/dynamodb from 1.13.0 to 1.14.0 +- [#10752](https://github.com/influxdata/telegraf/pull/10752) Update github.com/nats-io/nats-server/v2 from 2.7.2 to 2.7.3 +- [#10757](https://github.com/influxdata/telegraf/pull/10757) Update github.com/miekg/dns from 1.1.43 to 1.1.46 +- [#10758](https://github.com/influxdata/telegraf/pull/10758) Update github.com/shirou/gopsutil/v3 from 3.21.12 to 3.22.2 +- [#10759](https://github.com/influxdata/telegraf/pull/10759) Update github.com/aws/aws-sdk-go-v2/feature/ec2/imds from 1.10.0 to 1.11.0 +- [#10772](https://github.com/influxdata/telegraf/pull/10772) Update github.com/Shopify/sarama from 1.29.1 to 1.32.0 +- [#10807](https://github.com/influxdata/telegraf/pull/10807) Update github.com/nats-io/nats-server/v2 from 2.7.3 to 2.7.4 + +## v1.21.4 [2022-02-16] + +### Bugfixes + +- [#10491](https://github.com/influxdata/telegraf/pull/10491) `inputs.docker` Update docker memory usage calculation +- [#10636](https://github.com/influxdata/telegraf/pull/10636) `inputs.ecs` Use current time as timestamp +- [#10551](https://github.com/influxdata/telegraf/pull/10551) `inputs.snmp` Ensure folders do not get loaded more than once +- [#10579](https://github.com/influxdata/telegraf/pull/10579) `inputs.win_perf_counters` Add deprecated warning and version to win_perf_counters option +- [#10635](https://github.com/influxdata/telegraf/pull/10635) `outputs.amqp` Check for nil client before closing in amqp +- [#10179](https://github.com/influxdata/telegraf/pull/10179) `outputs.azure_data_explorer` Lower RAM usage +- [#10513](https://github.com/influxdata/telegraf/pull/10513) `outputs.elasticsearch` Add scheme to fix error in sniffing option +- [#10657](https://github.com/influxdata/telegraf/pull/10657) `parsers.json_v2` Fix timestamp change during execution of json_v2 parser +- [#10618](https://github.com/influxdata/telegraf/pull/10618) `parsers.json_v2` Fix incorrect handling of json_v2 timestamp_path +- [#10468](https://github.com/influxdata/telegraf/pull/10468) `parsers.json_v2` Allow optional paths and handle wrong paths correctly +- [#10547](https://github.com/influxdata/telegraf/pull/10547) `serializers.prometheusremotewrite` Use the correct timestamp unit +- [#10647](https://github.com/influxdata/telegraf/pull/10647) Update all go.opentelemetry.io from 0.24.0 to 0.27.0 +- [#10652](https://github.com/influxdata/telegraf/pull/10652) Update github.com/signalfx/golib/v3 from 3.3.38 to 3.3.43 +- [#10653](https://github.com/influxdata/telegraf/pull/10653) Update github.com/aliyun/alibaba-cloud-sdk-go from 1.61.1004 to 1.61.1483 +- [#10503](https://github.com/influxdata/telegraf/pull/10503) Update github.com/denisenkom/go-mssqldb from 0.10.0 to 0.12.0 +- [#10626](https://github.com/influxdata/telegraf/pull/10626) Update github.com/gopcua/opcua from 0.2.3 to 0.3.1 +- [#10638](https://github.com/influxdata/telegraf/pull/10638) Update github.com/nats-io/nats-server/v2 from 2.6.5 to 2.7.2 +- [#10589](https://github.com/influxdata/telegraf/pull/10589) Update k8s.io/client-go from 0.22.2 to 0.23.3 +- [#10601](https://github.com/influxdata/telegraf/pull/10601) Update github.com/aws/aws-sdk-go-v2/service/kinesis from 1.6.0 to 1.13.0 +- [#10588](https://github.com/influxdata/telegraf/pull/10588) Update github.com/benbjohnson/clock from 1.1.0 to 1.3.0 +- [#10598](https://github.com/influxdata/telegraf/pull/10598) Update github.com/Azure/azure-kusto-go from 0.5.0 to 0.5.2 +- [#10571](https://github.com/influxdata/telegraf/pull/10571) Update github.com/vmware/govmomi from 0.27.2 to 0.27.3 +- [#10572](https://github.com/influxdata/telegraf/pull/10572) Update github.com/prometheus/client_golang from 1.11.0 to 1.12.1 +- [#10564](https://github.com/influxdata/telegraf/pull/10564) Update go.mongodb.org/mongo-driver from 1.7.3 to 1.8.3 +- [#10563](https://github.com/influxdata/telegraf/pull/10563) Update github.com/google/go-cmp from 0.5.6 to 0.5.7 +- [#10562](https://github.com/influxdata/telegraf/pull/10562) Update go.opentelemetry.io/collector/model from 0.39.0 to 0.43.2 +- [#10538](https://github.com/influxdata/telegraf/pull/10538) Update github.com/multiplay/go-ts3 from 1.0.0 to 1.0.1 +- [#10454](https://github.com/influxdata/telegraf/pull/10454) Update cloud.google.com/go/monitoring from 0.2.0 to 1.2.0 +- [#10536](https://github.com/influxdata/telegraf/pull/10536) Update github.com/vmware/govmomi from 0.26.0 to 0.27.2 + +### New External Plugins + +- [apt](https://github.com/x70b1/telegraf-apt) - contributed by @x70b1 +- [knot](https://github.com/x70b1/telegraf-knot) - contributed by @x70b1 + +## v1.21.3 [2022-01-27] + +### Bugfixes + +- [#10430](https://github.com/influxdata/telegraf/pull/10430) `inputs.snmp_trap` Fix translation of partially resolved OIDs +- [#10529](https://github.com/influxdata/telegraf/pull/10529) Update deprecation notices +- [#10525](https://github.com/influxdata/telegraf/pull/10525) Update grpc module to v1.44.0 +- [#10434](https://github.com/influxdata/telegraf/pull/10434) Update google.golang.org/api module from 0.54.0 to 0.65.0 +- [#10507](https://github.com/influxdata/telegraf/pull/10507) Update antchfx/xmlquery module from 1.3.6 to 1.3.9 +- [#10521](https://github.com/influxdata/telegraf/pull/10521) Update nsqio/go-nsq module from 1.0.8 to 1.1.0 +- [#10506](https://github.com/influxdata/telegraf/pull/10506) Update prometheus/common module from 0.31.1 to 0.32.1 +- [#10474](https://github.com/influxdata/telegraf/pull/10474) `inputs.ipset` Fix panic when command not found +- [#10504](https://github.com/influxdata/telegraf/pull/10504) Update cloud.google.com/go/pubsub module from 1.17.0 to 1.17.1 +- [#10432](https://github.com/influxdata/telegraf/pull/10432) Update influxdata/influxdb-observability/influx2otel module from 0.2.8 to 0.2.10 +- [#10478](https://github.com/influxdata/telegraf/pull/10478) `inputs.opcua` Remove duplicate fields +- [#10473](https://github.com/influxdata/telegraf/pull/10473) `parsers.nagios` Log correct errors when executing commands +- [#10463](https://github.com/influxdata/telegraf/pull/10463) `inputs.execd` Add newline in execd for prometheus parsing +- [#10451](https://github.com/influxdata/telegraf/pull/10451) Update shirou/gopsutil/v3 module from 3.21.10 to 3.21.12 +- [#10453](https://github.com/influxdata/telegraf/pull/10453) Update jackc/pgx/v4 module from 4.6.0 to 4.14.1 +- [#10449](https://github.com/influxdata/telegraf/pull/10449) Update Azure/azure-event-hubs-go/v3 module from 3.3.13 to 3.3.17 +- [#10450](https://github.com/influxdata/telegraf/pull/10450) Update gosnmp/gosnmp module from 1.33.0 to 1.34.0 +- [#10442](https://github.com/influxdata/telegraf/pull/10442) `parsers.wavefront` Add missing setting wavefront_disable_prefix_conversion +- [#10435](https://github.com/influxdata/telegraf/pull/10435) Update hashicorp/consul/api module from 1.9.1 to 1.12.0 +- [#10436](https://github.com/influxdata/telegraf/pull/10436) Update antchfx/xpath module from 1.1.11 to 1.2.0 +- [#10433](https://github.com/influxdata/telegraf/pull/10433) Update antchfx/jsonquery module from 1.1.4 to 1.1.5 +- [#10414](https://github.com/influxdata/telegraf/pull/10414) Update prometheus/procfs module from 0.6.0 to 0.7.3 +- [#10354](https://github.com/influxdata/telegraf/pull/10354) `inputs.snmp` Fix panic when mibs folder doesn't exist (#10346) +- [#10393](https://github.com/influxdata/telegraf/pull/10393) `outputs.syslog` Correctly set ASCII trailer for syslog output +- [#10415](https://github.com/influxdata/telegraf/pull/10415) Update aws/aws-sdk-go-v2/service/cloudwatchlogs module from 1.5.2 to 1.12.0 +- [#10416](https://github.com/influxdata/telegraf/pull/10416) Update kardianos/service module from 1.0.0 to 1.2.1 +- [#10396](https://github.com/influxdata/telegraf/pull/10396) `inputs.http` Allow empty http body +- [#10417](https://github.com/influxdata/telegraf/pull/10417) Update couchbase/go-couchbase module from 0.1.0 to 0.1.1 +- [#10413](https://github.com/influxdata/telegraf/pull/10413) `parsers.json_v2` Fix timestamp precision when using unix_ns format +- [#10418](https://github.com/influxdata/telegraf/pull/10418) Update pion/dtls/v2 module from 2.0.9 to 2.0.13 +- [#10402](https://github.com/influxdata/telegraf/pull/10402) Update containerd/containerd module to 1.5.9 +- [#8947](https://github.com/influxdata/telegraf/pull/8947) `outputs.timestream` Fix batching logic with write records and introduce concurrent requests +- [#10360](https://github.com/influxdata/telegraf/pull/10360) `outputs.amqp` Avoid connection leak when writing error +- [#10097](https://github.com/influxdata/telegraf/pull/10097) `outputs.stackdriver` Send correct interval start times for counters + +## v1.21.2 [2022-01-05] + +### Release Notes + +Happy New Year! + +### Features + +- Added arm64 MacOS builds +- Added riscv64 Linux builds +- Numerous changes to CircleCI config to ensure more timely completion and more clear execution flow + +### Bugfixes + +- [#10318](https://github.com/influxdata/telegraf/pull/10318) `inputs.disk` Fix missing storage in containers +- [#10324](https://github.com/influxdata/telegraf/pull/10324) `inputs.dpdk` Add note about dpdk and socket availability +- [#10296](https://github.com/influxdata/telegraf/pull/10296) `inputs.logparser` Resolve panic in logparser due to missing Log +- [#10322](https://github.com/influxdata/telegraf/pull/10322) `inputs.snmp` Ensure module load order to avoid snmp marshal error +- [#10321](https://github.com/influxdata/telegraf/pull/10321) `inputs.snmp` Do not require networking during tests +- [#10303](https://github.com/influxdata/telegraf/pull/10303) `inputs.snmp` Resolve SNMP panic due to no gosmi module +- [#10295](https://github.com/influxdata/telegraf/pull/10295) `inputs.snmp` Grab MIB table columns more accurately +- [#10299](https://github.com/influxdata/telegraf/pull/10299) `inputs.snmp` Check index before assignment when floating :: exists to avoid panic +- [#10301](https://github.com/influxdata/telegraf/pull/10301) `inputs.snmp` Fix panic if no mibs folder is found +- [#10373](https://github.com/influxdata/telegraf/pull/10373) `inputs.snmp_trap` Document deprecation of timeout parameter +- [#10377](https://github.com/influxdata/telegraf/pull/10377) `parsers.csv` empty import tzdata for Windows binaries to correctly set timezone +- [#10332](https://github.com/influxdata/telegraf/pull/10332) Update github.com/djherbis/times module from v1.2.0 to v1.5.0 +- [#10343](https://github.com/influxdata/telegraf/pull/10343) Update github.com/go-ldap/ldap/v3 module from v3.1.0 to v3.4.1 +- [#10255](https://github.com/influxdata/telegraf/pull/10255) Update github.com/gwos/tcg/sdk module from v0.0.0-20211130162655-32ad77586ccf to v0.0.0-20211223101342-35fbd1ae683c and improve logging + +## v1.21.1 [2021-12-16] + +### Bugfixes + +- [#10288](https://github.com/influxdata/telegraf/pull/10288) Fix panic in parsers due to missing Log for all plugins using SetParserFunc. +- [#10288](https://github.com/influxdata/telegraf/pull/10288) Fix panic in parsers due to missing Log for all plugins using SetParserFunc +- [#10247](https://github.com/influxdata/telegraf/pull/10247) Update go-sensu module to v2.12.0 +- [#10284](https://github.com/influxdata/telegraf/pull/10284) `inputs.openstack` Fix typo in openstack neutron input plugin (newtron) + +### Features + +- [#10239](https://github.com/influxdata/telegraf/pull/10239) Enable Darwin arm64 build +- [#10150](https://github.com/influxdata/telegraf/pull/10150) `inputs.smart` Add SMART plugin concurrency configuration option, nvme-cli v1.14+ support and lint fixes. +- [#10150](https://github.com/influxdata/telegraf/pull/10150) `inputs.smart` Add SMART plugin concurrency configuration option, nvme-cli v1.14+ support and lint fixes + +## v1.21.0 [2021-12-15] + +### Release Notes + +The signing for RPM digest has changed to use sha256 to improve security. Please see the pull request for more details: [#10272](https://github.com/influxdata/telegraf/pull/10272). + +Thank you to @zak-pawel for lots of linter fixes! + +### Bugfixes + +- [#10268](https://github.com/influxdata/telegraf/pull/10268) `inputs.snmp` Update snmp plugin to respect number of retries configured +- [#10225](https://github.com/influxdata/telegraf/pull/10225) `outputs.wavefront` Flush wavefront output sender on error to clean up broken connections +- [#9970](https://github.com/influxdata/telegraf/pull/9970) Restart Telegraf service if it is already running and upgraded via RPM +- [#10188](https://github.com/influxdata/telegraf/pull/10188) `parsers.xpath` Handle duplicate registration of protocol-buffer files gracefully +- [#10132](https://github.com/influxdata/telegraf/pull/10132) `inputs.http_listener_v2` Fix panic on close to check that Telegraf is closing +- [#10196](https://github.com/influxdata/telegraf/pull/10196) `outputs.elasticsearch` Implement NaN and inf handling for elasticsearch output +- [#10205](https://github.com/influxdata/telegraf/pull/10205) Print loaded plugins and deprecations for once and test flags +- [#10214](https://github.com/influxdata/telegraf/pull/10214) `processors.ifname` Eliminate MIB dependency for ifname processor +- [#10206](https://github.com/influxdata/telegraf/pull/10206) `inputs.snmp` Optimize locking for SNMP MIBs loading +- [#9975](https://github.com/influxdata/telegraf/pull/9975) `inputs.kube_inventory` Set TLS server name config properly +- [#10230](https://github.com/influxdata/telegraf/pull/10230) Sudden close of Telegraf caused by OPC UA input plugin +- [#9913](https://github.com/influxdata/telegraf/pull/9913) Update eclipse/paho.mqtt.golang module from 1.3.0 to 1.3.5 +- [#10221](https://github.com/influxdata/telegraf/pull/10221) `parsers.json_v2` Parser timestamp setting order +- [#10209](https://github.com/influxdata/telegraf/pull/10209) `outputs.graylog` Ensure graylog spec fields not prefixed with _ +- [#10099](https://github.com/influxdata/telegraf/pull/10099) `inputs.zfs` Pool detection and metrics gathering for ZFS >= 2.1.x +- [#10007](https://github.com/influxdata/telegraf/pull/10007) `processors.ifname` Parallelism fix for ifname processor +- [#10208](https://github.com/influxdata/telegraf/pull/10208) `inputs.mqtt_consumer` Mqtt topic extracting no longer requires all three fields +- [#9616](https://github.com/influxdata/telegraf/pull/9616) Windows Service - graceful shutdown of telegraf +- [#10203](https://github.com/influxdata/telegraf/pull/10203) Revert unintended corruption of the Makefile +- [#10112](https://github.com/influxdata/telegraf/pull/10112) `inputs.cloudwatch` Cloudwatch metrics collection +- [#10178](https://github.com/influxdata/telegraf/pull/10178) `outputs.all` Register bigquery to output plugins +- [#10165](https://github.com/influxdata/telegraf/pull/10165) `inputs.sysstat` Sysstat to use unique temp file vs hard-coded +- [#10046](https://github.com/influxdata/telegraf/pull/10046) Update nats-sever to support openbsd +- [#10091](https://github.com/influxdata/telegraf/pull/10091) `inputs.prometheus` Check error before defer in prometheus k8s +- [#10101](https://github.com/influxdata/telegraf/pull/10101) `inputs.win_perf_counters` Add setting to win_perf_counters input to ignore localization +- [#10136](https://github.com/influxdata/telegraf/pull/10136) `inputs.snmp_trap` Remove snmptranslate from readme and fix default path +- [#10116](https://github.com/influxdata/telegraf/pull/10116) `inputs.statsd` Input plugin statsd parse error +- [#10131](https://github.com/influxdata/telegraf/pull/10131) Skip knxlistener when writing the sample config +- [#10119](https://github.com/influxdata/telegraf/pull/10119) `inputs.cpu` Update shirou/gopsutil from v2 to v3 +- [#10074](https://github.com/influxdata/telegraf/pull/10074) `outputs.graylog` Failing test due to port already in use +- [#9865](https://github.com/influxdata/telegraf/pull/9865) `inputs.directory_monitor` Directory monitor input plugin when data format is CSV and csv_skip_rows>0 and csv_header_row_count>=1 +- [#9862](https://github.com/influxdata/telegraf/pull/9862) `outputs.graylog` Graylog plugin TLS support and message format +- [#9908](https://github.com/influxdata/telegraf/pull/9908) `parsers.json_v2` Remove dead code +- [#9881](https://github.com/influxdata/telegraf/pull/9881) `outputs.graylog` Mute graylog UDP/TCP tests by marking them as integration +- [#9751](https://github.com/influxdata/telegraf/pull/9751) Update google.golang.org/grpc module from 1.39.1 to 1.40.0 + +### Features + +- [#10200](https://github.com/influxdata/telegraf/pull/10200) `aggregators.deprecations.go` Implement deprecation infrastructure +- [#9518](https://github.com/influxdata/telegraf/pull/9518) `inputs.snmp` Snmp to use gosmi +- [#10130](https://github.com/influxdata/telegraf/pull/10130) `outputs.influxdb_v2` Add retry to 413 errors with InfluxDB output +- [#10144](https://github.com/influxdata/telegraf/pull/10144) `inputs.win_services` Add exclude filter +- [#9995](https://github.com/influxdata/telegraf/pull/9995) `inputs.mqtt_consumer` Enable extracting tag values from MQTT topics +- [#9419](https://github.com/influxdata/telegraf/pull/9419) `aggregators.all` Add support of aggregator as Starlark script +- [#9561](https://github.com/influxdata/telegraf/pull/9561) `processors.regex` Extend regexp processor do allow renaming of measurements, tags and fields +- [#8184](https://github.com/influxdata/telegraf/pull/8184) `outputs.http` Add use_batch_format for HTTP output plugin +- [#9988](https://github.com/influxdata/telegraf/pull/9988) `inputs.kafka_consumer` Add max_processing_time config to Kafka Consumer input +- [#9841](https://github.com/influxdata/telegraf/pull/9841) `inputs.sqlserver` Add additional metrics to support elastic pool (sqlserver plugin) +- [#9910](https://github.com/influxdata/telegraf/pull/9910) `common.tls` Filter client certificates by DNS names +- [#9942](https://github.com/influxdata/telegraf/pull/9942) `outputs.azure_data_explorer` Add option to skip table creation in azure data explorer output +- [#9984](https://github.com/influxdata/telegraf/pull/9984) `processors.ifname` Add more details to logmessages +- [#9833](https://github.com/influxdata/telegraf/pull/9833) `common.kafka` Add metadata full to config +- [#9876](https://github.com/influxdata/telegraf/pull/9876) Update etc/telegraf.conf and etc/telegraf_windows.conf +- [#9256](https://github.com/influxdata/telegraf/pull/9256) `inputs.modbus` Modbus connection settings (serial) +- [#9860](https://github.com/influxdata/telegraf/pull/9860) `inputs.directory_monitor` Adds the ability to create and name a tag containing the filename using the directory monitor input plugin +- [#9740](https://github.com/influxdata/telegraf/pull/9740) `inputs.prometheus` Add ignore_timestamp option +- [#9513](https://github.com/influxdata/telegraf/pull/9513) `processors.starlark` Starlark processor example for processing sparkplug_b messages +- [#9449](https://github.com/influxdata/telegraf/pull/9449) `parsers.json_v2` Support defining field/tag tables within an object table +- [#9827](https://github.com/influxdata/telegraf/pull/9827) `inputs.elasticsearch_query` Add debug query output to elasticsearch_query +- [#9241](https://github.com/influxdata/telegraf/pull/9241) `inputs.snmp` Telegraf to merge tables with different indexes +- [#9013](https://github.com/influxdata/telegraf/pull/9013) `inputs.opcua` Allow user to select the source for the metric timestamp. +- [#9706](https://github.com/influxdata/telegraf/pull/9706) `inputs.puppetagent` Add measurements from puppet 5 +- [#9644](https://github.com/influxdata/telegraf/pull/9644) `outputs.graylog` Add graylog plugin TCP support +- [#8229](https://github.com/influxdata/telegraf/pull/8229) `outputs.azure_data_explorer` Add json_timestamp_layout option + +### New Input Plugins + +- [#9724](https://github.com/influxdata/telegraf/pull/9724) Add intel_pmu plugin +- [#9771](https://github.com/influxdata/telegraf/pull/9771) Add Linux Volume Manager input plugin +- [#9236](https://github.com/influxdata/telegraf/pull/9236) Openstack input plugin + +### New Output Plugins + +- [#9891](https://github.com/influxdata/telegraf/pull/9891) Add new groundwork output plugin +- [#9923](https://github.com/influxdata/telegraf/pull/9923) Add mongodb output plugin +- [#9346](https://github.com/influxdata/telegraf/pull/9346) Azure Event Hubs output plugin + +## v1.20.4 [2021-11-17] + +### Release Notes + +- [#10073](https://github.com/influxdata/telegraf/pull/10073) Update go version from 1.17.2 to 1.17.3 +- [#10100](https://github.com/influxdata/telegraf/pull/10100) Update deprecated plugin READMEs to better indicate deprecation + +Thank you to @zak-pawel for lots of linter fixes! + +- [#9986](https://github.com/influxdata/telegraf/pull/9986) Linter fixes for plugins/inputs/[h-j]* +- [#9999](https://github.com/influxdata/telegraf/pull/9999) Linter fixes for plugins/inputs/[k-l]* +- [#10006](https://github.com/influxdata/telegraf/pull/10006) Linter fixes for plugins/inputs/m* +- [#10011](https://github.com/influxdata/telegraf/pull/10011) Linter fixes for plugins/inputs/[n-o]* + +### Bugfixes + +- [#10089](https://github.com/influxdata/telegraf/pull/10089) Update BurntSushi/toml from 0.3.1 to 0.4.1 +- [#10075](https://github.com/influxdata/telegraf/pull/10075) `inputs.mongodb` Update readme with correct connection URI +- [#10076](https://github.com/influxdata/telegraf/pull/10076) Update gosnmp module from 1.32 to 1.33 +- [#9966](https://github.com/influxdata/telegraf/pull/9966) `inputs.mysql` Fix type conversion follow-up +- [#10068](https://github.com/influxdata/telegraf/pull/10068) `inputs.proxmox` Changed VM ID from string to int +- [#10047](https://github.com/influxdata/telegraf/pull/10047) `inputs.modbus` Do not build modbus on openbsd +- [#10019](https://github.com/influxdata/telegraf/pull/10019) `inputs.cisco_telemetry_mdt` Move to new protobuf library +- [#10001](https://github.com/influxdata/telegraf/pull/10001) `outputs.loki` Add metric name with label "__name" +- [#9980](https://github.com/influxdata/telegraf/pull/9980) `inputs.nvidia_smi` Set the default path correctly +- [#10010](https://github.com/influxdata/telegraf/pull/10010) Update go.opentelemetry.io/otel from v0.23.0 to v0.24.0 +- [#10044](https://github.com/influxdata/telegraf/pull/10044) `inputs.sqlserver` Add elastic pool in supported versions in sqlserver +- [#10029](https://github.com/influxdata/telegraf/pull/10029) `inputs.influxdb` Update influxdb input schema docs +- [#10026](https://github.com/influxdata/telegraf/pull/10026) `inputs.intel_rdt` Correct timezone handling + +## v1.20.3 [2021-10-27] + +### Release Notes + +- [#9873](https://github.com/influxdata/telegraf/pull/9873) Update go to 1.17.2 + +### Bugfixes + +- [#9948](https://github.com/influxdata/telegraf/pull/9948) Update github.com/aws/aws-sdk-go-v2/config module from 1.8.2 to 1.8.3 +- [#9997](https://github.com/influxdata/telegraf/pull/9997) `inputs.ipmi_sensor` Redact IPMI password in logs +- [#9978](https://github.com/influxdata/telegraf/pull/9978) `inputs.kube_inventory` Do not skip resources with zero s/ns timestamps +- [#9998](https://github.com/influxdata/telegraf/pull/9998) Update gjson module to v1.10.2 +- [#9973](https://github.com/influxdata/telegraf/pull/9973) `inputs.procstat` Revert and fix tag creation +- [#9943](https://github.com/influxdata/telegraf/pull/9943) `inputs.sqlserver` Add sqlserver plugin integration tests +- [#9647](https://github.com/influxdata/telegraf/pull/9647) `inputs.cloudwatch` Use the AWS SDK v2 library +- [#9954](https://github.com/influxdata/telegraf/pull/9954) `processors.starlark` Starlark pop operation for non-existing keys +- [#9956](https://github.com/influxdata/telegraf/pull/9956) `inputs.zfs` Check return code of zfs command for FreeBSD +- [#9585](https://github.com/influxdata/telegraf/pull/9585) `inputs.kube_inventory` Fix segfault in ingress, persistentvolumeclaim, statefulset in kube_inventory +- [#9901](https://github.com/influxdata/telegraf/pull/9901) `inputs.ethtool` Add normalization of tags for ethtool input plugin +- [#9957](https://github.com/influxdata/telegraf/pull/9957) `inputs.internet_speed` Resolve missing latency field +- [#9662](https://github.com/influxdata/telegraf/pull/9662) `inputs.prometheus` Decode Prometheus scrape path from Kubernetes labels +- [#9933](https://github.com/influxdata/telegraf/pull/9933) `inputs.procstat` Correct conversion of int with specific bit size +- [#9940](https://github.com/influxdata/telegraf/pull/9940) `inputs.webhooks` Provide more fields for papertrail event webhook +- [#9892](https://github.com/influxdata/telegraf/pull/9892) `inputs.mongodb` Solve compatibility issue for mongodb inputs when using 5.x relicaset +- [#9768](https://github.com/influxdata/telegraf/pull/9768) Update github.com/Azure/azure-kusto-go module from 0.3.2 to 0.4.0 +- [#9904](https://github.com/influxdata/telegraf/pull/9904) Update github.com/golang-jwt/jwt/v4 module from 4.0.0 to 4.1.0 +- [#9921](https://github.com/influxdata/telegraf/pull/9921) Update github.com/apache/thrift module from 0.14.2 to 0.15.0 +- [#9403](https://github.com/influxdata/telegraf/pull/9403) `inputs.mysql`Fix inconsistent metric types in mysql +- [#9905](https://github.com/influxdata/telegraf/pull/9905) Update github.com/docker/docker module from 20.10.7+incompatible to 20.10.9+incompatible +- [#9920](https://github.com/influxdata/telegraf/pull/9920) `inputs.prometheus` Move err check to correct place +- [#9869](https://github.com/influxdata/telegraf/pull/9869) Update github.com/prometheus/common module from 0.26.0 to 0.31.1 +- [#9866](https://github.com/influxdata/telegraf/pull/9866) Update snowflake database driver module to 1.6.2 +- [#9527](https://github.com/influxdata/telegraf/pull/9527) `inputs.intel_rdt` Allow sudo usage +- [#9893](https://github.com/influxdata/telegraf/pull/9893) Update github.com/jaegertracing/jaeger module from 1.15.1 to 1.26.0 + +### New External Plugins + +- [IBM DB2](https://github.com/bonitoo-io/telegraf-input-db2) - contributed by @sranka +- [Oracle Database](https://github.com/bonitoo-io/telegraf-input-oracle) - contributed by @sranka + +## v1.20.2 [2021-10-07] + +### Bugfixes + +- [#9878](https://github.com/influxdata/telegraf/pull/9878) `inputs.cloudwatch` Use new session API +- [#9872](https://github.com/influxdata/telegraf/pull/9872) `parsers.json_v2` Duplicate line_protocol when using object and fields +- [#9787](https://github.com/influxdata/telegraf/pull/9787) `parsers.influx` Fix memory leak in influx parser +- [#9880](https://github.com/influxdata/telegraf/pull/9880) `inputs.stackdriver` Migrate to cloud.google.com/go/monitoring/apiv3/v2 +- [#9887](https://github.com/influxdata/telegraf/pull/9887) Fix makefile typo that prevented i386 tar and rpm packages from being built + +## v1.20.1 [2021-10-06] + +### Bugfixes + +- [#9776](https://github.com/influxdata/telegraf/pull/9776) Update k8s.io/apimachinery module from 0.21.1 to 0.22.2 +- [#9864](https://github.com/influxdata/telegraf/pull/9864) Update containerd module to v1.5.7 +- [#9863](https://github.com/influxdata/telegraf/pull/9863) Update consul module to v1.11.0 +- [#9846](https://github.com/influxdata/telegraf/pull/9846) `inputs.mongodb` Fix panic due to nil dereference +- [#9850](https://github.com/influxdata/telegraf/pull/9850) `inputs.intel_rdt` Prevent timeout when logging +- [#9848](https://github.com/influxdata/telegraf/pull/9848) `outputs.loki` Update http_headers setting to match sample config +- [#9808](https://github.com/influxdata/telegraf/pull/9808) `inputs.procstat` Add missing tags +- [#9803](https://github.com/influxdata/telegraf/pull/9803) `outputs.mqtt` Add keep alive config option and documentation around issue with eclipse/mosquitto version +- [#9800](https://github.com/influxdata/telegraf/pull/9800) Fix output buffer never completely flushing +- [#9458](https://github.com/influxdata/telegraf/pull/9458) `inputs.couchbase` Fix insecure certificate validation +- [#9797](https://github.com/influxdata/telegraf/pull/9797) `inputs.opentelemetry` Fix error returned to OpenTelemetry client +- [#9789](https://github.com/influxdata/telegraf/pull/9789) Update github.com/testcontainers/testcontainers-go module from 0.11.0 to 0.11.1 +- [#9791](https://github.com/influxdata/telegraf/pull/9791) Update github.com/Azure/go-autorest/autorest/adal module +- [#9678](https://github.com/influxdata/telegraf/pull/9678) Update github.com/Azure/go-autorest/autorest/azure/auth module from 0.5.6 to 0.5.8 +- [#9769](https://github.com/influxdata/telegraf/pull/9769) Update cloud.google.com/go/pubsub module from 1.15.0 to 1.17.0 +- [#9770](https://github.com/influxdata/telegraf/pull/9770) Update github.com/aws/smithy-go module from 1.3.1 to 1.8.0 + +### Features + +- [#9838](https://github.com/influxdata/telegraf/pull/9838) `inputs.elasticsearch_query` Add custom time/date format field + +## v1.20.0 [2021-09-17] + +### Release Notes + +- [#9642](https://github.com/influxdata/telegraf/pull/9642) Build with Golang 1.17 + +### Bugfixes + +- [#9700](https://github.com/influxdata/telegraf/pull/9700) Update thrift module to 0.14.2 and zipkin-go-opentracing to 0.4.5 +- [#9587](https://github.com/influxdata/telegraf/pull/9587) `outputs.opentelemetry` Use headers config in grpc requests +- [#9713](https://github.com/influxdata/telegraf/pull/9713) Update runc module to v1.0.0-rc95 to address CVE-2021-30465 +- [#9699](https://github.com/influxdata/telegraf/pull/9699) Migrate dgrijalva/jwt-go to golang-jwt/jwt/v4 +- [#9139](https://github.com/influxdata/telegraf/pull/9139) `serializers.prometheus` Update timestamps and expiration time as new data arrives +- [#9625](https://github.com/influxdata/telegraf/pull/9625) `outputs.graylog` Output timestamp with fractional seconds +- [#9655](https://github.com/influxdata/telegraf/pull/9655) Update cloud.google.com/go/pubsub module from 1.2.0 to 1.15.0 +- [#9674](https://github.com/influxdata/telegraf/pull/9674) `inputs.mongodb` Change command based on server version +- [#9676](https://github.com/influxdata/telegraf/pull/9676) `outputs.dynatrace` Remove hardcoded int value +- [#9619](https://github.com/influxdata/telegraf/pull/9619) `outputs.influxdb_v2` Increase accepted retry-after header values. +- [#9652](https://github.com/influxdata/telegraf/pull/9652) Update tinylib/msgp module from 1.1.5 to 1.1.6 +- [#9471](https://github.com/influxdata/telegraf/pull/9471) `inputs.sql` Make timeout apply to single query +- [#9760](https://github.com/influxdata/telegraf/pull/9760) Update shirou/gopsutil module to 3.21.8 +- [#9707](https://github.com/influxdata/telegraf/pull/9707) `inputs.logstash` Add additional logstash output plugin stats +- [#9656](https://github.com/influxdata/telegraf/pull/9656) Update miekg/dns module from 1.1.31 to 1.1.43 +- [#9750](https://github.com/influxdata/telegraf/pull/9750) Update antchfx/xmlquery module from 1.3.5 to 1.3.6 +- [#9757](https://github.com/influxdata/telegraf/pull/9757) `parsers.registry.go` Fix panic for non-existing metric names +- [#9677](https://github.com/influxdata/telegraf/pull/9677) Update Azure/azure-event-hubs-go/v3 module from 3.2.0 to 3.3.13 +- [#9653](https://github.com/influxdata/telegraf/pull/9653) Update prometheus/client_golang module from 1.7.1 to 1.11.0 +- [#9693](https://github.com/influxdata/telegraf/pull/9693) `inputs.cloudwatch` Fix pagination error +- [#9727](https://github.com/influxdata/telegraf/pull/9727) `outputs.http` Add error message logging +- [#9718](https://github.com/influxdata/telegraf/pull/9718) Update influxdata/influxdb-observability module from 0.2.4 to 0.2.7 +- [#9560](https://github.com/influxdata/telegraf/pull/9560) Update gopcua/opcua module +- [#9544](https://github.com/influxdata/telegraf/pull/9544) `inputs.couchbase` Fix memory leak +- [#9588](https://github.com/influxdata/telegraf/pull/9588) `outputs.opentelemetry` Use attributes setting + +### Features + +- [#9665](https://github.com/influxdata/telegraf/pull/9665) `inputs.systemd_units` feat(plugins/inputs/systemd_units): add pattern support +- [#9598](https://github.com/influxdata/telegraf/pull/9598) `outputs.sql` Add bool datatype +- [#9386](https://github.com/influxdata/telegraf/pull/9386) `inputs.cloudwatch` Pull metrics from multiple AWS CloudWatch namespaces +- [#9411](https://github.com/influxdata/telegraf/pull/9411) `inputs.cloudwatch` Support AWS Web Identity Provider +- [#9570](https://github.com/influxdata/telegraf/pull/9570) `inputs.modbus` Add support for RTU over TCP +- [#9488](https://github.com/influxdata/telegraf/pull/9488) `inputs.procstat` Support cgroup globs and include systemd unit children +- [#9322](https://github.com/influxdata/telegraf/pull/9322) `inputs.suricata` Support alert event type +- [#5464](https://github.com/influxdata/telegraf/pull/5464) `inputs.prometheus` Add ability to query Consul Service catalog +- [#8641](https://github.com/influxdata/telegraf/pull/8641) `outputs.prometheus_client` Add Landing page +- [#9529](https://github.com/influxdata/telegraf/pull/9529) `inputs.http_listener_v2` Allows multiple paths and add path_tag +- [#9395](https://github.com/influxdata/telegraf/pull/9395) Add cookie authentication to HTTP input and output plugins +- [#8454](https://github.com/influxdata/telegraf/pull/8454) `inputs.syslog` Add RFC3164 support +- [#9351](https://github.com/influxdata/telegraf/pull/9351) `inputs.jenkins` Add option to include nodes by name +- [#9277](https://github.com/influxdata/telegraf/pull/9277) Add JSON, MessagePack, and Protocol-buffers format support to the XPath parser +- [#9343](https://github.com/influxdata/telegraf/pull/9343) `inputs.snmp_trap` Improve MIB lookup performance +- [#9342](https://github.com/influxdata/telegraf/pull/9342) `outputs.newrelic` Add option to override metric_url +- [#9306](https://github.com/influxdata/telegraf/pull/9306) `inputs.smart` Add power mode status +- [#9762](https://github.com/influxdata/telegraf/pull/9762) `inputs.bond` Add count of bonded slaves (for easier alerting) +- [#9675](https://github.com/influxdata/telegraf/pull/9675) `outputs.dynatrace` Remove special handling from counters and update dynatrace-oss/dynatrace-metric-utils-go module to 0.3.0 + +### New Input Plugins + +- [#9602](https://github.com/influxdata/telegraf/pull/9602) Add rocm_smi input to monitor AMD GPUs +- [#9101](https://github.com/influxdata/telegraf/pull/9101) Add mdstat input to gather from /proc/mdstat collection +- [#3536](https://github.com/influxdata/telegraf/pull/3536) Add Elasticsearch query input +- [#9623](https://github.com/influxdata/telegraf/pull/9623) Add internet Speed Monitor Input Plugin + +### New Output Plugins + +- [#9228](https://github.com/influxdata/telegraf/pull/9228) Add OpenTelemetry output +- [#9426](https://github.com/influxdata/telegraf/pull/9426) Add Azure Data Explorer(ADX) output + +## v1.19.3 [2021-08-18] + +### Bugfixes + +- [#9639](https://github.com/influxdata/telegraf/pull/9639) Update sirupsen/logrus module from 1.7.0 to 1.8.1 +- [#9638](https://github.com/influxdata/telegraf/pull/9638) Update testcontainers/testcontainers-go module from 0.11.0 to 0.11.1 +- [#9637](https://github.com/influxdata/telegraf/pull/9637) Update golang/snappy module from 0.0.3 to 0.0.4 +- [#9636](https://github.com/influxdata/telegraf/pull/9636) Update aws/aws-sdk-go-v2 module from 1.3.2 to 1.8.0 +- [#9605](https://github.com/influxdata/telegraf/pull/9605) `inputs.prometheus` Fix prometheus kubernetes pod discovery +- [#9606](https://github.com/influxdata/telegraf/pull/9606) `inputs.redis` Improve redis commands documentation +- [#9566](https://github.com/influxdata/telegraf/pull/9566) `outputs.cratedb` Replace dots in tag keys with underscores +- [#9401](https://github.com/influxdata/telegraf/pull/9401) `inputs.clickhouse` Fix panic, improve handling empty result set +- [#9583](https://github.com/influxdata/telegraf/pull/9583) `inputs.opcua` Avoid closing session on a closed connection +- [#9576](https://github.com/influxdata/telegraf/pull/9576) `processors.aws` Refactor ec2 init for config-api +- [#9571](https://github.com/influxdata/telegraf/pull/9571) `outputs.loki` Sort logs by timestamp before writing to Loki +- [#9524](https://github.com/influxdata/telegraf/pull/9524) `inputs.opcua` Fix reconnection regression introduced in 1.19.1 +- [#9581](https://github.com/influxdata/telegraf/pull/9581) `inputs.kube_inventory` Fix k8s nodes and pods parsing error +- [#9577](https://github.com/influxdata/telegraf/pull/9577) Update sensu/go module to v2.9.0 +- [#9554](https://github.com/influxdata/telegraf/pull/9554) `inputs.postgresql` Normalize unix socket path +- [#9565](https://github.com/influxdata/telegraf/pull/9565) Update hashicorp/consul/api module to 1.9.1 +- [#9552](https://github.com/influxdata/telegraf/pull/9552) `inputs.vsphere` Update vmware/govmomi module to v0.26.0 in order to support vSphere 7.0 +- [#9550](https://github.com/influxdata/telegraf/pull/9550) `inputs.opcua` Do not skip good quality nodes after a bad quality node is encountered + +## v1.19.2 [2021-07-28] + +### Release Notes + +- [#9542](https://github.com/influxdata/telegraf/pull/9542) Update Go to v1.16.6 + +### Bugfixes + +- [#9363](https://github.com/influxdata/telegraf/pull/9363) `outputs.dynatrace` Update dynatrace output to allow optional default dimensions +- [#9526](https://github.com/influxdata/telegraf/pull/9526) `outputs.influxdb` Fix metrics reported as written but not actually written +- [#9549](https://github.com/influxdata/telegraf/pull/9549) `inputs.kube_inventory` Prevent segfault in persistent volume claims +- [#9503](https://github.com/influxdata/telegraf/pull/9503) `inputs.nsq_consumer` Fix connection error when not using server setting +- [#9540](https://github.com/influxdata/telegraf/pull/9540) `inputs.sql` Fix handling bool column +- [#9387](https://github.com/influxdata/telegraf/pull/9387) Linter fixes for plugins/inputs/[fg]* +- [#9438](https://github.com/influxdata/telegraf/pull/9438) `inputs.kubernetes` Attach the pod labels to kubernetes_pod_volume and kubernetes_pod_network metrics +- [#9519](https://github.com/influxdata/telegraf/pull/9519) `processors.ifname` Fix SNMP empty metric name +- [#8587](https://github.com/influxdata/telegraf/pull/8587) `inputs.sqlserver` Add tempdb troubleshooting stats and missing V2 query metrics +- [#9323](https://github.com/influxdata/telegraf/pull/9323) `inputs.x509_cert` Prevent x509_cert from hanging on UDP connection +- [#9504](https://github.com/influxdata/telegraf/pull/9504) `parsers.json_v2` Simplify how nesting is handled +- [#9493](https://github.com/influxdata/telegraf/pull/9493) `inputs.mongodb` Switch to official mongo-go-driver module to fix SSL auth failure +- [#9491](https://github.com/influxdata/telegraf/pull/9491) `outputs.dynatrace` Fix panic caused by uninitialized loggedMetrics map +- [#9497](https://github.com/influxdata/telegraf/pull/9497) `inputs.prometheus` Fix prometheus cadvisor authentication +- [#9520](https://github.com/influxdata/telegraf/pull/9520) `parsers.json_v2` Add support for large uint64 and int64 numbers +- [#9447](https://github.com/influxdata/telegraf/pull/9447) `inputs.statsd` Fix regression that didn't allow integer percentiles +- [#9466](https://github.com/influxdata/telegraf/pull/9466) `inputs.sqlserver` Provide detailed error message in telegraf log +- [#9399](https://github.com/influxdata/telegraf/pull/9399) Update dynatrace-metric-utils-go module to v0.2.0 +- [#8108](https://github.com/influxdata/telegraf/pull/8108) `inputs.cgroup` Allow multiple keys when parsing cgroups +- [#9479](https://github.com/influxdata/telegraf/pull/9479) `parsers.json_v2` Fix json_v2 parser to handle nested objects in arrays properly + +### Features + +- [#9485](https://github.com/influxdata/telegraf/pull/9485) Add option to automatically reload settings when config file is modified + +## v1.19.1 [2021-07-07] + +### Bugfixes + +- [#9388](https://github.com/influxdata/telegraf/pull/9388) `inputs.sqlserver` Require authentication method to be specified +- [#9456](https://github.com/influxdata/telegraf/pull/9456) `inputs.kube_inventory` Fix segfault in kube_inventory +- [#9448](https://github.com/influxdata/telegraf/pull/9448) `inputs.couchbase` Fix panic +- [#9444](https://github.com/influxdata/telegraf/pull/9444) `inputs.knx_listener` Fix nil pointer panic +- [#9446](https://github.com/influxdata/telegraf/pull/9446) `inputs.procstat` Update gopsutil module to fix panic +- [#9443](https://github.com/influxdata/telegraf/pull/9443) `inputs.rabbitmq` Fix JSON unmarshall regression +- [#9369](https://github.com/influxdata/telegraf/pull/9369) Update nat-server module to v2.2.6 +- [#9429](https://github.com/influxdata/telegraf/pull/9429) `inputs.dovecot` Exclude read-timeout from being an error +- [#9423](https://github.com/influxdata/telegraf/pull/9423) `inputs.statsd` Don't stop parsing after parsing error +- [#9370](https://github.com/influxdata/telegraf/pull/9370) Update apimachinary module to v0.21.1 +- [#9373](https://github.com/influxdata/telegraf/pull/9373) Update jwt module to v1.2.2 and jwt-go module to v3.2.3 +- [#9412](https://github.com/influxdata/telegraf/pull/9412) Update couchbase Module to v0.1.0 +- [#9366](https://github.com/influxdata/telegraf/pull/9366) `inputs.snmp` Add a check for oid and name to prevent empty metrics +- [#9413](https://github.com/influxdata/telegraf/pull/9413) `outputs.http` Fix toml error when parsing insecure_skip_verify +- [#9400](https://github.com/influxdata/telegraf/pull/9400) `inputs.x509_cert` Fix 'source' tag for https +- [#9375](https://github.com/influxdata/telegraf/pull/9375) Update signalfx module to v3.3.34 +- [#9406](https://github.com/influxdata/telegraf/pull/9406) `parsers.json_v2` Don't require tags to be added to included_keys +- [#9289](https://github.com/influxdata/telegraf/pull/9289) `inputs.x509_cert` Fix SNI support +- [#9372](https://github.com/influxdata/telegraf/pull/9372) Update gjson module to v1.8.0 +- [#9379](https://github.com/influxdata/telegraf/pull/9379) Linter fixes for plugins/inputs/[de]* + +## v1.19.0 [2021-06-17] + +### Release Notes + +- Many linter fixes - thanks @zak-pawel and all! +- [#9331](https://github.com/influxdata/telegraf/pull/9331) Update Go to 1.16.5 + +### Bugfixes + +- [#9182](https://github.com/influxdata/telegraf/pull/9182) Update pgx to v4 +- [#9275](https://github.com/influxdata/telegraf/pull/9275) Fix reading config files starting with http: +- [#9196](https://github.com/influxdata/telegraf/pull/9196) `serializers.prometheusremotewrite` Update dependency and remove tags with empty values +- [#9051](https://github.com/influxdata/telegraf/pull/9051) `outputs.kafka` Don't prevent telegraf from starting when there's a connection error +- [#8795](https://github.com/influxdata/telegraf/pull/8795) `parsers.prometheusremotewrite` Update prometheus dependency to v2.21.0 +- [#9295](https://github.com/influxdata/telegraf/pull/9295) `outputs.dynatrace` Use dynatrace-metric-utils +- [#9368](https://github.com/influxdata/telegraf/pull/9368) `parsers.json_v2` Update json_v2 parser to handle null types +- [#9359](https://github.com/influxdata/telegraf/pull/9359) `inputs.sql` Fix import of sqlite and ignore it on all platforms that require CGO. +- [#9329](https://github.com/influxdata/telegraf/pull/9329) `inputs.kube_inventory` Fix connecting to the wrong url +- [#9358](https://github.com/influxdata/telegraf/pull/9358) upgrade denisenkom go-mssql to v0.10.0 +- [#9283](https://github.com/influxdata/telegraf/pull/9283) `processors.parser` Fix segfault +- [#9243](https://github.com/influxdata/telegraf/pull/9243) `inputs.docker` Close all idle connections +- [#9338](https://github.com/influxdata/telegraf/pull/9338) `inputs.suricata` Support new JSON format +- [#9296](https://github.com/influxdata/telegraf/pull/9296) `outputs.influxdb` Fix endless retries + +### Features + +- [#8987](https://github.com/influxdata/telegraf/pull/8987) Config file environment variable can be a URL +- [#9297](https://github.com/influxdata/telegraf/pull/9297) `outputs.datadog` Add HTTP proxy to datadog output +- [#9087](https://github.com/influxdata/telegraf/pull/9087) Add named timestamp formats +- [#9276](https://github.com/influxdata/telegraf/pull/9276) `inputs.vsphere` Add config option for the historical interval duration +- [#9274](https://github.com/influxdata/telegraf/pull/9274) `inputs.ping` Add an option to specify packet size +- [#9007](https://github.com/influxdata/telegraf/pull/9007) Allow multiple "--config" and "--config-directory" flags +- [#9249](https://github.com/influxdata/telegraf/pull/9249) `outputs.graphite` Allow more characters in graphite tags +- [#8351](https://github.com/influxdata/telegraf/pull/8351) `inputs.sqlserver` Added login_name +- [#9223](https://github.com/influxdata/telegraf/pull/9223) `inputs.dovecot` Add support for unix domain sockets +- [#9118](https://github.com/influxdata/telegraf/pull/9118) `processors.strings` Add UTF-8 sanitizer +- [#9156](https://github.com/influxdata/telegraf/pull/9156) `inputs.aliyuncms` Add config option list of regions to query +- [#9138](https://github.com/influxdata/telegraf/pull/9138) `common.http` Add OAuth2 to HTTP input +- [#8822](https://github.com/influxdata/telegraf/pull/8822) `inputs.sqlserver` Enable Azure Active Directory (AAD) authentication support +- [#9136](https://github.com/influxdata/telegraf/pull/9136) `inputs.cloudwatch` Add wildcard support in dimensions configuration +- [#5517](https://github.com/influxdata/telegraf/pull/5517) `inputs.mysql` Gather all mysql channels +- [#8911](https://github.com/influxdata/telegraf/pull/8911) `processors.enum` Support float64 +- [#9105](https://github.com/influxdata/telegraf/pull/9105) `processors.starlark` Support nanosecond resolution timestamp +- [#9080](https://github.com/influxdata/telegraf/pull/9080) `inputs.logstash` Add support for version 7 queue stats +- [#9074](https://github.com/influxdata/telegraf/pull/9074) `parsers.prometheusremotewrite` Add starlark script for renaming metrics +- [#9032](https://github.com/influxdata/telegraf/pull/9032) `inputs.couchbase` Add ~200 more Couchbase metrics via Buckets endpoint +- [#8596](https://github.com/influxdata/telegraf/pull/8596) `inputs.sqlserver` input/sqlserver: Add service and save connection pools +- [#9042](https://github.com/influxdata/telegraf/pull/9042) `processors.starlark` Add math module +- [#6952](https://github.com/influxdata/telegraf/pull/6952) `inputs.x509_cert` Wildcard support for cert filenames +- [#9004](https://github.com/influxdata/telegraf/pull/9004) `processors.starlark` Add time module +- [#8891](https://github.com/influxdata/telegraf/pull/8891) `inputs.kinesis_consumer` Add content_encoding option with gzip and zlib support +- [#8996](https://github.com/influxdata/telegraf/pull/8996) `processors.starlark` Add an example showing how to obtain IOPS from diskio input +- [#8966](https://github.com/influxdata/telegraf/pull/8966) `inputs.http_listener_v2` Add support for snappy compression +- [#8661](https://github.com/influxdata/telegraf/pull/8661) `inputs.cisco_telemetry_mdt` Add support for events and class based query +- [#8861](https://github.com/influxdata/telegraf/pull/8861) `inputs.mongodb` Optionally collect top stats +- [#8979](https://github.com/influxdata/telegraf/pull/8979) `parsers.value` Add custom field name config option +- [#8544](https://github.com/influxdata/telegraf/pull/8544) `inputs.sqlserver` Add an optional health metric + +### New Input Plugins + +- [Alibaba CloudMonitor Service (Aliyun)](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/aliyuncms) - contributed by @i-prudnikov +- [OpenTelemetry](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/opentelemetry) - contributed by @jacobmarble +- [Intel Data Plane Development Kit (DPDK)](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/dpdk) - contributed by @p-zak +- [KNX](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/knx_listener) - contributed by @DocLambda +- [SQL](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/sql) - contributed by @srebhan + +### New Output Plugins + +- [Websocket](https://github.com/influxdata/telegraf/tree/master/plugins/outputs/websocket) - contributed by @FZambia +- [SQL](https://github.com/influxdata/telegraf/tree/master/plugins/outputs/sql) - contributed by @illuusio +- [AWS Cloudwatch logs](https://github.com/influxdata/telegraf/tree/master/plugins/outputs/cloudwatch_logs) - contributed by @i-prudnikov + +### New Parser Plugins + +- [Prometheus Remote Write](https://github.com/influxdata/telegraf/tree/master/plugins/parsers/prometheusremotewrite) - contributed by @helenosheaa +- [JSON V2](https://github.com/influxdata/telegraf/tree/master/plugins/parsers/json_v2) - contributed by @sspaink + +### New External Plugins + +- [ldap_org and ds389](https://github.com/falon/CSI-telegraf-plugins) - contributed by @falon +- [x509_crl](https://github.com/jcgonnard/telegraf-input-x590crl) - contributed by @jcgonnard +- [dnsmasq](https://github.com/machinly/dnsmasq-telegraf-plugin) - contributed by @machinly +- [Big Blue Button](https://github.com/bigblueswarm/bigbluebutton-telegraf-plugin) - contributed by @SLedunois + +## v1.18.3 [2021-05-20] + +### Release Notes + +- Added FreeBSD armv7 build + +### Bugfixes + +- [#9271](https://github.com/influxdata/telegraf/pull/9271) `inputs.prometheus` Set user agent when scraping prom metrics +- [#9203](https://github.com/influxdata/telegraf/pull/9203) Migrate from soniah/gosnmp to gosnmp/gosnmp and update to 1.32.0 +- [#9169](https://github.com/influxdata/telegraf/pull/9169) `inputs.kinesis_consumer` Fix repeating parser error +- [#9130](https://github.com/influxdata/telegraf/pull/9130) `inputs.sqlserver` Remove disallowed whitespace from sqlServerRingBufferCPU query +- [#9238](https://github.com/influxdata/telegraf/pull/9238) Update hashicorp/consul/api module to v1.8.1 +- [#9235](https://github.com/influxdata/telegraf/pull/9235) Migrate from docker/libnetwork/ipvs to moby/ipvs +- [#9224](https://github.com/influxdata/telegraf/pull/9224) Update shirou/gopsutil to 3.21.3 +- [#9209](https://github.com/influxdata/telegraf/pull/9209) Update microsoft/ApplicationInsights-Go to 0.4.4 +- [#9190](https://github.com/influxdata/telegraf/pull/9190) Update gogo/protobuf to 1.3.2 +- [#8746](https://github.com/influxdata/telegraf/pull/8746) Update Azure/go-autorest/autorest/azure/auth to 0.5.6 and Azure/go-autorest/autorest to 0.11.17 +- [#8745](https://github.com/influxdata/telegraf/pull/8745) Update collectd.org to 0.5.0 +- [#8716](https://github.com/influxdata/telegraf/pull/8716) Update nats-io/nats.go 1.10.0 +- [#9039](https://github.com/influxdata/telegraf/pull/9039) Update golang/protobuf to v1.5.1 +- [#8937](https://github.com/influxdata/telegraf/pull/8937) Migrate from ericchiang/k8s to kubernetes/client-go + +### Features + +- [#8913](https://github.com/influxdata/telegraf/pull/8913) `outputs.elasticsearch` Add ability to enable gzip compression + +## v1.18.2 [2021-04-28] + +### Bugfixes + +- [#9160](https://github.com/influxdata/telegraf/pull/9160) `processors.converter` Add support for large hexadecimal strings +- [#9195](https://github.com/influxdata/telegraf/pull/9195) `inputs.apcupsd` Fix apcupsd 'ALARMDEL' bug via forked repo +- [#9110](https://github.com/influxdata/telegraf/pull/9110) `parsers.json` Make JSON format compatible with nulls +- [#9128](https://github.com/influxdata/telegraf/pull/9128) `inputs.nfsclient` Fix nfsclient ops map to allow collection of metrics other than read and write +- [#8917](https://github.com/influxdata/telegraf/pull/8917) `inputs.snmp` Log snmpv3 auth failures +- [#8892](https://github.com/influxdata/telegraf/pull/8892) `common.shim` Accept larger inputs from scanner +- [#9045](https://github.com/influxdata/telegraf/pull/9045) `inputs.vsphere` Add MetricLookback setting to handle reporting delays in vCenter 6.7 and later +- [#9026](https://github.com/influxdata/telegraf/pull/9026) `outputs.sumologic` Carbon2 serializer: sanitize metric name +- [#9086](https://github.com/influxdata/telegraf/pull/9086) `inputs.opcua` Fix error handling + +## v1.18.1 [2021-04-07] + +### Bugfixes + +- [#9082](https://github.com/influxdata/telegraf/pull/9082) `inputs.mysql` Fix 'binary logs' query for MySQL 8 +- [#9069](https://github.com/influxdata/telegraf/pull/9069) `inputs.tail` Add configurable option for the 'path' tag override +- [#9067](https://github.com/influxdata/telegraf/pull/9067) `inputs.nfsclient` Fix integer overflow in fields from mountstat +- [#9050](https://github.com/influxdata/telegraf/pull/9050) `inputs.snmp` Fix init when no mibs are installed +- [#9072](https://github.com/influxdata/telegraf/pull/9072) `inputs.ping` Always call SetPrivileged(true) in native mode +- [#9043](https://github.com/influxdata/telegraf/pull/9043) `processors.ifname` Get interface name more efficiently +- [#9056](https://github.com/influxdata/telegraf/pull/9056) `outputs.yandex_cloud_monitoring` Use correct compute metadata URL to get folder-id +- [#9048](https://github.com/influxdata/telegraf/pull/9048) `outputs.azure_monitor` Handle error when initializing the auth object +- [#8549](https://github.com/influxdata/telegraf/pull/8549) `inputs.sqlserver` Fix sqlserver_process_cpu calculation +- [#9035](https://github.com/influxdata/telegraf/pull/9035) `inputs.ipmi_sensor` Fix panic +- [#9009](https://github.com/influxdata/telegraf/pull/9009) `inputs.docker` Fix panic when parsing container stats +- [#8333](https://github.com/influxdata/telegraf/pull/8333) `inputs.exec` Don't truncate messages in debug mode +- [#8769](https://github.com/influxdata/telegraf/pull/8769) `agent` Close running outputs when reloadinlg + +## v1.18.0 [2021-03-17] + +### Release Notes + +- Support Go version 1.16.2 +- Added support for code signing in Windows + +### Bugfixes + +- [#7312](https://github.com/influxdata/telegraf/pull/7312) `inputs.docker` CPU stats respect perdevice +- [#8397](https://github.com/influxdata/telegraf/pull/8397) `outputs.dynatrace` Dynatrace Plugin: Make conversion to counters possible / Changed large bulk handling +- [#8655](https://github.com/influxdata/telegraf/pull/8655) `inputs.sqlserver` SqlServer - fix for default server list +- [#8703](https://github.com/influxdata/telegraf/pull/8703) `inputs.docker` Use consistent container name in docker input plugin +- [#8902](https://github.com/influxdata/telegraf/pull/8902) `inputs.snmp` Fix max_repetitions signedness issues +- [#8817](https://github.com/influxdata/telegraf/pull/8817) `outputs.kinesis` outputs.kinesis - log record error count +- [#8833](https://github.com/influxdata/telegraf/pull/8833) `inputs.sqlserver` Bug Fix - SQL Server HADR queries for SQL Versions +- [#8628](https://github.com/influxdata/telegraf/pull/8628) `inputs.modbus` fix: reading multiple holding registers in modbus input plugin +- [#8885](https://github.com/influxdata/telegraf/pull/8885) `inputs.statsd` Fix statsd concurrency bug +- [#8393](https://github.com/influxdata/telegraf/pull/8393) `inputs.sqlserver` SQL Perfmon counters - synced queries from v2 to all db types +- [#8873](https://github.com/influxdata/telegraf/pull/8873) `processors.ifname` Fix mutex locking around ifname cache +- [#8720](https://github.com/influxdata/telegraf/pull/8720) `parsers.influx` fix: remove ambiguity on '\v' from line-protocol parser +- [#8678](https://github.com/influxdata/telegraf/pull/8678) `inputs.redis` Fix Redis output field type inconsistencies +- [#8953](https://github.com/influxdata/telegraf/pull/8953) `agent` Reset the flush interval timer when flush is requested or batch is ready. +- [#8954](https://github.com/influxdata/telegraf/pull/8954) `common.kafka` Fix max open requests to one if idempotent writes is set to true +- [#8721](https://github.com/influxdata/telegraf/pull/8721) `inputs.kube_inventory` Set $HOSTIP in default URL +- [#8995](https://github.com/influxdata/telegraf/pull/8995) `inputs.sflow` fix segfaults in sflow plugin by checking if protocol headers are set +- [#8986](https://github.com/influxdata/telegraf/pull/8986) `outputs.nats` nats_output: use the configured credentials file + +### Features + +- [#8887](https://github.com/influxdata/telegraf/pull/8887) `inputs.procstat` Add PPID field to procstat input plugin +- [#8852](https://github.com/influxdata/telegraf/pull/8852) `processors.starlark` Add Starlark script for estimating Line Protocol cardinality +- [#8915](https://github.com/influxdata/telegraf/pull/8915) `inputs.cloudwatch` add proxy +- [#8910](https://github.com/influxdata/telegraf/pull/8910) `agent` Display error message on badly formatted config string array (eg. namepass) +- [#8785](https://github.com/influxdata/telegraf/pull/8785) `inputs.diskio` Non systemd support with unittest +- [#8850](https://github.com/influxdata/telegraf/pull/8850) `inputs.snmp` Support more snmpv3 authentication protocols +- [#8813](https://github.com/influxdata/telegraf/pull/8813) `inputs.redfish` added member_id as tag(as it is a unique value) for redfish plugin and added address of the server when the status is other than 200 for better debugging +- [#8613](https://github.com/influxdata/telegraf/pull/8613) `inputs.phpfpm` Support exclamation mark to create non-matching list in tail plugin +- [#8179](https://github.com/influxdata/telegraf/pull/8179) `inputs.statsd` Add support for datadog distributions metric +- [#8803](https://github.com/influxdata/telegraf/pull/8803) `agent` Add default retry for load config via url +- [#8816](https://github.com/influxdata/telegraf/pull/8816) Code Signing for Windows +- [#8772](https://github.com/influxdata/telegraf/pull/8772) `processors.starlark` Allow to provide constants to a starlark script +- [#8749](https://github.com/influxdata/telegraf/pull/8749) `outputs.newrelic` Add HTTP proxy setting to New Relic output plugin +- [#8543](https://github.com/influxdata/telegraf/pull/8543) `inputs.elasticsearch` Add configurable number of 'most recent' date-stamped indices to gather in Elasticsearch input +- [#8675](https://github.com/influxdata/telegraf/pull/8675) `processors.starlark` Add Starlark parsing example of nested JSON +- [#8762](https://github.com/influxdata/telegraf/pull/8762) `inputs.prometheus` Optimize for bigger kubernetes clusters (500+ pods) +- [#8950](https://github.com/influxdata/telegraf/pull/8950) `inputs.teamspeak` Teamspeak input plugin query clients +- [#8849](https://github.com/influxdata/telegraf/pull/8849) `inputs.sqlserver` Filter data out from system databases for Azure SQL DB only + +### New Inputs + +- [Beat Input Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/beat) - Contributed by @nferch +- [CS:GO Input Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/csgo) - Contributed by @oofdog +- [Directory Monitoring Input Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/directory_monitor) - Contributed by @InfluxData +- [RavenDB Input Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/ravendb) - Contributed by @ml054 and @bartoncasey +- [NFS Input Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nfsclient) - Contributed by @pmoranga + +### New Outputs + +- [Grafana Loki Output Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/outputs/loki) - Contributed by @Eraac +- [Google BigQuery Output Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/outputs/loki) - Contributed by @gkatzioura +- [Sensu Output Plugin](https://github.com/influxdata/telegraf/blob/master/plugins/outputs/sensu) - Contributed by @calebhailey +- [SignalFX Output Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/outputs/signalfx) - Contributed by @keitwb + +### New Aggregators + +- [Derivative Aggregator Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/aggregators/derivative) - Contributed by @KarstenSchnitter +- [Quantile Aggregator Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/aggregators/quantile) - Contributed by @srebhan + +### New Processors + +- [AWS EC2 Metadata Processor Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/processors/aws/ec2) - Contributed by @pmalek-sumo + +### New Parsers + +- [XML Parser Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/parsers/xml) - Contributed by @srebhan + +### New Serializers + +- [MessagePack Serializer Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/serializers/msgpack) - Contributed by @dialogbox + +### New External Plugins + +- [GeoIP Processor Plugin](https://github.com/a-bali/telegraf-geoip) - Contributed by @a-bali +- [Plex Webhook Input Plugin](https://github.com/russorat/telegraf-webhooks-plex) - Contributed by @russorat +- [SMCIPMITool Input Plugin](https://github.com/jhpope/smc_ipmi) - Contributed by @jhpope + +## v1.17.3 [2021-02-17] + +### Bugfixes + +- [#7316](https://github.com/influxdata/telegraf/pull/7316) `inputs.filestat` plugins/filestat: Skip missing files +- [#8868](https://github.com/influxdata/telegraf/pull/8868) Update to Go 1.15.8 +- [#8744](https://github.com/influxdata/telegraf/pull/8744) Bump github.com/gopcua/opcua from 0.1.12 to 0.1.13 +- [#8657](https://github.com/influxdata/telegraf/pull/8657) `outputs.warp10` outputs/warp10: url encode comma in tags value +- [#8824](https://github.com/influxdata/telegraf/pull/8824) `inputs.x509_cert` inputs.x509_cert: Fix timeout issue +- [#8821](https://github.com/influxdata/telegraf/pull/8821) `inputs.mqtt_consumer` Fix reconnection issues mqtt +- [#8775](https://github.com/influxdata/telegraf/pull/8775) `outputs.influxdb` Validate the response from InfluxDB after writing/creating a database to avoid json parsing panics/errors +- [#8804](https://github.com/influxdata/telegraf/pull/8804) `inputs.snmp` Expose v4/v6-only connection-schemes through GosnmpWrapper +- [#8838](https://github.com/influxdata/telegraf/pull/8838) `agent` fix issue with reading flush_jitter output from config +- [#8839](https://github.com/influxdata/telegraf/pull/8839) `inputs.ping` fixes Sort and timeout around deadline +- [#8787](https://github.com/influxdata/telegraf/pull/8787) `inputs.ping` Update README for inputs.ping with correct cmd for native ping on Linux +- [#8771](https://github.com/influxdata/telegraf/pull/8771) Update go-ping to latest version + +## v1.17.2 [2021-01-28] + +### Bugfixes + +- [#8770](https://github.com/influxdata/telegraf/pull/8770) `inputs.ping` Set interface for native +- [#8764](https://github.com/influxdata/telegraf/pull/8764) `inputs.ping` Resolve regression, re-add missing function + +## v1.17.1 [2021-01-27] + +### Release Notes + +Included a few more changes that add configuration options to plugins as it's been while since the last release + +- [#8335](https://github.com/influxdata/telegraf/pull/8335) `inputs.ipmi_sensor` Add setting to enable caching in ipmitool +- [#8616](https://github.com/influxdata/telegraf/pull/8616) Add Event Log support for Windows +- [#8602](https://github.com/influxdata/telegraf/pull/8602) `inputs.postgresql_extensible` Add timestamp column support to postgresql_extensible +- [#8627](https://github.com/influxdata/telegraf/pull/8627) `parsers.csv` Added ability to define skip values in csv parser +- [#8055](https://github.com/influxdata/telegraf/pull/8055) `outputs.http` outputs/http: add option to control idle connection timeout +- [#7897](https://github.com/influxdata/telegraf/pull/7897) `common.tls` common/tls: Allow specifying SNI hostnames +- [#8541](https://github.com/influxdata/telegraf/pull/8541) `inputs.snmp` Extended the internal snmp wrapper to support AES192, AES192C, AES256, and AES256C +- [#6165](https://github.com/influxdata/telegraf/pull/6165) `inputs.procstat` Provide method to include core count when reporting cpu_usage in procstat input +- [#8287](https://github.com/influxdata/telegraf/pull/8287) `inputs.jenkins` Add support for an inclusive job list in Jenkins plugin +- [#8524](https://github.com/influxdata/telegraf/pull/8524) `inputs.ipmi_sensor` Add hex_key parameter for IPMI input plugin connection + +### Bugfixes + +- [#8662](https://github.com/influxdata/telegraf/pull/8662) `outputs.influxdb_v2` [outputs.influxdb_v2] add exponential backoff, and respect client error responses +- [#8748](https://github.com/influxdata/telegraf/pull/8748) `outputs.elasticsearch` Fix issue with elasticsearch output being really noisy about some errors +- [#7533](https://github.com/influxdata/telegraf/pull/7533) `inputs.zookeeper` improve mntr regex to match user specific keys. +- [#7967](https://github.com/influxdata/telegraf/pull/7967) `inputs.lustre2` Fix crash in lustre2 input plugin, when field name and value +- [#8673](https://github.com/influxdata/telegraf/pull/8673) Update grok-library to v1.0.1 with dots and dash-patterns fixed. +- [#8679](https://github.com/influxdata/telegraf/pull/8679) `inputs.ping` Use go-ping for "native" execution in Ping plugin +- [#8741](https://github.com/influxdata/telegraf/pull/8741) `inputs.x509_cert` fix x509 cert timeout issue +- [#8714](https://github.com/influxdata/telegraf/pull/8714) Bump github.com/nsqio/go-nsq from 1.0.7 to 1.0.8 +- [#8715](https://github.com/influxdata/telegraf/pull/8715) Bump github.com/Shopify/sarama from 1.27.1 to 1.27.2 +- [#8712](https://github.com/influxdata/telegraf/pull/8712) Bump github.com/newrelic/newrelic-telemetry-sdk-go from 0.2.0 to 0.5.1 +- [#8659](https://github.com/influxdata/telegraf/pull/8659) `inputs.gnmi` GNMI plugin should not take off the first character of field keys when no 'alias path' exists. +- [#8609](https://github.com/influxdata/telegraf/pull/8609) `inputs.webhooks` Use the 'measurement' json field from the particle webhook as the measurement name, or if it's blank, use the 'name' field of the event's json. +- [#8658](https://github.com/influxdata/telegraf/pull/8658) `inputs.procstat` Procstat input plugin should use the same timestamp in all metrics in the same Gather() cycle. +- [#8391](https://github.com/influxdata/telegraf/pull/8391) `aggregators.merge` Optimize SeriesGrouper & aggregators.merge +- [#8545](https://github.com/influxdata/telegraf/pull/8545) `inputs.prometheus` Using mime-type in prometheus parser to handle protocol-buffer responses +- [#8588](https://github.com/influxdata/telegraf/pull/8588) `inputs.snmp` Input SNMP plugin - upgrade gosnmp library to version 1.29.0 +- [#8502](https://github.com/influxdata/telegraf/pull/8502) `inputs.http_listener_v2` Fix Stop() bug when plugin fails to start + +### New External Plugins + +- [#8646](https://github.com/influxdata/telegraf/pull/8646) [Open Hardware Monitoring](https://github.com/marianob85/open_hardware_monitor-telegraf-plugin) Input Plugin + +## v1.17.0 [2020-12-18] + +### Release Notes + +- Starlark plugins can now store state between runs using a global state variable. This lets you make custom aggregators as well as custom processors that are state-aware. +- New input plugins: Riemann-Protobuff Listener, Intel PowerStat +- New output plugins: Yandex.Cloud monitoring, Logz.io +- New parser plugin: Prometheus +- New serializer: Prometheus remote write + +### Bugfixes + +- [#8505](https://github.com/influxdata/telegraf/pull/8505) `inputs.vsphere` Fixed misspelled check for datacenter +- [#8499](https://github.com/influxdata/telegraf/pull/8499) `processors.execd` Adding support for new lines in influx line protocol fields. +- [#8254](https://github.com/influxdata/telegraf/pull/8254) `serializers.carbon2` Fix carbon2 tests +- [#8498](https://github.com/influxdata/telegraf/pull/8498) `inputs.http_response` fixed network test +- [#8414](https://github.com/influxdata/telegraf/pull/8414) `inputs.bcache` Fix tests for Windows - part 1 +- [#8577](https://github.com/influxdata/telegraf/pull/8577) `inputs.ping` fix potential issue with race condition +- [#8562](https://github.com/influxdata/telegraf/pull/8562) `inputs.mqtt_consumer` fix issue with mqtt concurrent map write +- [#8574](https://github.com/influxdata/telegraf/pull/8574) `inputs.ecs` Remove duplicated field "revision" from ecs_task because it's already defined as a tag there +- [#8551](https://github.com/influxdata/telegraf/pull/8551) `inputs.socket_listener` fix crash when socket_listener receiving invalid data +- [#8564](https://github.com/influxdata/telegraf/pull/8564) `parsers.graphite` Graphite tags parser +- [#8472](https://github.com/influxdata/telegraf/pull/8472) `inputs.kube_inventory` Fixing issue with missing metrics when pod has only pending containers +- [#8542](https://github.com/influxdata/telegraf/pull/8542) `inputs.aerospike` fix edge case in aerospike plugin where an expected hex string was converted to integer if all digits +- [#8512](https://github.com/influxdata/telegraf/pull/8512) `inputs.kube_inventory` Update string parsing of allocatable cpu cores in kube_inventory + +### Features + +- [#8038](https://github.com/influxdata/telegraf/pull/8038) `inputs.jenkins` feat: add build number field to jenkins_job measurement +- [#7345](https://github.com/influxdata/telegraf/pull/7345) `inputs.ping` Add percentiles to the ping plugin +- [#8369](https://github.com/influxdata/telegraf/pull/8369) `inputs.sqlserver` Added tags for monitoring readable secondaries for Azure SQL MI +- [#8379](https://github.com/influxdata/telegraf/pull/8379) `inputs.sqlserver` SQL Server HA/DR Availability Group queries +- [#8520](https://github.com/influxdata/telegraf/pull/8520) Add initialization example to mock-plugin. +- [#8426](https://github.com/influxdata/telegraf/pull/8426) `inputs.snmp` Add support to convert snmp hex strings to integers +- [#8509](https://github.com/influxdata/telegraf/pull/8509) `inputs.statsd` Add configurable Max TTL duration for statsd input plugin entries +- [#8508](https://github.com/influxdata/telegraf/pull/8508) `inputs.bind` Add configurable timeout to bind input plugin http call +- [#8368](https://github.com/influxdata/telegraf/pull/8368) `inputs.sqlserver` Added is_primary_replica for monitoring readable secondaries for Azure SQL DB +- [#8462](https://github.com/influxdata/telegraf/pull/8462) `inputs.sqlserver` sqlAzureMIRequests - remove duplicate column [session_db_name] +- [#8464](https://github.com/influxdata/telegraf/pull/8464) `inputs.sqlserver` Add column measurement_db_type to output of all queries if not empty +- [#8389](https://github.com/influxdata/telegraf/pull/8389) `inputs.opcua` Add node groups to opcua input plugin +- [#8432](https://github.com/influxdata/telegraf/pull/8432) add support for linux/ppc64le +- [#8474](https://github.com/influxdata/telegraf/pull/8474) `inputs.modbus` Add FLOAT64-IEEE support to inputs.modbus (#8361) (by @Nemecsek) +- [#8447](https://github.com/influxdata/telegraf/pull/8447) `processors.starlark` Add the shared state to the global scope to get previous data +- [#8383](https://github.com/influxdata/telegraf/pull/8383) `inputs.zfs` Add dataset metrics to zfs input +- [#8429](https://github.com/influxdata/telegraf/pull/8429) `outputs.nats` Added "name" parameter to NATS output plugin +- [#8477](https://github.com/influxdata/telegraf/pull/8477) `inputs.http` proxy support for http input +- [#8466](https://github.com/influxdata/telegraf/pull/8466) `inputs.snmp` Translate snmp field values +- [#8435](https://github.com/influxdata/telegraf/pull/8435) `common.kafka` Enable kafka zstd compression and idempotent writes +- [#8056](https://github.com/influxdata/telegraf/pull/8056) `inputs.monit` Add response_time to monit plugin +- [#8446](https://github.com/influxdata/telegraf/pull/8446) update to go 1.15.5 +- [#8428](https://github.com/influxdata/telegraf/pull/8428) `aggregators.basicstats` Add rate and interval to the basicstats aggregator plugin +- [#8575](https://github.com/influxdata/telegraf/pull/8575) `inputs.win_services` Added Glob pattern matching for "Windows Services" plugin +- [#6132](https://github.com/influxdata/telegraf/pull/6132) `inputs.mysql` Add per user metrics to mysql input +- [#8500](https://github.com/influxdata/telegraf/pull/8500) `inputs.github` [inputs.github] Add query of pull-request statistics +- [#8598](https://github.com/influxdata/telegraf/pull/8598) `processors.enum` Allow globs (wildcards) in config for tags/fields in enum processor +- [#8590](https://github.com/influxdata/telegraf/pull/8590) `inputs.ethtool` [ethtool] interface_up field added +- [#8579](https://github.com/influxdata/telegraf/pull/8579) `parsers.json` Add wildcard tags json parser support + +### New Parser Plugins + +- [#7778](https://github.com/influxdata/telegraf/pull/7778) `parsers.prometheus` Add a parser plugin for prometheus + +### New Serializer Plugins + +- [#8360](https://github.com/influxdata/telegraf/pull/8360) `serializers.prometheusremotewrite` Add prometheus remote write serializer + +### New Input Plugins + +- [#8163](https://github.com/influxdata/telegraf/pull/8163) `inputs.riemann` Support Riemann-Protobuff Listener +- [#8488](https://github.com/influxdata/telegraf/pull/8488) `inputs.intel_powerstat` New Intel PowerStat input plugin + +### New Output Plugins + +- [#8296](https://github.com/influxdata/telegraf/pull/8296) `outputs.yandex_cloud_monitoring` #8295 Initial Yandex.Cloud monitoring +- [#8202](https://github.com/influxdata/telegraf/pull/8202) `outputs.logzio` A new Logz.io output plugin + +## v1.16.3 [2020-12-01] + +### Bugfixes + +- [#8483](https://github.com/influxdata/telegraf/pull/8483) `inputs.gnmi` Log SubscribeResponse_Error message and code. #8482 +- [#7987](https://github.com/influxdata/telegraf/pull/7987) update godirwalk to v1.16.1 +- [#8438](https://github.com/influxdata/telegraf/pull/8438) `processors.starlark` Starlark example dropbytype +- [#8468](https://github.com/influxdata/telegraf/pull/8468) `inputs.sqlserver` Fix typo in column name +- [#8461](https://github.com/influxdata/telegraf/pull/8461) `inputs.phpfpm` [php-fpm] Fix possible "index out of range" +- [#8444](https://github.com/influxdata/telegraf/pull/8444) `inputs.apcupsd` Update mdlayher/apcupsd dependency +- [#8439](https://github.com/influxdata/telegraf/pull/8439) `processors.starlark` Show how to return a custom error with the Starlark processor +- [#8440](https://github.com/influxdata/telegraf/pull/8440) `parsers.csv` keep field name as is for csv timestamp column +- [#8436](https://github.com/influxdata/telegraf/pull/8436) `inputs.nvidia_smi` Add DriverVersion and CUDA Version to output +- [#8423](https://github.com/influxdata/telegraf/pull/8423) `processors.starlark` Show how to return several metrics with the Starlark processor +- [#8408](https://github.com/influxdata/telegraf/pull/8408) `processors.starlark` Support logging in starlark +- [#8315](https://github.com/influxdata/telegraf/pull/8315) add kinesis output to external plugins list +- [#8406](https://github.com/influxdata/telegraf/pull/8406) `outputs.wavefront` #8405 add non-retryable debug logging +- [#8404](https://github.com/influxdata/telegraf/pull/8404) `outputs.wavefront` Wavefront output should distinguish between retryable and non-retryable errors +- [#8401](https://github.com/influxdata/telegraf/pull/8401) `processors.starlark` Allow to catch errors that occur in the apply function + +## v1.16.2 [2020-11-13] + +### Bugfixes + +- [#8400](https://github.com/influxdata/telegraf/pull/8400) `parsers.csv` Fix parsing of multiple files with different headers (#6318). +- [#8326](https://github.com/influxdata/telegraf/pull/8326) `inputs.proxmox` proxmox: ignore QEMU templates and iron out a few bugs +- [#7991](https://github.com/influxdata/telegraf/pull/7991) `inputs.systemd_units` systemd_units: add --plain to command invocation (#7990) +- [#8307](https://github.com/influxdata/telegraf/pull/8307) fix links in external plugins readme +- [#8370](https://github.com/influxdata/telegraf/pull/8370) `inputs.redis` Fix minor typos in readmes +- [#8374](https://github.com/influxdata/telegraf/pull/8374) `inputs.smart` Fix SMART plugin to recognize all devices from config +- [#8288](https://github.com/influxdata/telegraf/pull/8288) `inputs.redfish` Add OData-Version header to requests +- [#8357](https://github.com/influxdata/telegraf/pull/8357) `inputs.vsphere` Prydin issue 8169 +- [#8356](https://github.com/influxdata/telegraf/pull/8356) `inputs.sqlserver` On-prem fix for #8324 +- [#8165](https://github.com/influxdata/telegraf/pull/8165) `outputs.wavefront` [output.wavefront] Introduced "immediate_flush" flag +- [#7938](https://github.com/influxdata/telegraf/pull/7938) `inputs.gnmi` added support for bytes encoding +- [#8337](https://github.com/influxdata/telegraf/pull/8337) `inputs.dcos` Update jwt-go module to address CVE-2020-26160 +- [#8350](https://github.com/influxdata/telegraf/pull/8350) `inputs.ras` fix plugins/input/ras test +- [#8329](https://github.com/influxdata/telegraf/pull/8329) `outputs.dynatrace` #8328 Fixed a bug with the state map in Dynatrace Plugin + +## v1.16.1 [2020-10-28] + +### Release Notes + +- [#8318](https://github.com/influxdata/telegraf/pull/8318) `common.kafka` kafka sasl-mechanism auth support for SCRAM-SHA-256, SCRAM-SHA-512, GSSAPI + +### Bugfixes + +- [#8331](https://github.com/influxdata/telegraf/pull/8331) `inputs.sqlserver` SQL Server Azure PerfCounters Fix +- [#8325](https://github.com/influxdata/telegraf/pull/8325) `inputs.sqlserver` SQL Server - PerformanceCounters - removed synthetic counters +- [#8324](https://github.com/influxdata/telegraf/pull/8324) `inputs.sqlserver` SQL Server - server_properties added sql_version_desc +- [#8317](https://github.com/influxdata/telegraf/pull/8317) `inputs.ras` Disable RAS input plugin on specific Linux architectures: mips64, mips64le, ppc64le, riscv64 +- [#8309](https://github.com/influxdata/telegraf/pull/8309) `inputs.processes` processes: fix issue with stat no such file/dir +- [#8308](https://github.com/influxdata/telegraf/pull/8308) `inputs.win_perf_counters` fix issue with PDH_CALC_NEGATIVE_DENOMINATOR error +- [#8306](https://github.com/influxdata/telegraf/pull/8306) `inputs.ras` RAS plugin - fix for too many open files handlers + +## v1.16.0 [2020-10-21] + +### Release Notes + +- New [code examples](/plugins/processors/starlark/testdata) for the [Starlark processor](/plugins/processors/starlark/README.md) +- [#7920](https://github.com/influxdata/telegraf/pull/7920) `inputs.rabbitmq` remove deprecated healthcheck +- [#7953](https://github.com/influxdata/telegraf/pull/7953) Add details to connect to InfluxDB OSS 2 and Cloud 2 +- [#8054](https://github.com/influxdata/telegraf/pull/8054) add guidelines run to external plugins with execd +- [#8198](https://github.com/influxdata/telegraf/pull/8198) `inputs.influxdb_v2_listener` change default influxdb port from 9999 to 8086 to match OSS 2.0 release +- [starlark](https://github.com/influxdata/telegraf/tree/release-1.16/plugins/processors/starlark/testdata) `processors.starlark` add various code examples for the Starlark processor + +### Features + +- [#7814](https://github.com/influxdata/telegraf/pull/7814) `agent` Send metrics in FIFO order +- [#7869](https://github.com/influxdata/telegraf/pull/7869) `inputs.modbus` extend support of fixed point values on input +- [#7870](https://github.com/influxdata/telegraf/pull/7870) `inputs.mongodb` Added new metric "pages written from cache" +- [#7875](https://github.com/influxdata/telegraf/pull/7875) `inputs.consul` input consul - added metric_version flag +- [#7894](https://github.com/influxdata/telegraf/pull/7894) `inputs.cloudwatch` Implement AWS CloudWatch Input Plugin ListMetrics API calls to use Active Metric Filter +- [#7904](https://github.com/influxdata/telegraf/pull/7904) `inputs.clickhouse` add additional metrics to clickhouse input plugin +- [#7934](https://github.com/influxdata/telegraf/pull/7934) `inputs.sqlserver` Database_type config to Split up sql queries by engine type +- [#8018](https://github.com/influxdata/telegraf/pull/8018) `processors.ifname` Add addTag debugging in ifname plugin +- [#8019](https://github.com/influxdata/telegraf/pull/8019) `outputs.elasticsearch` added force_document_id option to ES output enable resend data and avoiding duplicated ES documents +- [#8025](https://github.com/influxdata/telegraf/pull/8025) `inputs.aerospike` Add set, and histogram reporting to aerospike telegraf plugin +- [#8082](https://github.com/influxdata/telegraf/pull/8082) `inputs.snmp` Add agent host tag configuration option +- [#8113](https://github.com/influxdata/telegraf/pull/8113) `inputs.smart` Add more missing NVMe attributes to smart plugin +- [#8120](https://github.com/influxdata/telegraf/pull/8120) `inputs.sqlserver` Added more performance counters to SqlServer input plugin +- [#8127](https://github.com/influxdata/telegraf/pull/8127) `agent` Sort plugin name lists for output +- [#8132](https://github.com/influxdata/telegraf/pull/8132) `outputs.sumologic` Sumo Logic output plugin: carbon2 default to include field in metric +- [#8133](https://github.com/influxdata/telegraf/pull/8133) `inputs.influxdb_v2_listener` influxdb_v2_listener - add /ready route +- [#8168](https://github.com/influxdata/telegraf/pull/8168) `processors.starlark` add json parsing support to starlark +- [#8186](https://github.com/influxdata/telegraf/pull/8186) `inputs.sqlserver` New sql server queries (Azure) +- [#8189](https://github.com/influxdata/telegraf/pull/8189) `inputs.snmp_trap` If the community string is available, add it as a tag +- [#8190](https://github.com/influxdata/telegraf/pull/8190) `inputs.tail` Semigroupoid multiline (#8167) +- [#8196](https://github.com/influxdata/telegraf/pull/8196) `inputs.redis` add functionality to get values from redis commands +- [#8220](https://github.com/influxdata/telegraf/pull/8220) `build` update to Go 1.15 +- [#8032](https://github.com/influxdata/telegraf/pull/8032) `inputs.http_response` http_response: match on status code +- [#8172](https://github.com/influxdata/telegraf/pull/8172) `inputs.sqlserver` New sql server queries (on-prem) - refactoring and formatting + +### Bugfixes + +- [#7816](https://github.com/influxdata/telegraf/pull/7816) `shim` fix bug with loading plugins in shim with no config +- [#7818](https://github.com/influxdata/telegraf/pull/7818) `build` Fix darwin package build flags +- [#7819](https://github.com/influxdata/telegraf/pull/7819) `inputs.tail` Close file to ensure it has been flushed +- [#7853](https://github.com/influxdata/telegraf/pull/7853) Initialize aggregation processors +- [#7865](https://github.com/influxdata/telegraf/pull/7865) `common.shim` shim logger improvements +- [#7867](https://github.com/influxdata/telegraf/pull/7867) `inputs.execd` fix issue with execd restart_delay being ignored +- [#7872](https://github.com/influxdata/telegraf/pull/7872) `inputs.gnmi` Recv next message after send returns EOF +- [#7877](https://github.com/influxdata/telegraf/pull/7877) Fix arch name in deb/rpm builds +- [#7909](https://github.com/influxdata/telegraf/pull/7909) fixes issue with rpm /var/log/telegraf permissions +- [#7918](https://github.com/influxdata/telegraf/pull/7918) `inputs.net` fix broken link to proc.c +- [#7927](https://github.com/influxdata/telegraf/pull/7927) `inputs.tail` Fix tail following on EOF +- [#8005](https://github.com/influxdata/telegraf/pull/8005) Fix docker-image make target +- [#8039](https://github.com/influxdata/telegraf/pull/8039) `serializers.splunkmetric` Remove Event field as it is causing issues with pre-trained source types +- [#8048](https://github.com/influxdata/telegraf/pull/8048) `inputs.jenkins` Multiple escaping occurs on Jenkins URLs at certain folder depth +- [#8071](https://github.com/influxdata/telegraf/pull/8071) `inputs.kubernetes` add missing error check for HTTP req failure +- [#8145](https://github.com/influxdata/telegraf/pull/8145) `processors.execd` Increased the maximum serialized metric size in line protocol +- [#8159](https://github.com/influxdata/telegraf/pull/8159) `outputs.dynatrace` Dynatrace Output: change handling of monotonic counters +- [#8176](https://github.com/influxdata/telegraf/pull/8176) fix panic on streaming processers using logging +- [#8177](https://github.com/influxdata/telegraf/pull/8177) `parsers.influx` fix: plugins/parsers/influx: avoid ParseError.Error panic +- [#8199](https://github.com/influxdata/telegraf/pull/8199) `inputs.docker` Fix vulnerabilities found in BDBA scan +- [#8200](https://github.com/influxdata/telegraf/pull/8200) `inputs.sqlserver` Fixed Query mapping +- [#8201](https://github.com/influxdata/telegraf/pull/8201) `outputs.sumologic` Fix carbon2 serializer not falling through to field separate when carbon2_format field is unset +- [#8210](https://github.com/influxdata/telegraf/pull/8210) update gopsutil: fix procstat performance regression +- [#8162](https://github.com/influxdata/telegraf/pull/8162) Fix bool serialization when using carbon2 +- [#8240](https://github.com/influxdata/telegraf/pull/8240) Fix bugs found by LGTM analysis platform +- [#8251](https://github.com/influxdata/telegraf/pull/8251) `outputs.dynatrace` Dynatrace Output Plugin: Fixed behaviour when state map is cleared +- [#8274](https://github.com/influxdata/telegraf/pull/8274) `common.shim` fix issue with loading processor config from execd + +### New Input Plugins + +- [influxdb_v2_listener](/plugins/inputs/influxdb_v2_listener/README.md) Influxdb v2 listener - Contributed by @magichair +- [intel_rdt](/plugins/inputs/intel_rdt/README.md) New input plugin for Intel RDT (Intel Resource Director Technology) - Contributed by @p-zak +- [nsd](/plugins/inputs/nsd/README.md) add nsd input plugin - Contributed by @gearnode +- [opcua](/plugins/inputs/opcua/README.md) Add OPC UA input plugin - Contributed by InfluxData +- [proxmox](/plugins/inputs/proxmox/README.md) Proxmox plugin - Contributed by @effitient +- [ras](/plugins/inputs/ras/README.md) New input plugin for RAS (Reliability, Availability and Serviceability) - Contributed by @p-zak +- [win_eventlog](/plugins/inputs/win_eventlog/README.md) Windows eventlog input plugin - Contributed by @simnv + +### New Output Plugins + +- [dynatrace](/plugins/outputs/dynatrace/README.md) Dynatrace output plugin - Contributed by @thschue +- [sumologic](/plugins/outputs/sumologic/README.md) Sumo Logic output plugin - Contributed by @pmalek-sumo +- [timestream](/plugins/outputs/timestream) Timestream Output Plugin - Contributed by @piotrwest + +### New External Plugins + +See [EXTERNAL_PLUGINS.md](/EXTERNAL_PLUGINS.md) for a full list of external plugins + +- [awsalarms](https://github.com/vipinvkmenon/awsalarms) - Simple plugin to gather/monitor alarms generated in AWS. +- [youtube-telegraf-plugin](https://github.com/inabagumi/youtube-telegraf-plugin) - Gather view and subscriber stats from your youtube videos +- [octoprint](https://github.com/BattleBas/octoprint-telegraf-plugin) - Gather 3d print information from the octoprint API. +- [systemd-timings](https://github.com/pdmorrow/telegraf-execd-systemd-timings) - Gather systemd boot and unit timestamp metrics. + +## v1.15.4 [2020-10-20] + +### Bugfixes + +- [#8274](https://github.com/influxdata/telegraf/pull/8274) `common.shim` fix issue with loading processor config from execd +- [#8176](https://github.com/influxdata/telegraf/pull/8176) `agent` fix panic on streaming processers using logging + +## v1.15.3 [2020-09-11] + +### Release Notes + +- Many documentation updates +- New [code examples](https://github.com/influxdata/telegraf/tree/master/plugins/processors/starlark/testdata) for the [Starlark processor](https://github.com/influxdata/telegraf/blob/master/plugins/processors/starlark/README.md) + +### Bugfixes + +- [#7999](https://github.com/influxdata/telegraf/pull/7999) `agent` fix minor agent error message race condition +- [#8051](https://github.com/influxdata/telegraf/pull/8051) `build` fix docker build. update dockerfiles to Go 1.14 +- [#8052](https://github.com/influxdata/telegraf/pull/8052) `shim` fix bug in shim logger affecting AddError +- [#7996](https://github.com/influxdata/telegraf/pull/7996) `shim` fix issue with shim use of config.Duration +- [#8006](https://github.com/influxdata/telegraf/pull/8006) `inputs.eventhub_consumer` Fix string to int conversion in eventhub consumer +- [#7986](https://github.com/influxdata/telegraf/pull/7986) `inputs.http_listener_v2` make http header tags case insensitive +- [#7869](https://github.com/influxdata/telegraf/pull/7869) `inputs.modbus` extend support of fixed point values on input +- [#7861](https://github.com/influxdata/telegraf/pull/7861) `inputs.ping` Fix Ping Input plugin for FreeBSD's ping6 +- [#7808](https://github.com/influxdata/telegraf/pull/7808) `inputs.sqlserver` added new counter - Lock Timeouts (timeout > 0)/sec +- [#8026](https://github.com/influxdata/telegraf/pull/8026) `inputs.vsphere` vSphere Fixed missing clustername issue 7878 +- [#8020](https://github.com/influxdata/telegraf/pull/8020) `processors.starlark` improve the quality of starlark docs by executing them as tests +- [#7976](https://github.com/influxdata/telegraf/pull/7976) `processors.starlark` add pivot example for starlark processor +- [#7134](https://github.com/influxdata/telegraf/pull/7134) `outputs.application_insights` Added the ability to set the endpoint url +- [#7908](https://github.com/influxdata/telegraf/pull/7908) `outputs.opentsdb` fix JSON handling of values NaN and Inf + +## v1.15.2 [2020-07-31] + +### Bug Fixes + +- [#7905](https://github.com/influxdata/telegraf/issues/7905): Fix RPM /var/log/telegraf permissions +- [#7880](https://github.com/influxdata/telegraf/issues/7880): Fix tail following on EOF + +## v1.15.1 [2020-07-22] + +### Bug Fixes + +- [#7877](https://github.com/influxdata/telegraf/pull/7877): Fix architecture in non-amd64 deb and rpm packages. + +## v1.15.0 [2020-07-22] + +### Release Notes + +- The `logparser` input is deprecated, use the `tail` input with `data_format = + "grok"` as a replacement. + +- The `cisco_telemetry_gnmi` input has been renamed to `gnmi` to better reflect + its general support for gNMI devices. + +- Several fields used primarily for debugging have been removed from the + `splunkmetric` serializer, if you are making use of these fields they can be + added back with the `tag` option. + +- Telegraf's `--test` mode now runs processors and aggregators before printing + metrics. + +- Official packages now built with Go 1.14.5. + +- When updating the Debian package you will no longer be prompted to merge the + telegraf.conf file, instead the new version will be installed to + `/etc/telegraf/telegraf.conf.sample`. The tar and zip packages now include + the version in the top level directory. + +### New Inputs + +- [nginx_sts](/plugins/inputs/nginx_sts/README.md) - Contributed by @zdmytriv +- [redfish](/plugins/inputs/redfish/README.md) - Contributed by @sarvanikonda + +### New Processors + +- [defaults](/plugins/processors/defaults/README.md) - Contributed by @jregistr +- [execd](/plugins/processors/execd/README.md) - Contributed by @influxdata +- [filepath](/plugins/processors/filepath/README.md) - Contributed by @kir4h +- [ifname](/plugins/processors/ifname/README.md) - Contributed by @influxdata +- [port_name](/plugins/processors/port_name/README.md) - Contributed by @influxdata +- [reverse_dns](/plugins/processors/reverse_dns/README.md) - Contributed by @influxdata +- [starlark](/plugins/processors/starlark/README.md) - Contributed by @influxdata + +### New Outputs + +- [newrelic](/plugins/outputs/newrelic/README.md) - Contributed by @hsinghkalsi +- [execd](/plugins/outputs/execd/README.md) - Contributed by @influxdata + +### Features + +- [#7634](https://github.com/influxdata/telegraf/pull/7634): Add support for streaming processors. +- [#6905](https://github.com/influxdata/telegraf/pull/6905): Add commands stats to mongodb input plugin. +- [#7193](https://github.com/influxdata/telegraf/pull/7193): Add additional concurrent transaction information. +- [#7223](https://github.com/influxdata/telegraf/pull/7223): Add ability to specify HTTP Headers in http_listener_v2 which will added as tags. +- [#7140](https://github.com/influxdata/telegraf/pull/7140): Apply ping deadline to dns lookup. +- [#7225](https://github.com/influxdata/telegraf/pull/7225): Add support for 64-bit integer types to modbus input. +- [#7231](https://github.com/influxdata/telegraf/pull/7231): Add possibility to specify measurement per register. +- [#7136](https://github.com/influxdata/telegraf/pull/7136): Support multiple templates for graphite serializers. +- [#7250](https://github.com/influxdata/telegraf/pull/7250): Deploy telegraf configuration as a "non config" file. +- [#7214](https://github.com/influxdata/telegraf/pull/7214): Add VolumeSpace query for sqlserver input with metric_version 2. +- [#7304](https://github.com/influxdata/telegraf/pull/7304): Add reading bearer token from a file to http input. +- [#7366](https://github.com/influxdata/telegraf/pull/7366): add support for SIGUSR1 to trigger flush. +- [#7271](https://github.com/influxdata/telegraf/pull/7271): Add retry when slave is busy to modbus input. +- [#7356](https://github.com/influxdata/telegraf/pull/7356): Add option to save retention policy as tag in influxdb_listener. +- [#6915](https://github.com/influxdata/telegraf/pull/6915): Add support for MDS and RGW sockets to ceph input. +- [#7391](https://github.com/influxdata/telegraf/pull/7391): Extract target as a tag for each rule in iptables input. +- [#7434](https://github.com/influxdata/telegraf/pull/7434): Use docker log timestamp as metric time. +- [#7359](https://github.com/influxdata/telegraf/pull/7359): Add cpu query to sqlserver input. +- [#7464](https://github.com/influxdata/telegraf/pull/7464): Add field creation to date processor and integer unix time support. +- [#7483](https://github.com/influxdata/telegraf/pull/7483): Add integer mapping support to enum processor. +- [#7321](https://github.com/influxdata/telegraf/pull/7321): Add additional fields to mongodb input. +- [#7491](https://github.com/influxdata/telegraf/pull/7491): Add authentication support to the http_response input plugin. +- [#7503](https://github.com/influxdata/telegraf/pull/7503): Add truncate_tags setting to wavefront output. +- [#7545](https://github.com/influxdata/telegraf/pull/7545): Add configurable separator graphite serializer and output. +- [#7489](https://github.com/influxdata/telegraf/pull/7489): Add cluster state integer to mongodb input. +- [#7515](https://github.com/influxdata/telegraf/pull/7515): Add option to disable mongodb cluster status. +- [#7319](https://github.com/influxdata/telegraf/pull/7319): Add support for battery level monitoring to the fibaro input. +- [#7405](https://github.com/influxdata/telegraf/pull/7405): Allow collection of HTTP Headers in http_response input. +- [#7540](https://github.com/influxdata/telegraf/pull/7540): Add processor to look up service name by port. +- [#7474](https://github.com/influxdata/telegraf/pull/7474): Add new once mode that write to outputs and exits. +- [#7474](https://github.com/influxdata/telegraf/pull/7474): Run processors and aggregators during test mode. +- [#7294](https://github.com/influxdata/telegraf/pull/7294): Add SNMPv3 trap support to snmp_trap input. +- [#7646](https://github.com/influxdata/telegraf/pull/7646): Add video codec stats to nvidia-smi. +- [#7651](https://github.com/influxdata/telegraf/pull/7651): Fix source field for icinga2 plugin and add tag for server hostname. +- [#7619](https://github.com/influxdata/telegraf/pull/7619): Add timezone configuration to csv input data format. +- [#7596](https://github.com/influxdata/telegraf/pull/7596): Add ability to collect response body as field with http_response. +- [#7267](https://github.com/influxdata/telegraf/pull/7267): Add ability to add selectors as tags in kube_inventory. +- [#7712](https://github.com/influxdata/telegraf/pull/7712): Add counter type to sqlserver perfmon collector. +- [#7575](https://github.com/influxdata/telegraf/pull/7575): Add missing nvme attributes to smart plugin. +- [#7726](https://github.com/influxdata/telegraf/pull/7726): Add laundry to mem plugin on FreeBSD. +- [#7762](https://github.com/influxdata/telegraf/pull/7762): Allow per input overriding of collection_jitter and precision. +- [#7686](https://github.com/influxdata/telegraf/pull/7686): Improve performance of procstat: Up to 40/120x better performance. +- [#7677](https://github.com/influxdata/telegraf/pull/7677): Expand execd shim support for processor and outputs. +- [#7154](https://github.com/influxdata/telegraf/pull/7154): Add v3 metadata support to ecs input. +- [#7792](https://github.com/influxdata/telegraf/pull/7792): Support utf-16 in file and tail inputs. + +### Bug Fixes + +- [#7371](https://github.com/influxdata/telegraf/issues/7371): Fix unable to write metrics to CloudWatch with IMDSv1 disabled. +- [#7233](https://github.com/influxdata/telegraf/issues/7233): Fix vSphere 6.7 missing data issue. +- [#7448](https://github.com/influxdata/telegraf/issues/7448): Remove debug fields from splunkmetric serializer. +- [#7446](https://github.com/influxdata/telegraf/issues/7446): Fix gzip support in socket_listener with tcp sockets. +- [#7390](https://github.com/influxdata/telegraf/issues/7390): Fix interval drift when round_interval is set in agent. +- [#7524](https://github.com/influxdata/telegraf/pull/7524): Fix typo in total_elapsed_time_ms field of sqlserver input. +- [#7203](https://github.com/influxdata/telegraf/issues/7203): Exclude csv_timestamp_column and csv_measurement_column from fields. +- [#7018](https://github.com/influxdata/telegraf/issues/7018): Fix incorrect uptime when clock is adjusted. +- [#6807](https://github.com/influxdata/telegraf/issues/6807): Fix memory leak when using procstat on Windows. +- [#7495](https://github.com/influxdata/telegraf/issues/7495): Improve sqlserver input compatibility with older server versions. +- [#7558](https://github.com/influxdata/telegraf/issues/7558): Remove trailing backslash from tag keys/values in influx serializer. +- [#7715](https://github.com/influxdata/telegraf/issues/7715): Fix incorrect Azure SQL DB server properties. +- [#7431](https://github.com/influxdata/telegraf/issues/7431): Fix json unmarshal error in the kibana input. +- [#5633](https://github.com/influxdata/telegraf/issues/5633): Send metrics in FIFO order. + +## v1.14.5 [2020-06-30] + +### Bug Fixes + +- [#7686](https://github.com/influxdata/telegraf/pull/7686): Improve the performance of the procstat input. +- [#7658](https://github.com/influxdata/telegraf/pull/7658): Fix ping exit code handling on non-Linux. +- [#7718](https://github.com/influxdata/telegraf/pull/7718): Skip overs errors in the output of the sensors command. +- [#7748](https://github.com/influxdata/telegraf/issues/7748): Prevent startup when tags have incorrect type in configuration file. +- [#7699](https://github.com/influxdata/telegraf/issues/7699): Fix panic with GJSON multiselect query in json parser. +- [#7754](https://github.com/influxdata/telegraf/issues/7754): Allow any key usage type on x509 certificate. +- [#7705](https://github.com/influxdata/telegraf/issues/7705): Allow histograms and summary types without buckets or quantiles in prometheus_client output. + +## v1.14.4 [2020-06-09] + +### Bug Fixes + +- [#7325](https://github.com/influxdata/telegraf/issues/7325): Fix "cannot insert the value NULL error" with PerformanceCounters query. +- [#7579](https://github.com/influxdata/telegraf/pull/7579): Fix numeric to bool conversion in converter processor. +- [#7551](https://github.com/influxdata/telegraf/issues/7551): Fix typo in name of gc_cpu_fraction field of the influxdb input. +- [#7617](https://github.com/influxdata/telegraf/issues/7617): Fix issue with influx stream parser blocking when data is in buffer. + +## v1.14.3 [2020-05-19] + +### Bug Fixes + +- [#7412](https://github.com/influxdata/telegraf/pull/7412): Use same timestamp for all objects in arrays in the json parser. +- [#7343](https://github.com/influxdata/telegraf/issues/7343): Handle multiple metrics with the same timestamp in dedup processor. +- [#5905](https://github.com/influxdata/telegraf/issues/5905): Fix reconnection of timed out HTTP2 connections influxdb outputs. +- [#7468](https://github.com/influxdata/telegraf/issues/7468): Fix negative value parsing in impi_sensor input. + +## v1.14.2 [2020-04-28] + +### Bug Fixes + +- [#7241](https://github.com/influxdata/telegraf/issues/7241): Trim whitespace from instance tag in sqlserver input. +- [#7322](https://github.com/influxdata/telegraf/issues/7322): Use increased AWS Cloudwatch GetMetricData limit of 500 metrics per call. +- [#7318](https://github.com/influxdata/telegraf/issues/7318): Fix dimension limit on azure_monitor output. +- [#7407](https://github.com/influxdata/telegraf/pull/7407): Fix 64-bit integer to string conversion in snmp input. +- [#7327](https://github.com/influxdata/telegraf/issues/7327): Fix shard indices reporting in elasticsearch input. +- [#7388](https://github.com/influxdata/telegraf/issues/7388): Ignore fields with NaN or Inf floats in the JSON serializer. +- [#7402](https://github.com/influxdata/telegraf/issues/7402): Fix typo in name of gc_cpu_fraction field of the kapacitor input. +- [#7235](https://github.com/influxdata/telegraf/issues/7235): Don't retry `create database` when using database_tag if forbidden by the server in influxdb output. +- [#7406](https://github.com/influxdata/telegraf/issues/7406): Allow CR and FF inside of string fields in influx parser. + +## v1.14.1 [2020-04-14] + +### Bug Fixes + +- [#7236](https://github.com/influxdata/telegraf/issues/7236): Fix PerformanceCounter query performance degradation in sqlserver input. +- [#7257](https://github.com/influxdata/telegraf/issues/7257): Fix error when using the Name field in template processor. +- [#7289](https://github.com/influxdata/telegraf/pull/7289): Fix export timestamp not working for prometheus on v2. +- [#7310](https://github.com/influxdata/telegraf/issues/7310): Fix exclude database and retention policy tags is shared. +- [#7262](https://github.com/influxdata/telegraf/issues/7262): Fix status path when using globs in phpfpm. + +## v1.14 [2020-03-26] + +### Release Notes + +- In the `sqlserver` input, the `sqlserver_azurestats` measurement has been + renamed to `sqlserver_azure_db_resource_stats` due to an issue where numeric + metrics were previously being reported incorrectly as strings. + +- The `date` processor now uses the UTC timezone when creating its tag. In + previous versions the local time was used. + +### New Inputs + +- [clickhouse](/plugins/inputs/clickhouse/README.md) - Contributed by @kshvakov +- [execd](/plugins/inputs/execd/README.md) - Contributed by @jgraichen +- [eventhub_consumer](/plugins/inputs/eventhub_consumer/README.md) - Contributed by @R290 +- [infiniband](/plugins/inputs/infiniband/README.md) - Contributed by @willfurnell +- [lanz](/plugins/inputs/lanz/README.md): Contributed by @timhughes +- [modbus](/plugins/inputs/modbus/README.md) - Contributed by @garciaolais +- [monit](/plugins/inputs/monit/README.md) - Contributed by @SirishaGopigiri +- [sflow](/plugins/inputs/sflow/README.md) - Contributed by @influxdata +- [wireguard](/plugins/inputs/wireguard/README.md) - Contributed by @LINKIWI + +### New Processors + +- [dedup](/plugins/processors/dedup/README.md) - Contributed by @igomura +- [template](/plugins/processors/template/README.md) - Contributed by @RobMalvern +- [s2geo](/plugins/processors/s2geo/README.md) - Contributed by @alespour + +### New Outputs + +- [warp10](/plugins/outputs/warp10/README.md) - Contributed by @aurrelhebert + +### Features + +- [#6730](https://github.com/influxdata/telegraf/pull/6730): Add page_faults for mongodb wired tiger. +- [#6798](https://github.com/influxdata/telegraf/pull/6798): Add use_sudo option to ipmi_sensor input. +- [#6764](https://github.com/influxdata/telegraf/pull/6764): Add ability to collect pod labels to kubernetes input. +- [#6770](https://github.com/influxdata/telegraf/pull/6770): Expose unbound-control config file option. +- [#6508](https://github.com/influxdata/telegraf/pull/6508): Add support for new nginx plus api endpoints. +- [#6342](https://github.com/influxdata/telegraf/pull/6342): Add kafka SASL version control to support Azure Event Hub. +- [#6869](https://github.com/influxdata/telegraf/pull/6869): Add RBPEX IO statistics to DatabaseIO query in sqlserver input. +- [#6869](https://github.com/influxdata/telegraf/pull/6869): Add space on disk for each file to DatabaseIO query in the sqlserver input. +- [#6869](https://github.com/influxdata/telegraf/pull/6869): Calculate DB Name instead of GUID in physical_db_name in the sqlserver input. +- [#6733](https://github.com/influxdata/telegraf/pull/6733): Add latency stats to mongo input. +- [#6844](https://github.com/influxdata/telegraf/pull/6844): Add source and port tags to jenkins_job metrics. +- [#6886](https://github.com/influxdata/telegraf/pull/6886): Add date offset and timezone options to date processor. +- [#6859](https://github.com/influxdata/telegraf/pull/6859): Exclude resources by inventory path in vsphere input. +- [#6700](https://github.com/influxdata/telegraf/pull/6700): Allow a user defined field to be used as the graylog short_message. +- [#6917](https://github.com/influxdata/telegraf/pull/6917): Add server_name override for x509_cert plugin. +- [#6921](https://github.com/influxdata/telegraf/pull/6921): Add udp internal metrics for the statsd input. +- [#6914](https://github.com/influxdata/telegraf/pull/6914): Add replica set tag to mongodb input. +- [#6935](https://github.com/influxdata/telegraf/pull/6935): Add counters for merged reads and writes to diskio input. +- [#6982](https://github.com/influxdata/telegraf/pull/6982): Add support for titlecase transformation to strings processor. +- [#6993](https://github.com/influxdata/telegraf/pull/6993): Add support for MDB database information to openldap input. +- [#6957](https://github.com/influxdata/telegraf/pull/6957): Add new fields for Jenkins total and busy executors. +- [#7035](https://github.com/influxdata/telegraf/pull/7035): Fix dash to underscore replacement when handling embedded tags in Cisco MDT. +- [#7039](https://github.com/influxdata/telegraf/pull/7039): Add process created_at time to procstat input. +- [#7022](https://github.com/influxdata/telegraf/pull/7022): Add support for credentials file to nats_consumer and nats output. +- [#7065](https://github.com/influxdata/telegraf/pull/7065): Add additional tags and fields to apcupsd. +- [#7084](https://github.com/influxdata/telegraf/pull/7084): Add RabbitMQ slave_nodes and synchronized_slave_nodes metrics. +- [#7089](https://github.com/influxdata/telegraf/pull/7089): Allow globs in FPM unix socket paths. +- [#7071](https://github.com/influxdata/telegraf/pull/7071): Add non-cumulative histogram to histogram aggregator. +- [#6969](https://github.com/influxdata/telegraf/pull/6969): Add label and field selectors to prometheus input k8s discovery. +- [#7049](https://github.com/influxdata/telegraf/pull/7049): Add support for converting tag or field to measurement in converter processor. +- [#7103](https://github.com/influxdata/telegraf/pull/7103): Add volume_mount_point to DatabaseIO query in sqlserver input. +- [#7142](https://github.com/influxdata/telegraf/pull/7142): Add topic tag options to kafka output. +- [#7141](https://github.com/influxdata/telegraf/pull/7141): Add support for setting InfluxDB retention policy using tag. +- [#7163](https://github.com/influxdata/telegraf/pull/7163): Add Database IO Tempdb per Azure DB to sqlserver input. +- [#7150](https://github.com/influxdata/telegraf/pull/7150): Add option for explicitly including queries in sqlserver input. +- [#7173](https://github.com/influxdata/telegraf/pull/7173): Add support for GNMI DecimalVal type to cisco_telemetry_gnmi. + +### Bug Fixes + +- [#6397](https://github.com/influxdata/telegraf/issues/6397): Fix conversion to floats in AzureDBResourceStats query in the sqlserver input. +- [#6867](https://github.com/influxdata/telegraf/issues/6867): Fix case sensitive collation in sqlserver input. +- [#7005](https://github.com/influxdata/telegraf/pull/7005): Search for chronyc only when chrony input plugin is enabled. +- [#2280](https://github.com/influxdata/telegraf/issues/2280): Fix request to InfluxDB Listener failing with EOF. +- [#6124](https://github.com/influxdata/telegraf/issues/6124): Fix InfluxDB listener to continue parsing after error. +- [#7133](https://github.com/influxdata/telegraf/issues/7133): Fix log rotation to use actual file size instead of bytes written. +- [#7103](https://github.com/influxdata/telegraf/pull/7103): Fix several issues with DatabaseIO query in sqlserver input. +- [#7119](https://github.com/influxdata/telegraf/pull/7119): Fix internal metrics for output split into multiple lines. +- [#7021](https://github.com/influxdata/telegraf/pull/7021): Fix schedulers query compatibility with pre SQL-2016. +- [#7182](https://github.com/influxdata/telegraf/pull/7182): Set headers on influxdb_listener ping URL. +- [#7165](https://github.com/influxdata/telegraf/issues/7165): Fix url encoding of job names in jenkins input plugin. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..553fc0c --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,77 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +`community@influxdata.com`. + +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +[version 2.1][v2.1]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3a4451b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,129 @@ +# Contributing to Telegraf + +There are many ways to get involved in the Telegraf project! From opening issues, creating pull requests, to joining the conversation in Slack. We would love to see you contribute your expertise and join our community. To get started review this document to learn best practices. + +![tiger](assets/GopherAndTiger.png "tiger") + +## Opening Issues + +### Bug reports + +Before you file an issue, please search existing issues in case it has already been filed, or perhaps even fixed. If you file an issue, please ensure you include all the requested details (e.g. Telegraf config and logs, platform, etc.) + +Please note that issues are not the place to file general support requests such as "How do I use the mongoDB plugin?" Questions of this nature should be sent to the [Community Slack](https://influxdata.com/slack) or [Community Page](https://community.influxdata.com/), not filed as issues. + +### Feature requests + +We really like to receive feature requests as it helps us prioritize our work. Before you file a feature request, please search existing issues, you can filter issues that have the label `feature request`. Please be clear about your requirements and goals, help us to understand what you would like to see added to Telegraf with examples and the reasons why it is important to you. If you find your feature request already exists as a Github issue please indicate your support for that feature by using the "thumbs up" reaction. + +### Support questions + +We recommend posting support questions in our [Community Slack](https://influxdata.com/slack) or [Community Page](https://community.influxdata.com/), we have a lot of talented community members there who could help answer your question more quickly. + +## Contributing code + +### AI Generated Code + +We currently cannot accept AI generated code contributions. Code contributed +should be your own per the CLA. + +### Creating a pull request + +1. [Sign the CLA][cla]. +2. Open a [new issue][] to discuss the changes you would like to make. This is + not strictly required but it may help reduce the amount of rework you need + to do later. +3. Make changes or write plugin using the guidelines in the following + documents: + - [Input Plugins][inputs] + - [Processor Plugins][processors] + - [Aggregator Plugins][aggregators] + - [Output Plugins][outputs] +4. Ensure you have added proper unit tests and documentation. +5. Open a new [pull request][]. +6. The pull request title needs to follow [conventional commit format](https://www.conventionalcommits.org/en/v1.0.0/#summary) + +**Note:** If you have a pull request with only one commit, then that commit needs to follow the conventional commit format or the `Semantic Pull Request` check will fail. This is because github will use the pull request title if there are multiple commits, but if there is only one commit it will use it instead. + +### When will your contribution get released? + +We have two kinds of releases: patch releases, which happen every few weeks, and feature releases, which happen once a quarter. If your fix is a bug fix, it will be released in the next patch release after it is merged to master. If your release is a new plugin or other feature, it will be released in the next quarterly release after it is merged to master. Quarterly releases are on the third Wednesday of March, June, September, and December. + +### Contributing an External Plugin + +Input, output, and processor plugins written for internal Telegraf can be run as externally-compiled plugins through the [Execd Input](/plugins/inputs/execd), [Execd Output](/plugins/outputs/execd), and [Execd Processor](/plugins/processors/execd) Plugins without having to change the plugin code. + +Follow the guidelines of how to integrate your plugin with the [Execd Go Shim](/plugins/common/shim) to easily compile it as a separate app and run it with the respective `execd` plugin. +Check out our [guidelines](/docs/EXTERNAL_PLUGINS.md#external-plugin-guidelines) on how to build and set up your external plugins to run with `execd`. + +## Security Vulnerability Reporting + +InfluxData takes security and our users' trust very seriously. If you believe you have found a security issue in any of our +open source projects, please responsibly disclose it by contacting `security@influxdata.com`. More details about +security vulnerability reporting, +including our GPG key, [can be found here](https://www.influxdata.com/how-to-report-security-vulnerabilities/). + +## Common development tasks + +**Adding a dependency:** + +Telegraf uses Go modules. Assuming you can already build the project, run this in the telegraf directory: + +1. `go get github.com/[dependency]/[new-package]` + +**Before opening a PR:** + +Before opening a pull request you should run the following checks locally to make sure the CI will pass. + +```shell +make lint +make check +make check-deps +make test +make docs +``` + +**Execute integration tests:** + +(Optional) + +To run only the integration tests use: + +```shell +make test-integration +``` + +To run the full test suite use: + +```shell +make test-all +``` + +### For more developer resources + +- [Code Style][codestyle] +- [Deprecation][deprecation] +- [Logging][logging] +- [Metric Format Changes][metricformat] +- [Packaging][packaging] +- [Profiling][profiling] +- [Reviews][reviews] +- [Sample Config][sample config] +- [Code of Conduct][code of conduct] + +[cla]: https://www.influxdata.com/legal/cla/ +[new issue]: https://github.com/influxdata/telegraf/issues/new/choose +[pull request]: https://github.com/influxdata/telegraf/compare +[inputs]: /docs/INPUTS.md +[processors]: /docs/PROCESSORS.md +[aggregators]: /docs/AGGREGATORS.md +[outputs]: /docs/OUTPUTS.md +[codestyle]: /docs/developers/CODE_STYLE.md +[deprecation]: /docs/developers/DEPRECATION.md +[logging]: /docs/developers/LOGGING.md +[metricformat]: /docs/developers/METRIC_FORMAT_CHANGES.md +[packaging]: /docs/developers/PACKAGING.md +[profiling]: /docs/developers/PROFILING.md +[reviews]: /docs/developers/REVIEWS.md +[sample config]: /docs/developers/SAMPLE_CONFIG.md +[code of conduct]: /CODE_OF_CONDUCT.md diff --git a/EXTERNAL_PLUGINS.md b/EXTERNAL_PLUGINS.md new file mode 100644 index 0000000..1ffb805 --- /dev/null +++ b/EXTERNAL_PLUGINS.md @@ -0,0 +1,48 @@ +# External Plugins + +This is a list of plugins that can be compiled outside of Telegraf and used via the `execd` [input](plugins/inputs/execd), [output](plugins/outputs/execd), or [processor](plugins/processors/execd). +Check out the [external plugin documentation](/docs/EXTERNAL_PLUGINS.md) for more information on writing and contributing a plugin. + +Pull requests welcome. + +## Inputs + +- [awsalarms](https://github.com/vipinvkmenon/awsalarms) - Simple plugin to gather/monitor alarms generated in AWS. +- [octoprint](https://github.com/BattleBas/octoprint-telegraf-plugin) - Gather 3d print information from the octoprint API. +- [opcda](https://github.com/lpc921/telegraf-execd-opcda) - Gather data from [OPC Foundation's Data Access (DA)](https://opcfoundation.org/about/opc-technologies/opc-classic/) protocol for industrial automation. +- [open-hardware-monitor](https://github.com/marianob85/open_hardware_monitor-telegraf-plugin) - Gather sensors data provided by [Open Hardware Monitor](http://openhardwaremonitor.org) +- [plex](https://github.com/russorat/telegraf-webhooks-plex) - Listens for events from Plex Media Server [Webhooks](https://support.plex.tv/articles/115002267687-webhooks/). +- [rand](https://github.com/ssoroka/rand) - Generate random numbers +- [SMCIPMITool](https://github.com/jhpope/smc_ipmi) - Python script to parse the output of [SMCIPMITool](https://www.supermicro.com/en/solutions/management-software/ipmi-utilities) into [InfluxDB line protocol](https://docs.influxdata.com/influxdb/latest/reference/syntax/line-protocol/). +- [systemd-timings](https://github.com/pdmorrow/telegraf-execd-systemd-timings) - Gather systemd boot and unit timestamp metrics. +- [twitter](https://github.com/inabagumi/twitter-telegraf-plugin) - Gather account information from Twitter accounts +- [youtube](https://github.com/inabagumi/youtube-telegraf-plugin) - Gather account information from YouTube channels +- [Big Blue Button](https://github.com/bigblueswarm/bigbluebutton-telegraf-plugin) - Gather meetings information from [Big Blue Button](https://bigbluebutton.org/) server +- [dnsmasq](https://github.com/machinly/dnsmasq-telegraf-plugin) - Gather dnsmasq statistics from dnsmasq +- [ldap_org and ds389](https://github.com/falon/CSI-telegraf-plugins) - Gather statistics from 389ds and from LDAP trees. +- [x509_crl](https://github.com/jcgonnard/telegraf-input-x590crl) - Gather information from your X509 CRL files +- [s7comm](https://github.com/nicolasme/s7comm) - Gather information from Siemens PLC +- [net_irtt](https://github.com/iAnatoly/telegraf-input-net_irtt) - Gather information from IRTT network test +- [dht_sensor](https://github.com/iAnatoly/telegraf-input-dht_sensor) - Gather temperature and humidity from DHTXX sensors +- [oracle](https://github.com/bonitoo-io/telegraf-input-oracle) - Gather the statistic data from Oracle RDBMS +- [db2](https://github.com/bonitoo-io/telegraf-input-db2) - Gather the statistic data from DB2 RDBMS +- [apt](https://github.com/x70b1/telegraf-apt) - Check Debian for package updates. +- [knot](https://github.com/x70b1/telegraf-knot) - Collect stats from Knot DNS. +- [fritzbox](https://github.com/hdecarne-github/fritzbox-telegraf-plugin) - Gather statistics from [FRITZ!Box](https://avm.de/produkte/fritzbox/) router and repeater +- [linux-psi-telegraf-plugin](https://github.com/gridscale/linux-psi-telegraf-plugin) - Gather pressure stall information ([PSI](https://facebookmicrosites.github.io/psi/)) from the Linux Kernel +- [hwinfo](https://github.com/zachstence/hwinfo-telegraf-plugin) - Gather Windows system hardware information from [HWiNFO](https://www.hwinfo.com/) +- [libvirt](https://gitlab.com/warrenio/tools/telegraf-input-libvirt) - Gather libvirt domain stats, based on a historical Telegraf implementation [libvirt](https://libvirt.org/) +- [bacnet](https://github.com/JurajMarcin/telegraf-bacnet) - Gather statistics from BACnet devices, with support for device discovery and Change of Value subscriptions +- [tado](https://github.com/zoeimogen/tado-telegraf-plugin) - Gather zone temperature settings and current temperature/humidity readings from Tado +- [homekit](https://github.com/hdecarne-github/homekit-telegraf-plugin) - Gather smart home statistics from [HomeKit](https://en.wikipedia.org/wiki/HomeKit) devices via Home Hub automation + +## Outputs + +- [kinesis](https://github.com/morfien101/telegraf-output-kinesis) - Aggregation and compression of metrics to send Amazon Kinesis. +- [firehose](https://github.com/muhlba91/telegraf-output-kinesis-data-firehose) - Sends metrics in batches to Amazon Kinesis Data Firehose. +- [playfab](https://github.com/dgkanatsios/telegraftoplayfab) - Sends metrics to [Azure PlayFab](https://learn.microsoft.com/en-us/gaming/playfab/). + +## Processors + +- [geoip](https://github.com/a-bali/telegraf-geoip) - Add GeoIP information to IP addresses. +- [metadata](https://github.com/lawdt/metadata) - Appends metadata gathered from Openstack to metrics. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..241f4ee --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015-2025 InfluxData Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ba04895 --- /dev/null +++ b/Makefile @@ -0,0 +1,502 @@ +ifneq (,$(filter $(OS),Windows_NT Windows)) + EXEEXT=.exe +endif + +cat := $(if $(filter $(OS),sh.exe),type,cat) +next_version := $(shell $(cat) build_version.txt) +tag := $(shell git describe --exact-match --tags 2>/dev/null) + +branch := $(shell git rev-parse --abbrev-ref HEAD) +commit := $(shell git rev-parse --short=8 HEAD) + +ifdef NIGHTLY + version := $(next_version) + rpm_version := nightly + rpm_iteration := 0 + deb_version := nightly + deb_iteration := 0 + tar_version := nightly +else ifeq ($(tag),) + version := $(next_version) + rpm_version := $(version)~$(commit)-0 + rpm_iteration := 0 + deb_version := $(version)~$(commit)-0 + deb_iteration := 0 + tar_version := $(version)~$(commit) +else ifneq ($(findstring -rc,$(tag)),) + version := $(word 1,$(subst -, ,$(tag))) + version := $(version:v%=%) + rc := $(word 2,$(subst -, ,$(tag))) + rpm_version := $(version)-0.$(rc) + rpm_iteration := 0.$(subst rc,,$(rc)) + deb_version := $(version)~$(rc)-1 + deb_iteration := 0 + tar_version := $(version)~$(rc) +else + version := $(tag:v%=%) + rpm_version := $(version)-1 + rpm_iteration := 1 + deb_version := $(version)-1 + deb_iteration := 1 + tar_version := $(version) +endif + +MAKEFLAGS += --no-print-directory +GOOS ?= $(shell go env GOOS) +GOARCH ?= $(shell go env GOARCH) +HOSTGO := env -u GOOS -u GOARCH -u GOARM -- go +INTERNAL_PKG=github.com/influxdata/telegraf/internal +LDFLAGS := $(LDFLAGS) -X $(INTERNAL_PKG).Commit=$(commit) -X $(INTERNAL_PKG).Branch=$(branch) +ifneq ($(tag),) + LDFLAGS += -X $(INTERNAL_PKG).Version=$(version) +else + LDFLAGS += -X $(INTERNAL_PKG).Version=$(version)-$(commit) +endif + +# Go built-in race detector works only for 64 bits architectures. +ifneq ($(GOARCH), 386) + # Resolve macOS issue with Xcode 15 when running in race detector mode + # https://github.com/golang/go/issues/61229 + ifeq ($(GOOS), darwin) + race_detector := -race -ldflags=-extldflags=-Wl,-ld_classic + else + race_detector := -race + endif +endif + + +GOFILES ?= $(shell git ls-files '*.go') +GOFMT ?= $(shell gofmt -l -s $(filter-out plugins/parsers/influx/machine.go, $(GOFILES))) + +prefix ?= /usr/local +bindir ?= $(prefix)/bin +sysconfdir ?= $(prefix)/etc +localstatedir ?= $(prefix)/var +pkgdir ?= build/dist + +.PHONY: all +all: deps docs telegraf + +.PHONY: help +help: + @echo 'Targets:' + @echo ' all - download dependencies and compile telegraf binary' + @echo ' config - generate the config from current repo state' + @echo ' deps - download dependencies' + @echo ' docs - embed sample-configurations into READMEs' + @echo ' telegraf - compile telegraf binary' + @echo ' test - run short unit tests' + @echo ' fmt - format source files' + @echo ' tidy - tidy go modules' + @echo ' lint - run linter' + @echo ' lint-branch - run linter on changes in current branch since master' + @echo ' lint-install - install linter' + @echo ' check-deps - check docs/LICENSE_OF_DEPENDENCIES.md' + @echo ' clean - delete build artifacts' + @echo ' package - build all supported packages, override include_packages to only build a subset' + @echo ' e.g.: make package include_packages="amd64.deb"' + @echo '' + @echo 'Possible values for include_packages variable' + @$(foreach package,$(include_packages),echo " $(package)";) + @echo '' + @echo 'Resulting package name format (where arch will be the arch of the package):' + @echo ' telegraf_$(deb_version)_arch.deb' + @echo ' telegraf-$(rpm_version).arch.rpm' + @echo ' telegraf-$(tar_version)_arch.tar.gz' + @echo ' telegraf-$(tar_version)_arch.zip' + + +.PHONY: deps +deps: + go mod download -x + +.PHONY: version +version: + @echo $(version)-$(commit) + +build_tools: + $(HOSTGO) build -o ./tools/custom_builder/custom_builder$(EXEEXT) ./tools/custom_builder + $(HOSTGO) build -o ./tools/license_checker/license_checker$(EXEEXT) ./tools/license_checker + $(HOSTGO) build -o ./tools/readme_config_includer/generator$(EXEEXT) ./tools/readme_config_includer/generator.go + $(HOSTGO) build -o ./tools/config_includer/generator$(EXEEXT) ./tools/config_includer/generator.go + $(HOSTGO) build -o ./tools/readme_linter/readme_linter$(EXEEXT) ./tools/readme_linter + +embed_readme_%: + go generate -run="tools/config_includer/generator" ./plugins/$*/... + go generate -run="tools/readme_config_includer/generator" ./plugins/$*/... + +.PHONY: config +config: + @echo "generating default config" + go run ./cmd/telegraf config > etc/telegraf.conf + +.PHONY: docs +docs: build_tools embed_readme_inputs embed_readme_outputs embed_readme_processors embed_readme_aggregators embed_readme_secretstores + +.PHONY: build +build: + CGO_ENABLED=0 go build -tags "$(BUILDTAGS)" -ldflags "$(LDFLAGS)" ./cmd/telegraf + +.PHONY: telegraf +telegraf: build + +# Used by dockerfile builds +.PHONY: go-install +go-install: + go install -mod=mod -ldflags "-w -s $(LDFLAGS)" ./cmd/telegraf + +.PHONY: test +test: + go test -short $(race_detector) ./... + +.PHONY: test-integration +test-integration: + go test -run Integration $(race_detector) ./... + +.PHONY: fmt +fmt: + @gofmt -s -w $(filter-out plugins/parsers/influx/machine.go, $(GOFILES)) + +.PHONY: fmtcheck +fmtcheck: + @if [ ! -z "$(GOFMT)" ]; then \ + echo "[ERROR] gofmt has found errors in the following files:" ; \ + echo "$(GOFMT)" ; \ + echo "" ;\ + echo "Run make fmt to fix them." ; \ + exit 1 ;\ + fi + +.PHONY: vet +vet: + @echo 'go vet $$(go list ./... | grep -v ./plugins/parsers/influx)' + @go vet $$(go list ./... | grep -v ./plugins/parsers/influx) ; if [ $$? -ne 0 ]; then \ + echo ""; \ + echo "go vet has found suspicious constructs. Please remediate any reported errors"; \ + echo "to fix them before submitting code for review."; \ + exit 1; \ + fi + +.PHONY: lint-install +lint-install: + @echo "Installing golangci-lint" + go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.2 + + @echo "Installing markdownlint" + npm install -g markdownlint-cli + +.PHONY: lint +lint: + @which golangci-lint >/dev/null 2>&1 || { \ + echo "golangci-lint not found, please run: make lint-install"; \ + exit 1; \ + } + golangci-lint run + + @which markdownlint >/dev/null 2>&1 || { \ + echo "markdownlint not found, please run: make lint-install"; \ + exit 1; \ + } + markdownlint . + +.PHONY: lint-branch +lint-branch: + @which golangci-lint >/dev/null 2>&1 || { \ + echo "golangci-lint not found, please run: make lint-install"; \ + exit 1; \ + } + golangci-lint run + +.PHONY: tidy +tidy: + go mod verify + go mod tidy + @if ! git diff --quiet go.mod go.sum; then \ + echo "please run go mod tidy and check in changes, you might have to use the same version of Go as the CI"; \ + exit 1; \ + fi + +.PHONY: check +check: fmtcheck vet + +.PHONY: test-all +test-all: fmtcheck vet + go test $(race_detector) ./... + +.PHONY: check-deps +check-deps: + ./scripts/check-deps.sh + +.PHONY: clean +clean: + rm -f telegraf + rm -f telegraf.exe + rm -f etc/telegraf.conf + rm -rf build + rm -rf cmd/telegraf/resource.syso + rm -rf cmd/telegraf/versioninfo.json + rm -rf tools/config_includer/generator + rm -rf tools/config_includer/generator.exe + rm -rf tools/custom_builder/custom_builder + rm -rf tools/custom_builder/custom_builder.exe + rm -rf tools/license_checker/license_checker + rm -rf tools/license_checker/license_checker.exe + rm -rf tools/package_incus_test/package_incus_test + rm -rf tools/package_incus_test/package_incus_test.exe + rm -rf tools/readme_config_includer/generator + rm -rf tools/readme_config_includer/generator.exe + rm -rf tools/readme_linter/readme_linter + rm -rf tools/readme_linter/readme_linter.exe + +.PHONY: docker-image +docker-image: + docker build -f scripts/buster.docker -t "telegraf:$(commit)" . + +plugins/parsers/influx/machine.go: plugins/parsers/influx/machine.go.rl + ragel -Z -G2 $^ -o $@ + +.PHONY: ci +ci: + docker build -t quay.io/influxdb/telegraf-ci:1.24.3 - < scripts/ci.docker + docker push quay.io/influxdb/telegraf-ci:1.24.3 + +.PHONY: install +install: $(buildbin) + @mkdir -pv $(DESTDIR)$(bindir) + @mkdir -pv $(DESTDIR)$(sysconfdir) + @mkdir -pv $(DESTDIR)$(localstatedir) + @if [ $(GOOS) != "windows" ]; then mkdir -pv $(DESTDIR)$(sysconfdir)/logrotate.d; fi + @if [ $(GOOS) != "windows" ]; then mkdir -pv $(DESTDIR)$(localstatedir)/log/telegraf; fi + @if [ $(GOOS) != "windows" ]; then mkdir -pv $(DESTDIR)$(sysconfdir)/telegraf/telegraf.d; fi + @cp -fv $(buildbin) $(DESTDIR)$(bindir) + @if [ $(GOOS) != "windows" ]; then cp -fv etc/telegraf.conf $(DESTDIR)$(sysconfdir)/telegraf/telegraf.conf$(conf_suffix); fi + @if [ $(GOOS) != "windows" ]; then cp -fv etc/logrotate.d/telegraf $(DESTDIR)$(sysconfdir)/logrotate.d; fi + @if [ $(GOOS) = "windows" ]; then cp -fv etc/telegraf.conf $(DESTDIR)/telegraf.conf; fi + @if [ $(GOOS) = "linux" ]; then mkdir -pv $(DESTDIR)$(prefix)/lib/telegraf/scripts; fi + @if [ $(GOOS) = "linux" ]; then cp -fv scripts/telegraf.service $(DESTDIR)$(prefix)/lib/telegraf/scripts; fi + @if [ $(GOOS) = "linux" ]; then cp -fv scripts/init.sh $(DESTDIR)$(prefix)/lib/telegraf/scripts; fi + +# Telegraf build per platform. This improves package performance by sharing +# the bin between deb/rpm/tar packages over building directly into the package +# directory. +.PHONY: $(buildbin) +$(buildbin): + echo $(GOOS) + @mkdir -pv $(dir $@) + CGO_ENABLED=0 go build -o $(dir $@) -tags "$(BUILDTAGS)" -ldflags "$(LDFLAGS)" ./cmd/telegraf + +# Define packages Telegraf supports, organized by architecture with a rule to echo the list to limit include_packages +# e.g. make package include_packages="$(make amd64)" +mips += linux_mips.tar.gz mips.deb +.PHONY: mips +mips: + @ echo $(mips) +mipsel += mipsel.deb linux_mipsel.tar.gz +.PHONY: mipsel +mipsel: + @ echo $(mipsel) +loong64 += linux_loong64.tar.gz loong64.deb loong64.rpm +.PHONY: loong64 +loong64: + @ echo $(loong64) +arm64 += linux_arm64.tar.gz arm64.deb aarch64.rpm +.PHONY: arm64 +arm64: + @ echo $(arm64) +amd64 += freebsd_amd64.tar.gz linux_amd64.tar.gz amd64.deb x86_64.rpm +.PHONY: amd64 +amd64: + @ echo $(amd64) +armel += linux_armel.tar.gz armel.rpm armel.deb +.PHONY: armel +armel: + @ echo $(armel) +armhf += linux_armhf.tar.gz freebsd_armv7.tar.gz armhf.deb armv6hl.rpm +.PHONY: armhf +armhf: + @ echo $(armhf) +s390x += linux_s390x.tar.gz s390x.deb s390x.rpm +.PHONY: riscv64 +riscv64: + @ echo $(riscv64) +riscv64 += linux_riscv64.tar.gz riscv64.rpm riscv64.deb +.PHONY: s390x +s390x: + @ echo $(s390x) +ppc64le += linux_ppc64le.tar.gz ppc64le.rpm ppc64el.deb +.PHONY: ppc64le +ppc64le: + @ echo $(ppc64le) +i386 += freebsd_i386.tar.gz i386.deb linux_i386.tar.gz i386.rpm +.PHONY: i386 +i386: + @ echo $(i386) +windows += windows_i386.zip windows_amd64.zip windows_arm64.zip +.PHONY: windows +windows: + @ echo $(windows) +darwin-amd64 += darwin_amd64.tar.gz +.PHONY: darwin-amd64 +darwin-amd64: + @ echo $(darwin-amd64) + +darwin-arm64 += darwin_arm64.tar.gz +.PHONY: darwin-arm64 +darwin-arm64: + @ echo $(darwin-arm64) + +include_packages := $(mips) $(mipsel) $(arm64) $(amd64) $(armel) $(armhf) $(riscv64) $(loong64) $(s390x) $(ppc64le) $(i386) $(windows) $(darwin-amd64) $(darwin-arm64) + +.PHONY: package +package: docs config $(include_packages) + +.PHONY: $(include_packages) +$(include_packages): + if [ "$(suffix $@)" = ".zip" ]; then go generate cmd/telegraf/telegraf_windows.go; fi + + @$(MAKE) install + @mkdir -p $(pkgdir) + + @if [ "$(suffix $@)" = ".rpm" ]; then \ + echo "# DO NOT EDIT OR REMOVE" > $(DESTDIR)$(sysconfdir)/telegraf/telegraf.d/.ignore; \ + echo "# This file prevents the rpm from changing permissions on this directory" >> $(DESTDIR)$(sysconfdir)/telegraf/telegraf.d/.ignore; \ + fpm --force \ + --log info \ + --architecture $(basename $@) \ + --input-type dir \ + --output-type rpm \ + --vendor InfluxData \ + --url https://github.com/influxdata/telegraf \ + --license MIT \ + --maintainer support@influxdb.com \ + --config-files /etc/telegraf/telegraf.conf \ + --config-files /etc/telegraf/telegraf.d/.ignore \ + --config-files /etc/logrotate.d/telegraf \ + --after-install scripts/rpm/post-install.sh \ + --before-install scripts/rpm/pre-install.sh \ + --after-remove scripts/rpm/post-remove.sh \ + --description "Plugin-driven server agent for reporting metrics into InfluxDB." \ + --depends coreutils \ + --rpm-digest sha256 \ + --rpm-posttrans scripts/rpm/post-install.sh \ + --rpm-os ${GOOS} \ + --rpm-tag "Requires(pre): /usr/sbin/useradd" \ + --name telegraf \ + --version $(version) \ + --iteration $(rpm_iteration) \ + --chdir $(DESTDIR) \ + --package $(pkgdir)/telegraf-$(rpm_version).$@ ;\ + elif [ "$(suffix $@)" = ".deb" ]; then \ + fpm --force \ + --log info \ + --architecture $(basename $@) \ + --input-type dir \ + --output-type deb \ + --vendor InfluxData \ + --url https://github.com/influxdata/telegraf \ + --license MIT \ + --maintainer support@influxdb.com \ + --config-files /etc/telegraf/telegraf.conf.sample \ + --config-files /etc/logrotate.d/telegraf \ + --after-install scripts/deb/post-install.sh \ + --before-install scripts/deb/pre-install.sh \ + --after-remove scripts/deb/post-remove.sh \ + --before-remove scripts/deb/pre-remove.sh \ + --description "Plugin-driven server agent for reporting metrics into InfluxDB." \ + --name telegraf \ + --version $(version) \ + --iteration $(deb_iteration) \ + --chdir $(DESTDIR) \ + --package $(pkgdir)/telegraf_$(deb_version)_$@ ;\ + elif [ "$(suffix $@)" = ".zip" ]; then \ + (cd $(dir $(DESTDIR)) && zip -r - ./*) > $(pkgdir)/telegraf-$(tar_version)_$@ ;\ + elif [ "$(suffix $@)" = ".gz" ]; then \ + tar --owner 0 --group 0 -czvf $(pkgdir)/telegraf-$(tar_version)_$@ -C $(dir $(DESTDIR)) . ;\ + fi + +amd64.deb x86_64.rpm linux_amd64.tar.gz: export GOOS := linux +amd64.deb x86_64.rpm linux_amd64.tar.gz: export GOARCH := amd64 + +i386.deb i386.rpm linux_i386.tar.gz: export GOOS := linux +i386.deb i386.rpm linux_i386.tar.gz: export GOARCH := 386 + +armel.deb armel.rpm linux_armel.tar.gz: export GOOS := linux +armel.deb armel.rpm linux_armel.tar.gz: export GOARCH := arm +armel.deb armel.rpm linux_armel.tar.gz: export GOARM := 5 + +armhf.deb armv6hl.rpm linux_armhf.tar.gz: export GOOS := linux +armhf.deb armv6hl.rpm linux_armhf.tar.gz: export GOARCH := arm +armhf.deb armv6hl.rpm linux_armhf.tar.gz: export GOARM := 6 + +arm64.deb aarch64.rpm linux_arm64.tar.gz: export GOOS := linux +arm64.deb aarch64.rpm linux_arm64.tar.gz: export GOARCH := arm64 +arm64.deb aarch64.rpm linux_arm64.tar.gz: export GOARM := 7 + +mips.deb linux_mips.tar.gz: export GOOS := linux +mips.deb linux_mips.tar.gz: export GOARCH := mips + +mipsel.deb linux_mipsel.tar.gz: export GOOS := linux +mipsel.deb linux_mipsel.tar.gz: export GOARCH := mipsle + +riscv64.deb riscv64.rpm linux_riscv64.tar.gz: export GOOS := linux +riscv64.deb riscv64.rpm linux_riscv64.tar.gz: export GOARCH := riscv64 + +loong64.deb loong64.rpm linux_loong64.tar.gz: export GOOS := linux +loong64.deb loong64.rpm linux_loong64.tar.gz: export GOARCH := loong64 + +s390x.deb s390x.rpm linux_s390x.tar.gz: export GOOS := linux +s390x.deb s390x.rpm linux_s390x.tar.gz: export GOARCH := s390x + +ppc64el.deb ppc64le.rpm linux_ppc64le.tar.gz: export GOOS := linux +ppc64el.deb ppc64le.rpm linux_ppc64le.tar.gz: export GOARCH := ppc64le + +freebsd_amd64.tar.gz: export GOOS := freebsd +freebsd_amd64.tar.gz: export GOARCH := amd64 + +freebsd_i386.tar.gz: export GOOS := freebsd +freebsd_i386.tar.gz: export GOARCH := 386 + +freebsd_armv7.tar.gz: export GOOS := freebsd +freebsd_armv7.tar.gz: export GOARCH := arm +freebsd_armv7.tar.gz: export GOARM := 7 + +windows_amd64.zip: export GOOS := windows +windows_amd64.zip: export GOARCH := amd64 + +windows_arm64.zip: export GOOS := windows +windows_arm64.zip: export GOARCH := arm64 + +darwin_amd64.tar.gz: export GOOS := darwin +darwin_amd64.tar.gz: export GOARCH := amd64 + +darwin_arm64.tar.gz: export GOOS := darwin +darwin_arm64.tar.gz: export GOARCH := arm64 + +windows_i386.zip: export GOOS := windows +windows_i386.zip: export GOARCH := 386 + +windows_i386.zip windows_amd64.zip windows_arm64.zip: export prefix = +windows_i386.zip windows_amd64.zip windows_arm64.zip: export bindir = $(prefix) +windows_i386.zip windows_amd64.zip windows_arm64.zip: export sysconfdir = $(prefix) +windows_i386.zip windows_amd64.zip windows_arm64.zip: export localstatedir = $(prefix) +windows_i386.zip windows_amd64.zip windows_arm64.zip: export EXEEXT := .exe + +%.deb: export pkg := deb +%.deb: export prefix := /usr +%.deb: export conf_suffix := .sample +%.deb: export sysconfdir := /etc +%.deb: export localstatedir := /var +%.rpm: export pkg := rpm +%.rpm: export prefix := /usr +%.rpm: export sysconfdir := /etc +%.rpm: export localstatedir := /var +%.tar.gz: export pkg := tar +%.tar.gz: export prefix := /usr +%.tar.gz: export sysconfdir := /etc +%.tar.gz: export localstatedir := /var +%.zip: export pkg := zip +%.zip: export prefix := / + +%.deb %.rpm %.tar.gz %.zip: export DESTDIR = build/$(GOOS)-$(GOARCH)$(GOARM)-$(pkg)/telegraf-$(version) +%.deb %.rpm %.tar.gz %.zip: export buildbin = build/$(GOOS)-$(GOARCH)$(GOARM)/telegraf$(EXEEXT) +%.deb %.rpm %.tar.gz %.zip: export LDFLAGS = -w -s diff --git a/README.md b/README.md new file mode 100644 index 0000000..c073cd1 --- /dev/null +++ b/README.md @@ -0,0 +1,126 @@ +# ![tiger](assets/TelegrafTigerSmall.png "tiger") Telegraf + +[![GoDoc](https://img.shields.io/badge/doc-reference-00ADD8.svg?logo=go)](https://godoc.org/github.com/influxdata/telegraf) +[![Docker pulls](https://img.shields.io/docker/pulls/library/telegraf.svg)](https://hub.docker.com/_/telegraf/) +[![Go Report Card](https://goreportcard.com/badge/github.com/influxdata/telegraf)](https://goreportcard.com/report/github.com/influxdata/telegraf) +[![Circle CI](https://circleci.com/gh/influxdata/telegraf.svg?style=svg)](https://circleci.com/gh/influxdata/telegraf) + +Telegraf is an agent for collecting, processing, aggregating, and writing +metrics, logs, and other arbitrary data. + +* Offers a comprehensive suite of over 300 plugins, covering a wide range of + functionalities including system monitoring, cloud services, and message + passing +* Enables the integration of user-defined code to collect, transform, and + transmit data efficiently +* Compiles into a standalone static binary without any external dependencies, + ensuring a streamlined deployment process +* Utilizes TOML for configuration, providing a user-friendly and unambiguous + setup experience +* Developed with contributions from a diverse community of over 1,200 + contributors + +Users can choose plugins from a wide range of topics, including but not limited +to: + +* Devices: [OPC UA][], [Modbus][] +* Logs: [File][], [Tail][], [Directory Monitor][] +* Messaging: [AMQP][], [Kafka][], [MQTT][] +* Monitoring: [OpenTelemetry][], [Prometheus][] +* Networking: [Cisco TelemetryMDT][], [gNMI][] +* System monitoring: [CPU][], [Memory][], [Disk][], [Network][], [SMART][], + [Docker][], [Nvidia SMI][], etc. +* Universal: [Exec][], [HTTP][], [HTTP Listener][], [SNMP][], [SQL][] +* Windows: [Event Log][], [Management Instrumentation][], + [Performance Counters][] + +## 🔨 Installation + +For binary builds, Docker images, RPM & DEB packages, and other builds of +Telegraf, please see the [install guide](/docs/INSTALL_GUIDE.md). + +See the [releases documentation](/docs/RELEASES.md) for details on versioning +and when releases are made. + +## 💻 Usage + +Users define a TOML configuration with the plugins and settings they wish to +use, then pass that configuration to Telegraf. The Telegraf agent then +collects data from inputs at each interval and sends data to outputs at each +flush interval. + +For a basic walkthrough see [quick start](/docs/QUICK_START.md). + +## 📖 Documentation + +For a full list of documentation including tutorials, reference and other +material, start with the [/docs directory](/docs/README.md). + +Additionally, each plugin has its own README that includes details about how to +configure, use, and sometimes debug or troubleshoot. Look under the +[/plugins directory](/plugins/) for specific plugins. + +Here are some commonly used documents: + +* [Changelog](/CHANGELOG.md) +* [Configuration](/docs/CONFIGURATION.md) +* [FAQ](/docs/FAQ.md) +* [Releases](https://github.com/influxdata/telegraf/releases) +* [Security](/SECURITY.md) + +## ❤️ Contribute + +[![Contribute](https://img.shields.io/badge/contribute-to_telegraf-blue.svg?logo=influxdb)](https://github.com/influxdata/telegraf/blob/master/CONTRIBUTING.md) + +We love our community of over 1,200 contributors! Many of the plugins included +in Telegraf were originally contributed by community members. Check out +our [contributing guide](CONTRIBUTING.md) if you are interested in helping out. +Also, join us on our [Community Slack](https://influxdata.com/slack) or +[Community Forums](https://community.influxdata.com/) if you have questions or +comments for our engineering teams. + +If you are completely new to Telegraf and InfluxDB, you can also enroll for free +at [InfluxDB university](https://www.influxdata.com/university/) to take courses +to learn more. + +## ℹ️ Support + +[![Slack](https://img.shields.io/badge/slack-join_chat-blue.svg?logo=slack)](https://www.influxdata.com/slack) +[![Forums](https://img.shields.io/badge/discourse-join_forums-blue.svg?logo=discourse)](https://community.influxdata.com/) + +Please use the [Community Slack](https://influxdata.com/slack) or +[Community Forums](https://community.influxdata.com/) if you have questions or +comments for our engineering teams. GitHub issues are limited to actual issues +and feature requests only. + +## 📜 License + +[![MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/influxdata/telegraf/blob/master/LICENSE) + +[OPC UA]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/opcua +[Modbus]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/modbus +[File]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/file +[Tail]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/tail +[Directory Monitor]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/directory_monitor +[AMQP]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/amqp_consumer +[Kafka]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/kafka_consumer +[MQTT]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/mqtt_consumer +[OpenTelemetry]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/opentelemetry +[Prometheus]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/prometheus +[Cisco TelemetryMDT]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/cisco_telemetry_mdt +[gNMI]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/gnmi +[CPU]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/cpu +[Memory]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/mem +[Disk]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/disk +[Network]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/net +[SMART]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/smartctl +[Docker]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/docker +[Nvidia SMI]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nvidia_smi +[Exec]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/exec +[HTTP]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/http +[HTTP Listener]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/http_listener_v2 +[SNMP]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/snmp +[SQL]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/sql +[Event Log]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/win_eventlog +[Management Instrumentation]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/win_wmi +[Performance Counters]: https://github.com/influxdata/telegraf/tree/master/plugins/inputs/win_perf_counters diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..4e017ac --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,11 @@ +# Security Policy + +## Reporting a Vulnerability + +InfluxData takes security and our users' trust seriously. If you believe you +have found a security issue in any of our open source projects, please +responsibly disclose it by contacting `security@influxdata.com`. More details +about security vulnerability reporting can be found on the +[InfluxData How to Report Vulnerabilities page][InfluxData Security]. + +[InfluxData Security]: https://www.influxdata.com/how-to-report-security-vulnerabilities/ diff --git a/accumulator.go b/accumulator.go new file mode 100644 index 0000000..6d740fb --- /dev/null +++ b/accumulator.go @@ -0,0 +1,93 @@ +package telegraf + +import ( + "time" +) + +// Accumulator allows adding metrics to the processing flow. +type Accumulator interface { + // AddFields adds a metric to the accumulator with the given measurement + // name, fields, and tags (and timestamp). If a timestamp is not provided, + // then the accumulator sets it to "now". + AddFields(measurement string, + fields map[string]interface{}, + tags map[string]string, + t ...time.Time) + + // AddGauge is the same as AddFields, but will add the metric as a "Gauge" type + AddGauge(measurement string, + fields map[string]interface{}, + tags map[string]string, + t ...time.Time) + + // AddCounter is the same as AddFields, but will add the metric as a "Counter" type + AddCounter(measurement string, + fields map[string]interface{}, + tags map[string]string, + t ...time.Time) + + // AddSummary is the same as AddFields, but will add the metric as a "Summary" type + AddSummary(measurement string, + fields map[string]interface{}, + tags map[string]string, + t ...time.Time) + + // AddHistogram is the same as AddFields, but will add the metric as a "Histogram" type + AddHistogram(measurement string, + fields map[string]interface{}, + tags map[string]string, + t ...time.Time) + + // AddMetric adds a metric to the accumulator. + AddMetric(Metric) + + // SetPrecision sets the timestamp rounding precision. All metrics + // added to the accumulator will have their timestamp rounded to the + // nearest multiple of precision. + SetPrecision(precision time.Duration) + + // Report an error. + AddError(err error) + + // Upgrade to a TrackingAccumulator with space for maxTracked + // metrics/batches. + WithTracking(maxTracked int) TrackingAccumulator +} + +// TrackingID uniquely identifies a tracked metric group +type TrackingID uint64 + +type TrackingData interface { + // ID is the TrackingID + ID() TrackingID + + // RefCount is the number of tracking metrics still persistent and referencing this tracking ID + RefCount() int32 +} + +// DeliveryInfo provides the results of a delivered metric group. +type DeliveryInfo interface { + // ID is the TrackingID + ID() TrackingID + + // Delivered returns true if the metric was processed successfully. + Delivered() bool +} + +// TrackingAccumulator is an Accumulator that provides a signal when the +// metric has been fully processed. Sending more metrics than the accumulator +// has been allocated for without reading status from the Accepted or Rejected +// channels is an error. +type TrackingAccumulator interface { + Accumulator + + // Add the Metric and arrange for tracking feedback after processing. + AddTrackingMetric(m Metric) TrackingID + + // Add a group of Metrics and arrange for a signal when the group has been + // processed. + AddTrackingMetricGroup(group []Metric) TrackingID + + // Delivered returns a channel that will contain the tracking results. + Delivered() <-chan DeliveryInfo +} diff --git a/agent/README.md b/agent/README.md new file mode 100644 index 0000000..eb603e2 --- /dev/null +++ b/agent/README.md @@ -0,0 +1,6 @@ +# Agent + +For a complete list of configuration options and details about the agent, please +see the [configuration][] document's agent section. + +[configuration]: ../docs/CONFIGURATION.md#agent diff --git a/agent/accumulator.go b/agent/accumulator.go new file mode 100644 index 0000000..9105c17 --- /dev/null +++ b/agent/accumulator.go @@ -0,0 +1,160 @@ +package agent + +import ( + "time" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/metric" +) + +type MetricMaker interface { + LogName() string + MakeMetric(m telegraf.Metric) telegraf.Metric + Log() telegraf.Logger +} + +type accumulator struct { + maker MetricMaker + metrics chan<- telegraf.Metric + precision time.Duration +} + +func NewAccumulator( + maker MetricMaker, + metrics chan<- telegraf.Metric, +) telegraf.Accumulator { + acc := accumulator{ + maker: maker, + metrics: metrics, + precision: time.Nanosecond, + } + return &acc +} + +func (ac *accumulator) AddFields( + measurement string, + fields map[string]interface{}, + tags map[string]string, + t ...time.Time, +) { + ac.addMeasurement(measurement, tags, fields, telegraf.Untyped, t...) +} + +func (ac *accumulator) AddGauge( + measurement string, + fields map[string]interface{}, + tags map[string]string, + t ...time.Time, +) { + ac.addMeasurement(measurement, tags, fields, telegraf.Gauge, t...) +} + +func (ac *accumulator) AddCounter( + measurement string, + fields map[string]interface{}, + tags map[string]string, + t ...time.Time, +) { + ac.addMeasurement(measurement, tags, fields, telegraf.Counter, t...) +} + +func (ac *accumulator) AddSummary( + measurement string, + fields map[string]interface{}, + tags map[string]string, + t ...time.Time, +) { + ac.addMeasurement(measurement, tags, fields, telegraf.Summary, t...) +} + +func (ac *accumulator) AddHistogram( + measurement string, + fields map[string]interface{}, + tags map[string]string, + t ...time.Time, +) { + ac.addMeasurement(measurement, tags, fields, telegraf.Histogram, t...) +} + +func (ac *accumulator) AddMetric(m telegraf.Metric) { + m.SetTime(m.Time().Round(ac.precision)) + if m := ac.maker.MakeMetric(m); m != nil { + ac.metrics <- m + } +} + +func (ac *accumulator) addMeasurement( + measurement string, + tags map[string]string, + fields map[string]interface{}, + tp telegraf.ValueType, + t ...time.Time, +) { + m := metric.New(measurement, tags, fields, ac.getTime(t), tp) + if m := ac.maker.MakeMetric(m); m != nil { + ac.metrics <- m + } +} + +// AddError passes a runtime error to the accumulator. +// The error will be tagged with the plugin name and written to the log. +func (ac *accumulator) AddError(err error) { + if err == nil { + return + } + ac.maker.Log().Errorf("Error in plugin: %v", err) +} + +func (ac *accumulator) SetPrecision(precision time.Duration) { + ac.precision = precision +} + +func (ac *accumulator) getTime(t []time.Time) time.Time { + var timestamp time.Time + if len(t) > 0 { + timestamp = t[0] + } else { + timestamp = time.Now() + } + return timestamp.Round(ac.precision) +} + +func (ac *accumulator) WithTracking(maxTracked int) telegraf.TrackingAccumulator { + return &trackingAccumulator{ + Accumulator: ac, + delivered: make(chan telegraf.DeliveryInfo, maxTracked), + } +} + +type trackingAccumulator struct { + telegraf.Accumulator + delivered chan telegraf.DeliveryInfo +} + +func (a *trackingAccumulator) AddTrackingMetric(m telegraf.Metric) telegraf.TrackingID { + dm, id := metric.WithTracking(m, a.onDelivery) + a.AddMetric(dm) + return id +} + +func (a *trackingAccumulator) AddTrackingMetricGroup(group []telegraf.Metric) telegraf.TrackingID { + db, id := metric.WithGroupTracking(group, a.onDelivery) + for _, m := range db { + a.AddMetric(m) + } + return id +} + +func (a *trackingAccumulator) Delivered() <-chan telegraf.DeliveryInfo { + return a.delivered +} + +func (a *trackingAccumulator) onDelivery(info telegraf.DeliveryInfo) { + select { + case a.delivered <- info: + default: + // This is a programming error in the input. More items were sent for + // tracking than space requested. + panic("channel is full") + } +} diff --git a/agent/accumulator_test.go b/agent/accumulator_test.go new file mode 100644 index 0000000..51b3633 --- /dev/null +++ b/agent/accumulator_test.go @@ -0,0 +1,160 @@ +package agent + +import ( + "bytes" + "errors" + "os" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/logger" + "github.com/influxdata/telegraf/testutil" +) + +func TestAddFields(t *testing.T) { + metrics := make(chan telegraf.Metric, 10) + defer close(metrics) + a := NewAccumulator(&TestMetricMaker{}, metrics) + + tags := map[string]string{"foo": "bar"} + fields := map[string]interface{}{ + "usage": float64(99), + } + now := time.Now() + a.AddCounter("acctest", fields, tags, now) + + testm := <-metrics + + require.Equal(t, "acctest", testm.Name()) + actual, ok := testm.GetField("usage") + + require.True(t, ok) + require.InDelta(t, float64(99), actual, testutil.DefaultDelta) + + actual, ok = testm.GetTag("foo") + require.True(t, ok) + require.Equal(t, "bar", actual) + + tm := testm.Time() + // okay if monotonic clock differs + require.True(t, now.Equal(tm)) + + tp := testm.Type() + require.Equal(t, telegraf.Counter, tp) +} + +func TestAccAddError(t *testing.T) { + errBuf := bytes.NewBuffer(nil) + logger.RedirectLogging(errBuf) + defer logger.RedirectLogging(os.Stderr) + + metrics := make(chan telegraf.Metric, 10) + defer close(metrics) + a := NewAccumulator(&TestMetricMaker{}, metrics) + + a.AddError(errors.New("foo")) + a.AddError(errors.New("bar")) + a.AddError(errors.New("baz")) + + errs := bytes.Split(errBuf.Bytes(), []byte{'\n'}) + require.Len(t, errs, 4) // 4 because of trailing newline + require.Contains(t, string(errs[0]), "TestPlugin") + require.Contains(t, string(errs[0]), "foo") + require.Contains(t, string(errs[1]), "TestPlugin") + require.Contains(t, string(errs[1]), "bar") + require.Contains(t, string(errs[2]), "TestPlugin") + require.Contains(t, string(errs[2]), "baz") +} + +func TestSetPrecision(t *testing.T) { + tests := []struct { + name string + unset bool + precision time.Duration + timestamp time.Time + expected time.Time + }{ + { + name: "default precision is nanosecond", + unset: true, + timestamp: time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC), + expected: time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC), + }, + { + name: "second interval", + precision: time.Second, + timestamp: time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC), + expected: time.Date(2006, time.February, 10, 12, 0, 0, 0, time.UTC), + }, + { + name: "microsecond interval", + precision: time.Microsecond, + timestamp: time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC), + expected: time.Date(2006, time.February, 10, 12, 0, 0, 82913000, time.UTC), + }, + { + name: "2 second precision", + precision: 2 * time.Second, + timestamp: time.Date(2006, time.February, 10, 12, 0, 2, 4, time.UTC), + expected: time.Date(2006, time.February, 10, 12, 0, 2, 0, time.UTC), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + metrics := make(chan telegraf.Metric, 10) + + a := NewAccumulator(&TestMetricMaker{}, metrics) + if !tt.unset { + a.SetPrecision(tt.precision) + } + + a.AddFields("acctest", + map[string]interface{}{"value": float64(101)}, + map[string]string{}, + tt.timestamp, + ) + + testm := <-metrics + require.Equal(t, tt.expected, testm.Time()) + + close(metrics) + }) + } +} + +func TestAddTrackingMetricGroupEmpty(t *testing.T) { + ch := make(chan telegraf.Metric, 10) + metrics := make([]telegraf.Metric, 0) + acc := NewAccumulator(&TestMetricMaker{}, ch).WithTracking(1) + + id := acc.AddTrackingMetricGroup(metrics) + + select { + case tracking := <-acc.Delivered(): + require.Equal(t, tracking.ID(), id) + default: + t.Fatal("empty group should be delivered immediately") + } +} + +type TestMetricMaker struct { +} + +func (*TestMetricMaker) Name() string { + return "TestPlugin" +} + +func (tm *TestMetricMaker) LogName() string { + return tm.Name() +} + +func (*TestMetricMaker) MakeMetric(metric telegraf.Metric) telegraf.Metric { + return metric +} + +func (*TestMetricMaker) Log() telegraf.Logger { + return logger.New("TestPlugin", "test", "") +} diff --git a/agent/agent.go b/agent/agent.go new file mode 100644 index 0000000..76af7a3 --- /dev/null +++ b/agent/agent.go @@ -0,0 +1,1215 @@ +package agent + +import ( + "context" + "errors" + "fmt" + "log" + "os" + "runtime" + "sync" + "time" + + "github.com/fatih/color" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/config" + "github.com/influxdata/telegraf/internal" + "github.com/influxdata/telegraf/internal/snmp" + "github.com/influxdata/telegraf/models" + "github.com/influxdata/telegraf/plugins/processors" + "github.com/influxdata/telegraf/plugins/serializers/influx" +) + +// Agent runs a set of plugins. +type Agent struct { + Config *config.Config +} + +// NewAgent returns an Agent for the given Config. +func NewAgent(cfg *config.Config) *Agent { + a := &Agent{ + Config: cfg, + } + return a +} + +// inputUnit is a group of input plugins and the shared channel they write to. +// +// ┌───────┐ +// │ Input │───┐ +// └───────┘ │ +// ┌───────┐ │ ______ +// │ Input │───┼──▶ ()_____) +// └───────┘ │ +// ┌───────┐ │ +// │ Input │───┘ +// └───────┘ +type inputUnit struct { + dst chan<- telegraf.Metric + inputs []*models.RunningInput +} + +// ______ ┌───────────┐ ______ +// ()_____)──▶ │ Processor │──▶ ()_____) +// └───────────┘ + +type processorUnit struct { + src <-chan telegraf.Metric + dst chan<- telegraf.Metric + processor *models.RunningProcessor +} + +// aggregatorUnit is a group of Aggregators and their source and sink channels. +// Typically, the aggregators write to a processor channel and pass the original +// metrics to the output channel. The sink channels may be the same channel. + +// ┌────────────┐ +// ┌──▶ │ Aggregator │───┐ +// │ └────────────┘ │ +// ______ │ ┌────────────┐ │ ______ +// ()_____)───┼──▶ │ Aggregator │───┼──▶ ()_____) +// │ └────────────┘ │ +// │ ┌────────────┐ │ +// ├──▶ │ Aggregator │───┘ +// │ └────────────┘ +// │ ______ +// └────────────────────────▶ ()_____) + +type aggregatorUnit struct { + src <-chan telegraf.Metric + aggC chan<- telegraf.Metric + outputC chan<- telegraf.Metric + aggregators []*models.RunningAggregator +} + +// outputUnit is a group of Outputs and their source channel. Metrics on the +// channel are written to all outputs. + +// ┌────────┐ +// ┌──▶ │ Output │ +// │ └────────┘ +// ______ ┌─────┐ │ ┌────────┐ +// ()_____)──▶ │ Fan │───┼──▶ │ Output │ +// └─────┘ │ └────────┘ +// │ ┌────────┐ +// └──▶ │ Output │ +// └────────┘ + +type outputUnit struct { + src <-chan telegraf.Metric + outputs []*models.RunningOutput +} + +// Run starts and runs the Agent until the context is done. +func (a *Agent) Run(ctx context.Context) error { + log.Printf("I! [agent] Config: Interval:%s, Quiet:%#v, Hostname:%#v, "+ + "Flush Interval:%s", + time.Duration(a.Config.Agent.Interval), a.Config.Agent.Quiet, + a.Config.Agent.Hostname, time.Duration(a.Config.Agent.FlushInterval)) + + // Set the default for processor skipping + if a.Config.Agent.SkipProcessorsAfterAggregators == nil { + msg := `The default value of 'skip_processors_after_aggregators' will change to 'true' with Telegraf v1.40.0! ` + msg += `If you need the current default behavior, please explicitly set the option to 'false'!` + log.Print("W! [agent] ", color.YellowString(msg)) + skipProcessorsAfterAggregators := false + a.Config.Agent.SkipProcessorsAfterAggregators = &skipProcessorsAfterAggregators + } + + log.Printf("D! [agent] Initializing plugins") + if err := a.InitPlugins(); err != nil { + return err + } + + if a.Config.Persister != nil { + log.Printf("D! [agent] Initializing plugin states") + if err := a.initPersister(); err != nil { + return err + } + if err := a.Config.Persister.Load(); err != nil { + if !errors.Is(err, os.ErrNotExist) { + return err + } + log.Print("I! [agent] State file does not exist... Skip restoring states...") + } + } + + startTime := time.Now() + + log.Printf("D! [agent] Connecting outputs") + next, ou, err := a.startOutputs(ctx, a.Config.Outputs) + if err != nil { + return err + } + + var apu []*processorUnit + var au *aggregatorUnit + if len(a.Config.Aggregators) != 0 { + aggC := next + if len(a.Config.AggProcessors) != 0 && !*a.Config.Agent.SkipProcessorsAfterAggregators { + aggC, apu, err = a.startProcessors(next, a.Config.AggProcessors) + if err != nil { + return err + } + } + + next, au = a.startAggregators(aggC, next, a.Config.Aggregators) + } + + var pu []*processorUnit + if len(a.Config.Processors) != 0 { + next, pu, err = a.startProcessors(next, a.Config.Processors) + if err != nil { + return err + } + } + + iu, err := a.startInputs(next, a.Config.Inputs) + if err != nil { + return err + } + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + a.runOutputs(ou) + }() + + if au != nil { + wg.Add(1) + go func() { + defer wg.Done() + a.runProcessors(apu) + }() + + wg.Add(1) + go func() { + defer wg.Done() + a.runAggregators(startTime, au) + }() + } + + if pu != nil { + wg.Add(1) + go func() { + defer wg.Done() + a.runProcessors(pu) + }() + } + + wg.Add(1) + go func() { + defer wg.Done() + a.runInputs(ctx, startTime, iu) + }() + + wg.Wait() + + if a.Config.Persister != nil { + log.Printf("D! [agent] Persisting plugin states") + if err := a.Config.Persister.Store(); err != nil { + return err + } + } + + log.Printf("D! [agent] Stopped Successfully") + return err +} + +// InitPlugins runs the Init function on plugins. +func (a *Agent) InitPlugins() error { + for _, input := range a.Config.Inputs { + // Share the snmp translator setting with plugins that need it. + if tp, ok := input.Input.(snmp.TranslatorPlugin); ok { + tp.SetTranslator(a.Config.Agent.SnmpTranslator) + } + err := input.Init() + if err != nil { + return fmt.Errorf("could not initialize input %s: %w", input.LogName(), err) + } + } + for _, processor := range a.Config.Processors { + err := processor.Init() + if err != nil { + return fmt.Errorf("could not initialize processor %s: %w", processor.LogName(), err) + } + } + for _, aggregator := range a.Config.Aggregators { + err := aggregator.Init() + if err != nil { + return fmt.Errorf("could not initialize aggregator %s: %w", aggregator.LogName(), err) + } + } + if !*a.Config.Agent.SkipProcessorsAfterAggregators { + for _, processor := range a.Config.AggProcessors { + err := processor.Init() + if err != nil { + return fmt.Errorf("could not initialize processor %s: %w", processor.LogName(), err) + } + } + } + for _, output := range a.Config.Outputs { + err := output.Init() + if err != nil { + return fmt.Errorf("could not initialize output %s: %w", output.LogName(), err) + } + } + return nil +} + +// initPersister initializes the persister and registers the plugins. +func (a *Agent) initPersister() error { + if err := a.Config.Persister.Init(); err != nil { + return err + } + + for _, input := range a.Config.Inputs { + plugin, ok := input.Input.(telegraf.StatefulPlugin) + if !ok { + continue + } + + name := input.LogName() + id := input.ID() + if err := a.Config.Persister.Register(id, plugin); err != nil { + return fmt.Errorf("could not register input %s: %w", name, err) + } + } + + for _, processor := range a.Config.Processors { + var plugin telegraf.StatefulPlugin + if p, ok := processor.Processor.(processors.HasUnwrap); ok { + plugin, ok = p.Unwrap().(telegraf.StatefulPlugin) + if !ok { + continue + } + } else { + plugin, ok = processor.Processor.(telegraf.StatefulPlugin) + if !ok { + continue + } + } + + name := processor.LogName() + id := processor.ID() + if err := a.Config.Persister.Register(id, plugin); err != nil { + return fmt.Errorf("could not register processor %s: %w", name, err) + } + } + + for _, aggregator := range a.Config.Aggregators { + plugin, ok := aggregator.Aggregator.(telegraf.StatefulPlugin) + if !ok { + continue + } + + name := aggregator.LogName() + id := aggregator.ID() + if err := a.Config.Persister.Register(id, plugin); err != nil { + return fmt.Errorf("could not register aggregator %s: %w", name, err) + } + } + + for _, processor := range a.Config.AggProcessors { + plugin, ok := processor.Processor.(telegraf.StatefulPlugin) + if !ok { + continue + } + + name := processor.LogName() + id := processor.ID() + if err := a.Config.Persister.Register(id, plugin); err != nil { + return fmt.Errorf("could not register aggregating processor %s: %w", name, err) + } + } + + for _, output := range a.Config.Outputs { + plugin, ok := output.Output.(telegraf.StatefulPlugin) + if !ok { + continue + } + + name := output.LogName() + id := output.ID() + if err := a.Config.Persister.Register(id, plugin); err != nil { + return fmt.Errorf("could not register output %s: %w", name, err) + } + } + + return nil +} + +func (*Agent) startInputs(dst chan<- telegraf.Metric, inputs []*models.RunningInput) (*inputUnit, error) { + log.Printf("D! [agent] Starting service inputs") + + unit := &inputUnit{ + dst: dst, + } + + for _, input := range inputs { + // Service input plugins are not normally subject to timestamp + // rounding except for when precision is set on the input plugin. + // + // This only applies to the accumulator passed to Start(), the + // Gather() accumulator does apply rounding according to the + // precision and interval agent/plugin settings. + var interval time.Duration + var precision time.Duration + if input.Config.Precision != 0 { + precision = input.Config.Precision + } + + acc := NewAccumulator(input, dst) + acc.SetPrecision(getPrecision(precision, interval)) + + if err := input.Start(acc); err != nil { + // If the model tells us to remove the plugin we do so without error + var fatalErr *internal.FatalError + if errors.As(err, &fatalErr) { + log.Printf("I! [agent] Failed to start %s, shutting down plugin: %s", input.LogName(), err) + continue + } + + stopRunningInputs(unit.inputs) + + return nil, fmt.Errorf("starting input %s: %w", input.LogName(), err) + } + if err := input.Probe(); err != nil { + // Probe failures are non-fatal to the agent but should only remove the plugin + log.Printf("I! [agent] Failed to probe %s, shutting down plugin: %s", input.LogName(), err) + input.Stop() + continue + } + unit.inputs = append(unit.inputs, input) + } + + return unit, nil +} + +// runInputs starts and triggers the periodic gather for Inputs. +// +// When the context is done the timers are stopped and this function returns +// after all ongoing Gather calls complete. +func (a *Agent) runInputs( + ctx context.Context, + startTime time.Time, + unit *inputUnit, +) { + var wg sync.WaitGroup + tickers := make([]Ticker, 0, len(unit.inputs)) + for _, input := range unit.inputs { + // Overwrite agent interval if this plugin has its own. + interval := time.Duration(a.Config.Agent.Interval) + if input.Config.Interval != 0 { + interval = input.Config.Interval + } + + // Overwrite agent precision if this plugin has its own. + precision := time.Duration(a.Config.Agent.Precision) + if input.Config.Precision != 0 { + precision = input.Config.Precision + } + + // Overwrite agent collection_jitter if this plugin has its own. + jitter := time.Duration(a.Config.Agent.CollectionJitter) + if input.Config.CollectionJitter != 0 { + jitter = input.Config.CollectionJitter + } + + // Overwrite agent collection_offset if this plugin has its own. + offset := time.Duration(a.Config.Agent.CollectionOffset) + if input.Config.CollectionOffset != 0 { + offset = input.Config.CollectionOffset + } + + var ticker Ticker + if a.Config.Agent.RoundInterval { + ticker = NewAlignedTicker(startTime, interval, jitter, offset) + } else { + ticker = NewUnalignedTicker(interval, jitter, offset) + } + tickers = append(tickers, ticker) + + acc := NewAccumulator(input, unit.dst) + acc.SetPrecision(getPrecision(precision, interval)) + + wg.Add(1) + go func(input *models.RunningInput) { + defer wg.Done() + a.gatherLoop(ctx, acc, input, ticker, interval) + }(input) + } + defer stopTickers(tickers) + wg.Wait() + + log.Printf("D! [agent] Stopping service inputs") + stopRunningInputs(unit.inputs) + + close(unit.dst) + log.Printf("D! [agent] Input channel closed") +} + +// testStartInputs is a variation of startInputs for use in --test and --once mode. +// It differs by logging Start errors and returning only plugins successfully started. +func (*Agent) testStartInputs(dst chan<- telegraf.Metric, inputs []*models.RunningInput) *inputUnit { + log.Printf("D! [agent] Starting service inputs") + + unit := &inputUnit{ + dst: dst, + } + + for _, input := range inputs { + // Service input plugins are not subject to timestamp rounding. + // This only applies to the accumulator passed to Start(), the + // Gather() accumulator does apply rounding according to the + // precision agent setting. + acc := NewAccumulator(input, dst) + acc.SetPrecision(time.Nanosecond) + + if err := input.Start(acc); err != nil { + log.Printf("E! [agent] Starting input %s: %v", input.LogName(), err) + continue + } + + unit.inputs = append(unit.inputs, input) + } + + return unit +} + +// testRunInputs is a variation of runInputs for use in --test and --once mode. +// Instead of using a ticker to run the inputs they are called once immediately. +func (a *Agent) testRunInputs( + ctx context.Context, + wait time.Duration, + unit *inputUnit, +) { + var wg sync.WaitGroup + + nul := make(chan telegraf.Metric) + go func() { + //nolint:revive // empty block needed here + for range nul { + } + }() + + for _, input := range unit.inputs { + wg.Add(1) + go func(input *models.RunningInput) { + defer wg.Done() + + // Overwrite agent interval if this plugin has its own. + interval := time.Duration(a.Config.Agent.Interval) + if input.Config.Interval != 0 { + interval = input.Config.Interval + } + + // Overwrite agent precision if this plugin has its own. + precision := time.Duration(a.Config.Agent.Precision) + if input.Config.Precision != 0 { + precision = input.Config.Precision + } + + // Run plugins that require multiple gathers to calculate rate + // and delta metrics twice. + switch input.Config.Name { + case "cpu", "mongodb", "procstat": + nulAcc := NewAccumulator(input, nul) + nulAcc.SetPrecision(getPrecision(precision, interval)) + if err := input.Input.Gather(nulAcc); err != nil { + nulAcc.AddError(err) + } + + time.Sleep(500 * time.Millisecond) + } + + acc := NewAccumulator(input, unit.dst) + acc.SetPrecision(getPrecision(precision, interval)) + + if err := input.Input.Gather(acc); err != nil { + acc.AddError(err) + } + }(input) + } + wg.Wait() + + if err := internal.SleepContext(ctx, wait); err != nil { + log.Printf("E! [agent] SleepContext finished with: %v", err) + } + + log.Printf("D! [agent] Stopping service inputs") + stopRunningInputs(unit.inputs) + + close(unit.dst) + log.Printf("D! [agent] Input channel closed") +} + +// stopRunningInputs stops all service inputs. +func stopRunningInputs(inputs []*models.RunningInput) { + for _, input := range inputs { + input.Stop() + } +} + +// stopRunningOutputs stops all running outputs. +func stopRunningOutputs(outputs []*models.RunningOutput) { + for _, output := range outputs { + output.Close() + } +} + +// gather runs an input's gather function periodically until the context is +// done. +func (a *Agent) gatherLoop( + ctx context.Context, + acc telegraf.Accumulator, + input *models.RunningInput, + ticker Ticker, + interval time.Duration, +) { + for { + select { + case <-ticker.Elapsed(): + err := a.gatherOnce(acc, input, ticker, interval) + if err != nil { + acc.AddError(err) + } + case <-ctx.Done(): + return + } + } +} + +// gatherOnce runs the input's Gather function once, logging a warning each interval it fails to complete before. +func (*Agent) gatherOnce(acc telegraf.Accumulator, input *models.RunningInput, ticker Ticker, interval time.Duration) error { + done := make(chan error) + go func() { + defer panicRecover(input) + done <- input.Gather(acc) + }() + + // Only warn after interval seconds, even if the interval is started late. + // Intervals can start late if the previous interval went over or due to + // clock changes. + slowWarning := time.NewTicker(interval) + defer slowWarning.Stop() + + for { + select { + case err := <-done: + return err + case <-slowWarning.C: + log.Printf("W! [%s] Collection took longer than expected; not complete after interval of %s", + input.LogName(), interval) + input.IncrGatherTimeouts() + case <-ticker.Elapsed(): + log.Printf("D! [%s] Previous collection has not completed; scheduled collection skipped", + input.LogName()) + } + } +} + +// startProcessors sets up the processor chain and calls Start on all processors. If an error occurs any started processors are Stopped. +func (*Agent) startProcessors(dst chan<- telegraf.Metric, runningProcessors models.RunningProcessors) (chan<- telegraf.Metric, []*processorUnit, error) { + var src chan telegraf.Metric + units := make([]*processorUnit, 0, len(runningProcessors)) + // The processor chain is constructed from the output side starting from + // the output(s) and walking the way back to the input(s). However, the + // processor-list is sorted by order and/or by appearance in the config, + // i.e. in input-to-output direction. Therefore, reverse the processor list + // to reflect the order/definition order in the processing chain. + for i := len(runningProcessors) - 1; i >= 0; i-- { + processor := runningProcessors[i] + + src = make(chan telegraf.Metric, 100) + acc := NewAccumulator(processor, dst) + + err := processor.Start(acc) + if err != nil { + for _, u := range units { + u.processor.Stop() + close(u.dst) + } + return nil, nil, fmt.Errorf("starting processor %s: %w", processor.LogName(), err) + } + + units = append(units, &processorUnit{ + src: src, + dst: dst, + processor: processor, + }) + + dst = src + } + + return src, units, nil +} + +// runProcessors begins processing metrics and runs until the source channel is closed and all metrics have been written. +func (*Agent) runProcessors(units []*processorUnit) { + var wg sync.WaitGroup + for _, unit := range units { + wg.Add(1) + go func(unit *processorUnit) { + defer wg.Done() + + acc := NewAccumulator(unit.processor, unit.dst) + for m := range unit.src { + if err := unit.processor.Add(m, acc); err != nil { + acc.AddError(err) + m.Drop() + } + } + unit.processor.Stop() + close(unit.dst) + log.Printf("D! [agent] Processor channel closed") + }(unit) + } + wg.Wait() +} + +// startAggregators sets up the aggregator unit and returns the source channel. +func (*Agent) startAggregators(aggC, outputC chan<- telegraf.Metric, aggregators []*models.RunningAggregator) (chan<- telegraf.Metric, *aggregatorUnit) { + src := make(chan telegraf.Metric, 100) + unit := &aggregatorUnit{ + src: src, + aggC: aggC, + outputC: outputC, + aggregators: aggregators, + } + return src, unit +} + +// runAggregators beings aggregating metrics and runs until the source channel +// is closed and all metrics have been written. +func (a *Agent) runAggregators( + startTime time.Time, + unit *aggregatorUnit, +) { + ctx, cancel := context.WithCancel(context.Background()) + + // Before calling Add, initialize the aggregation window. This ensures + // that any metric created after start time will be aggregated. + for _, agg := range a.Config.Aggregators { + since, until := updateWindow(startTime, a.Config.Agent.RoundInterval, agg.Period()) + agg.UpdateWindow(since, until) + } + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + for metric := range unit.src { + var dropOriginal bool + for _, agg := range a.Config.Aggregators { + if ok := agg.Add(metric); ok { + dropOriginal = true + } + } + + if !dropOriginal { + unit.outputC <- metric // keep original. + } else { + metric.Drop() + } + } + cancel() + }() + + for _, agg := range a.Config.Aggregators { + wg.Add(1) + go func(agg *models.RunningAggregator) { + defer wg.Done() + + interval := time.Duration(a.Config.Agent.Interval) + precision := time.Duration(a.Config.Agent.Precision) + + acc := NewAccumulator(agg, unit.aggC) + acc.SetPrecision(getPrecision(precision, interval)) + a.push(ctx, agg, acc) + }(agg) + } + + wg.Wait() + + // In the case that there are no processors, both aggC and outputC are the + // same channel. If there are processors, we close the aggC and the + // processor chain will close the outputC when it finishes processing. + close(unit.aggC) + log.Printf("D! [agent] Aggregator channel closed") +} + +func updateWindow(start time.Time, roundInterval bool, period time.Duration) (since, until time.Time) { + if roundInterval { + until = internal.AlignTime(start, period) + if until.Equal(start) { + until = internal.AlignTime(start.Add(time.Nanosecond), period) + } + } else { + until = start.Add(period) + } + + since = until.Add(-period) + + return since, until +} + +// push runs the push for a single aggregator every period. +func (*Agent) push(ctx context.Context, aggregator *models.RunningAggregator, acc telegraf.Accumulator) { + for { + // Ensures that Push will be called for each period, even if it has + // already elapsed before this function is called. This is guaranteed + // because so long as only Push updates the EndPeriod. This method + // also avoids drift by not using a ticker. + until := time.Until(aggregator.EndPeriod()) + + select { + case <-time.After(until): + aggregator.Push(acc) + case <-ctx.Done(): + aggregator.Push(acc) + return + } + } +} + +// startOutputs calls Connect on all outputs and returns the source channel. +// If an error occurs calling Connect, all started plugins have Close called. +func (a *Agent) startOutputs( + ctx context.Context, + outputs []*models.RunningOutput, +) (chan<- telegraf.Metric, *outputUnit, error) { + src := make(chan telegraf.Metric, 100) + unit := &outputUnit{src: src} + for _, output := range outputs { + if err := a.connectOutput(ctx, output); err != nil { + var fatalErr *internal.FatalError + if errors.As(err, &fatalErr) { + // If the model tells us to remove the plugin we do so without error + log.Printf("I! [agent] Failed to connect to [%s], error was %q; shutting down plugin...", output.LogName(), err) + output.Close() + continue + } + + for _, unitOutput := range unit.outputs { + unitOutput.Close() + } + return nil, nil, fmt.Errorf("connecting output %s: %w", output.LogName(), err) + } + + unit.outputs = append(unit.outputs, output) + } + + return src, unit, nil +} + +// connectOutput connects to all outputs. +func (*Agent) connectOutput(ctx context.Context, output *models.RunningOutput) error { + log.Printf("D! [agent] Attempting connection to [%s]", output.LogName()) + if err := output.Connect(); err != nil { + log.Printf("E! [agent] Failed to connect to [%s], retrying in 15s, error was %q", output.LogName(), err) + + if err := internal.SleepContext(ctx, 15*time.Second); err != nil { + return err + } + + if err = output.Connect(); err != nil { + return fmt.Errorf("error connecting to output %q: %w", output.LogName(), err) + } + } + log.Printf("D! [agent] Successfully connected to %s", output.LogName()) + return nil +} + +// runOutputs begins processing metrics and returns until the source channel is +// closed and all metrics have been written. On shutdown metrics will be +// written one last time and dropped if unsuccessful. +func (a *Agent) runOutputs( + unit *outputUnit, +) { + var wg sync.WaitGroup + + // Start flush loop + interval := time.Duration(a.Config.Agent.FlushInterval) + jitter := time.Duration(a.Config.Agent.FlushJitter) + + ctx, cancel := context.WithCancel(context.Background()) + + for _, output := range unit.outputs { + interval := interval + // Overwrite agent flush_interval if this plugin has its own. + if output.Config.FlushInterval != 0 { + interval = output.Config.FlushInterval + } + + jitter := jitter + // Overwrite agent flush_jitter if this plugin has its own. + if output.Config.FlushJitter != 0 { + jitter = output.Config.FlushJitter + } + + wg.Add(1) + go func(output *models.RunningOutput) { + defer wg.Done() + + ticker := NewRollingTicker(interval, jitter) + defer ticker.Stop() + + a.flushLoop(ctx, output, ticker) + }(output) + } + + for metric := range unit.src { + for i, output := range unit.outputs { + if i == len(unit.outputs)-1 { + output.AddMetricNoCopy(metric) + } else { + output.AddMetric(metric) + } + } + } + + log.Println("I! [agent] Hang on, flushing any cached metrics before shutdown") + cancel() + wg.Wait() + + log.Println("I! [agent] Stopping running outputs") + stopRunningOutputs(unit.outputs) +} + +// flushLoop runs an output's flush function periodically until the context is +// done. +func (a *Agent) flushLoop( + ctx context.Context, + output *models.RunningOutput, + ticker Ticker, +) { + logError := func(err error) { + if err != nil { + log.Printf("E! [agent] Error writing to %s: %v", output.LogName(), err) + } + } + + // watch for flush requests + flushRequested := make(chan os.Signal, 1) + watchForFlushSignal(flushRequested) + defer stopListeningForFlushSignal(flushRequested) + + for { + // Favor shutdown over other methods. + select { + case <-ctx.Done(): + logError(a.flushOnce(output, ticker, output.Write)) + return + default: + } + + select { + case <-ctx.Done(): + logError(a.flushOnce(output, ticker, output.Write)) + return + case <-ticker.Elapsed(): + logError(a.flushOnce(output, ticker, output.Write)) + case <-flushRequested: + logError(a.flushOnce(output, ticker, output.Write)) + case <-output.BatchReady: + logError(a.flushBatch(output, output.WriteBatch)) + } + } +} + +// flushOnce runs the output's Write function once, logging a warning each interval it fails to complete before the flush interval elapses. +func (*Agent) flushOnce(output *models.RunningOutput, ticker Ticker, writeFunc func() error) error { + done := make(chan error) + go func() { + done <- writeFunc() + }() + + for { + select { + case err := <-done: + output.LogBufferStatus() + return err + case <-ticker.Elapsed(): + log.Printf("W! [agent] [%q] did not complete within its flush interval", + output.LogName()) + output.LogBufferStatus() + } + } +} + +// flushBatch runs the output's Write function once Unlike flushOnce the interval elapsing is not considered during these flushes. +func (*Agent) flushBatch(output *models.RunningOutput, writeFunc func() error) error { + err := writeFunc() + output.LogBufferStatus() + return err +} + +// Test runs the inputs, processors and aggregators for a single gather and +// writes the metrics to stdout. +func (a *Agent) Test(ctx context.Context, wait time.Duration) error { + src := make(chan telegraf.Metric, 100) + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + s := &influx.Serializer{SortFields: true, UintSupport: true} + for metric := range src { + octets, err := s.Serialize(metric) + if err == nil { + fmt.Print("> ", string(octets)) + } + metric.Reject() + } + }() + + err := a.runTest(ctx, wait, src) + if err != nil { + return err + } + + wg.Wait() + + if models.GlobalGatherErrors.Get() != 0 { + return fmt.Errorf("input plugins recorded %d errors", models.GlobalGatherErrors.Get()) + } + return nil +} + +// runTest runs the agent and performs a single gather sending output to the +// outputC. After gathering pauses for the wait duration to allow service +// inputs to run. +func (a *Agent) runTest(ctx context.Context, wait time.Duration, outputC chan<- telegraf.Metric) error { + // Set the default for processor skipping + if a.Config.Agent.SkipProcessorsAfterAggregators == nil { + msg := `The default value of 'skip_processors_after_aggregators' will change to 'true' with Telegraf v1.40.0! ` + msg += `If you need the current default behavior, please explicitly set the option to 'false'!` + log.Print("W! [agent] ", color.YellowString(msg)) + skipProcessorsAfterAggregators := false + a.Config.Agent.SkipProcessorsAfterAggregators = &skipProcessorsAfterAggregators + } + + log.Printf("D! [agent] Initializing plugins") + if err := a.InitPlugins(); err != nil { + return err + } + + startTime := time.Now() + + next := outputC + + var apu []*processorUnit + var au *aggregatorUnit + if len(a.Config.Aggregators) != 0 { + procC := next + if len(a.Config.AggProcessors) != 0 && !*a.Config.Agent.SkipProcessorsAfterAggregators { + var err error + procC, apu, err = a.startProcessors(next, a.Config.AggProcessors) + if err != nil { + return err + } + } + + next, au = a.startAggregators(procC, next, a.Config.Aggregators) + } + + var pu []*processorUnit + if len(a.Config.Processors) != 0 { + var err error + next, pu, err = a.startProcessors(next, a.Config.Processors) + if err != nil { + return err + } + } + + iu := a.testStartInputs(next, a.Config.Inputs) + + var wg sync.WaitGroup + if au != nil { + wg.Add(1) + go func() { + defer wg.Done() + a.runProcessors(apu) + }() + + wg.Add(1) + go func() { + defer wg.Done() + a.runAggregators(startTime, au) + }() + } + + if pu != nil { + wg.Add(1) + go func() { + defer wg.Done() + a.runProcessors(pu) + }() + } + + wg.Add(1) + go func() { + defer wg.Done() + a.testRunInputs(ctx, wait, iu) + }() + + wg.Wait() + + log.Printf("D! [agent] Stopped Successfully") + + return nil +} + +// Once runs the full agent for a single gather. +func (a *Agent) Once(ctx context.Context, wait time.Duration) error { + err := a.runOnce(ctx, wait) + if err != nil { + return err + } + + if models.GlobalGatherErrors.Get() != 0 { + return fmt.Errorf("input plugins recorded %d errors", models.GlobalGatherErrors.Get()) + } + + unsent := 0 + for _, output := range a.Config.Outputs { + unsent += output.BufferLength() + } + if unsent != 0 { + return fmt.Errorf("output plugins unable to send %d metrics", unsent) + } + return nil +} + +// runOnce runs the agent and performs a single gather sending output to the +// outputC. After gathering pauses for the wait duration to allow service +// inputs to run. +func (a *Agent) runOnce(ctx context.Context, wait time.Duration) error { + // Set the default for processor skipping + if a.Config.Agent.SkipProcessorsAfterAggregators == nil { + msg := `The default value of 'skip_processors_after_aggregators' will change to 'true' with Telegraf v1.40.0! ` + msg += `If you need the current default behavior, please explicitly set the option to 'false'!` + log.Print("W! [agent] ", color.YellowString(msg)) + skipProcessorsAfterAggregators := false + a.Config.Agent.SkipProcessorsAfterAggregators = &skipProcessorsAfterAggregators + } + + log.Printf("D! [agent] Initializing plugins") + if err := a.InitPlugins(); err != nil { + return err + } + + startTime := time.Now() + + log.Printf("D! [agent] Connecting outputs") + next, ou, err := a.startOutputs(ctx, a.Config.Outputs) + if err != nil { + return err + } + + var apu []*processorUnit + var au *aggregatorUnit + if len(a.Config.Aggregators) != 0 { + procC := next + if len(a.Config.AggProcessors) != 0 && !*a.Config.Agent.SkipProcessorsAfterAggregators { + procC, apu, err = a.startProcessors(next, a.Config.AggProcessors) + if err != nil { + return err + } + } + + next, au = a.startAggregators(procC, next, a.Config.Aggregators) + } + + var pu []*processorUnit + if len(a.Config.Processors) != 0 { + next, pu, err = a.startProcessors(next, a.Config.Processors) + if err != nil { + return err + } + } + + iu := a.testStartInputs(next, a.Config.Inputs) + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + a.runOutputs(ou) + }() + + if au != nil { + wg.Add(1) + go func() { + defer wg.Done() + a.runProcessors(apu) + }() + + wg.Add(1) + go func() { + defer wg.Done() + a.runAggregators(startTime, au) + }() + } + + if pu != nil { + wg.Add(1) + go func() { + defer wg.Done() + a.runProcessors(pu) + }() + } + + wg.Add(1) + go func() { + defer wg.Done() + a.testRunInputs(ctx, wait, iu) + }() + + wg.Wait() + + log.Printf("D! [agent] Stopped Successfully") + + return nil +} + +// Returns the rounding precision for metrics. +func getPrecision(precision, interval time.Duration) time.Duration { + if precision > 0 { + return precision + } + + switch { + case interval >= time.Second: + return time.Second + case interval >= time.Millisecond: + return time.Millisecond + case interval >= time.Microsecond: + return time.Microsecond + default: + return time.Nanosecond + } +} + +// panicRecover displays an error if an input panics. +func panicRecover(input *models.RunningInput) { + //nolint:revive // recover is called inside a deferred function + if err := recover(); err != nil { + trace := make([]byte, 2048) + runtime.Stack(trace, true) + log.Printf("E! FATAL: [%s] panicked: %s, Stack:\n%s", + input.LogName(), err, trace) + log.Fatalln("E! PLEASE REPORT THIS PANIC ON GITHUB with " + + "stack trace, configuration, and OS information: " + + "https://github.com/influxdata/telegraf/issues/new/choose") + } +} + +func stopTickers(tickers []Ticker) { + for _, ticker := range tickers { + ticker.Stop() + } +} diff --git a/agent/agent_posix.go b/agent/agent_posix.go new file mode 100644 index 0000000..24b8ce7 --- /dev/null +++ b/agent/agent_posix.go @@ -0,0 +1,19 @@ +//go:build !windows + +package agent + +import ( + "os" + "os/signal" + "syscall" +) + +const flushSignal = syscall.SIGUSR1 + +func watchForFlushSignal(flushRequested chan os.Signal) { + signal.Notify(flushRequested, flushSignal) +} + +func stopListeningForFlushSignal(flushRequested chan os.Signal) { + signal.Stop(flushRequested) +} diff --git a/agent/agent_test.go b/agent/agent_test.go new file mode 100644 index 0000000..607209e --- /dev/null +++ b/agent/agent_test.go @@ -0,0 +1,259 @@ +package agent + +import ( + "context" + "fmt" + "os" + "path/filepath" + "sync" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/require" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/config" + "github.com/influxdata/telegraf/models" + _ "github.com/influxdata/telegraf/plugins/aggregators/all" + _ "github.com/influxdata/telegraf/plugins/inputs/all" + _ "github.com/influxdata/telegraf/plugins/outputs/all" + "github.com/influxdata/telegraf/plugins/parsers/influx" + _ "github.com/influxdata/telegraf/plugins/processors/all" + "github.com/influxdata/telegraf/testutil" +) + +func TestAgent_OmitHostname(t *testing.T) { + c := config.NewConfig() + c.Agent.OmitHostname = true + _ = NewAgent(c) + require.NotContains(t, c.Tags, "host") +} + +func TestAgent_LoadPlugin(t *testing.T) { + c := config.NewConfig() + c.InputFilters = []string{"mysql"} + err := c.LoadConfig("../config/testdata/telegraf-agent.toml") + require.NoError(t, err) + a := NewAgent(c) + require.Len(t, a.Config.Inputs, 1) + + c = config.NewConfig() + c.InputFilters = []string{"foo"} + err = c.LoadConfig("../config/testdata/telegraf-agent.toml") + require.NoError(t, err) + a = NewAgent(c) + require.Empty(t, a.Config.Inputs) + + c = config.NewConfig() + c.InputFilters = []string{"mysql", "foo"} + err = c.LoadConfig("../config/testdata/telegraf-agent.toml") + require.NoError(t, err) + a = NewAgent(c) + require.Len(t, a.Config.Inputs, 1) + + c = config.NewConfig() + c.InputFilters = []string{"mysql", "redis"} + err = c.LoadConfig("../config/testdata/telegraf-agent.toml") + require.NoError(t, err) + a = NewAgent(c) + require.Len(t, a.Config.Inputs, 2) + + c = config.NewConfig() + c.InputFilters = []string{"mysql", "foo", "redis", "bar"} + err = c.LoadConfig("../config/testdata/telegraf-agent.toml") + require.NoError(t, err) + a = NewAgent(c) + require.Len(t, a.Config.Inputs, 2) +} + +func TestAgent_LoadOutput(t *testing.T) { + c := config.NewConfig() + c.OutputFilters = []string{"influxdb"} + err := c.LoadConfig("../config/testdata/telegraf-agent.toml") + require.NoError(t, err) + a := NewAgent(c) + require.Len(t, a.Config.Outputs, 2) + + c = config.NewConfig() + c.OutputFilters = []string{"kafka"} + err = c.LoadConfig("../config/testdata/telegraf-agent.toml") + require.NoError(t, err) + a = NewAgent(c) + require.Len(t, a.Config.Outputs, 1) + + c = config.NewConfig() + err = c.LoadConfig("../config/testdata/telegraf-agent.toml") + require.NoError(t, err) + a = NewAgent(c) + require.Len(t, a.Config.Outputs, 3) + + c = config.NewConfig() + c.OutputFilters = []string{"foo"} + err = c.LoadConfig("../config/testdata/telegraf-agent.toml") + require.NoError(t, err) + a = NewAgent(c) + require.Empty(t, a.Config.Outputs) + + c = config.NewConfig() + c.OutputFilters = []string{"influxdb", "foo"} + err = c.LoadConfig("../config/testdata/telegraf-agent.toml") + require.NoError(t, err) + a = NewAgent(c) + require.Len(t, a.Config.Outputs, 2) + + c = config.NewConfig() + c.OutputFilters = []string{"influxdb", "kafka"} + err = c.LoadConfig("../config/testdata/telegraf-agent.toml") + require.NoError(t, err) + require.Len(t, c.Outputs, 3) + a = NewAgent(c) + require.Len(t, a.Config.Outputs, 3) + + c = config.NewConfig() + c.OutputFilters = []string{"influxdb", "foo", "kafka", "bar"} + err = c.LoadConfig("../config/testdata/telegraf-agent.toml") + require.NoError(t, err) + a = NewAgent(c) + require.Len(t, a.Config.Outputs, 3) +} + +func TestWindow(t *testing.T) { + parse := func(s string) time.Time { + tm, err := time.Parse(time.RFC3339, s) + if err != nil { + panic(err) + } + return tm + } + + tests := []struct { + name string + start time.Time + roundInterval bool + period time.Duration + since time.Time + until time.Time + }{ + { + name: "round with exact alignment", + start: parse("2018-03-27T00:00:00Z"), + roundInterval: true, + period: 30 * time.Second, + since: parse("2018-03-27T00:00:00Z"), + until: parse("2018-03-27T00:00:30Z"), + }, + { + name: "round with alignment needed", + start: parse("2018-03-27T00:00:05Z"), + roundInterval: true, + period: 30 * time.Second, + since: parse("2018-03-27T00:00:00Z"), + until: parse("2018-03-27T00:00:30Z"), + }, + { + name: "no round with exact alignment", + start: parse("2018-03-27T00:00:00Z"), + roundInterval: false, + period: 30 * time.Second, + since: parse("2018-03-27T00:00:00Z"), + until: parse("2018-03-27T00:00:30Z"), + }, + { + name: "no found with alignment needed", + start: parse("2018-03-27T00:00:05Z"), + roundInterval: false, + period: 30 * time.Second, + since: parse("2018-03-27T00:00:05Z"), + until: parse("2018-03-27T00:00:35Z"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + since, until := updateWindow(tt.start, tt.roundInterval, tt.period) + require.Equal(t, tt.since, since, "since") + require.Equal(t, tt.until, until, "until") + }) + } +} + +func TestCases(t *testing.T) { + // Get all directories in testcases + folders, err := os.ReadDir("testcases") + require.NoError(t, err) + + // Make sure tests contains data + require.NotEmpty(t, folders) + + for _, f := range folders { + // Only handle folders + if !f.IsDir() { + continue + } + + fname := f.Name() + testdataPath := filepath.Join("testcases", fname) + configFilename := filepath.Join(testdataPath, "telegraf.conf") + expectedFilename := filepath.Join(testdataPath, "expected.out") + + t.Run(fname, func(t *testing.T) { + // Get parser to parse input and expected output + parser := &influx.Parser{} + require.NoError(t, parser.Init()) + + expected, err := testutil.ParseMetricsFromFile(expectedFilename, parser) + require.NoError(t, err) + require.NotEmpty(t, expected) + + // Load the config and inject the mock output to be able to verify + // the resulting metrics + cfg := config.NewConfig() + require.NoError(t, cfg.LoadAll(configFilename)) + require.Empty(t, cfg.Outputs, "No output(s) allowed in the config!") + + // Setup the agent and run the agent in "once" mode + agent := NewAgent(cfg) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) + defer cancel() + actual, err := collect(ctx, agent, 0) + require.NoError(t, err) + + // Process expected metrics and compare with resulting metrics + options := []cmp.Option{ + testutil.IgnoreTags("host"), + testutil.IgnoreTime(), + } + testutil.RequireMetricsEqual(t, expected, actual, options...) + }) + } +} + +// Implement a "test-mode" like call but collect the metrics +func collect(ctx context.Context, a *Agent, wait time.Duration) ([]telegraf.Metric, error) { + var received []telegraf.Metric + var mu sync.Mutex + + src := make(chan telegraf.Metric, 100) + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + for m := range src { + mu.Lock() + received = append(received, m) + mu.Unlock() + m.Reject() + } + }() + + if err := a.runTest(ctx, wait, src); err != nil { + return nil, err + } + wg.Wait() + + if models.GlobalGatherErrors.Get() != 0 { + return received, fmt.Errorf("input plugins recorded %d errors", models.GlobalGatherErrors.Get()) + } + return received, nil +} diff --git a/agent/agent_windows.go b/agent/agent_windows.go new file mode 100644 index 0000000..c1a8359 --- /dev/null +++ b/agent/agent_windows.go @@ -0,0 +1,13 @@ +//go:build windows + +package agent + +import "os" + +func watchForFlushSignal(_ chan os.Signal) { + // not supported +} + +func stopListeningForFlushSignal(_ chan os.Signal) { + // not supported +} diff --git a/agent/testcases/aggregators-rerun-processors/expected.out b/agent/testcases/aggregators-rerun-processors/expected.out new file mode 100644 index 0000000..ea610c4 --- /dev/null +++ b/agent/testcases/aggregators-rerun-processors/expected.out @@ -0,0 +1,2 @@ +metric value=420 +metric value_min=4200,value_max=4200 diff --git a/agent/testcases/aggregators-rerun-processors/input.influx b/agent/testcases/aggregators-rerun-processors/input.influx new file mode 100644 index 0000000..194bd02 --- /dev/null +++ b/agent/testcases/aggregators-rerun-processors/input.influx @@ -0,0 +1 @@ +metric value=42.0 diff --git a/agent/testcases/aggregators-rerun-processors/telegraf.conf b/agent/testcases/aggregators-rerun-processors/telegraf.conf new file mode 100644 index 0000000..2cc749b --- /dev/null +++ b/agent/testcases/aggregators-rerun-processors/telegraf.conf @@ -0,0 +1,22 @@ +# Test for not skipping processors after running aggregators +[agent] + omit_hostname = true + skip_processors_after_aggregators = false + +[[inputs.file]] + files = ["testcases/aggregators-rerun-processors/input.influx"] + data_format = "influx" + +[[processors.starlark]] + source = ''' +def apply(metric): + for k, v in metric.fields.items(): + if type(v) == "float": + metric.fields[k] = v * 10 + return metric +''' + +[[aggregators.minmax]] + period = "1s" + drop_original = false + diff --git a/agent/testcases/aggregators-skip-processors/expected.out b/agent/testcases/aggregators-skip-processors/expected.out new file mode 100644 index 0000000..7a006b8 --- /dev/null +++ b/agent/testcases/aggregators-skip-processors/expected.out @@ -0,0 +1,2 @@ +metric value=420 +metric value_min=420,value_max=420 diff --git a/agent/testcases/aggregators-skip-processors/input.influx b/agent/testcases/aggregators-skip-processors/input.influx new file mode 100644 index 0000000..194bd02 --- /dev/null +++ b/agent/testcases/aggregators-skip-processors/input.influx @@ -0,0 +1 @@ +metric value=42.0 diff --git a/agent/testcases/aggregators-skip-processors/telegraf.conf b/agent/testcases/aggregators-skip-processors/telegraf.conf new file mode 100644 index 0000000..8dd2f57 --- /dev/null +++ b/agent/testcases/aggregators-skip-processors/telegraf.conf @@ -0,0 +1,22 @@ +# Test for skipping processors after running aggregators +[agent] + omit_hostname = true + skip_processors_after_aggregators = true + +[[inputs.file]] + files = ["testcases/aggregators-skip-processors/input.influx"] + data_format = "influx" + +[[processors.starlark]] + source = ''' +def apply(metric): + for k, v in metric.fields.items(): + if type(v) == "float": + metric.fields[k] = v * 10 + return metric +''' + +[[aggregators.minmax]] + period = "1s" + drop_original = false + diff --git a/agent/testcases/processor-order-appearance/expected.out b/agent/testcases/processor-order-appearance/expected.out new file mode 100644 index 0000000..6f41ac3 --- /dev/null +++ b/agent/testcases/processor-order-appearance/expected.out @@ -0,0 +1,2 @@ +new_metric_from_starlark,foo=bar baz=42i,timestamp="2023-07-13T12:53:54.197709713Z" 1689252834197709713 +old_metric_from_mock,mood=good value=23i,timestamp="2023-07-13T13:10:34Z" 1689253834000000000 diff --git a/agent/testcases/processor-order-appearance/input.influx b/agent/testcases/processor-order-appearance/input.influx new file mode 100644 index 0000000..2bcf853 --- /dev/null +++ b/agent/testcases/processor-order-appearance/input.influx @@ -0,0 +1 @@ +old_metric_from_mock,mood=good value=23i 1689253834000000000 diff --git a/agent/testcases/processor-order-appearance/telegraf.conf b/agent/testcases/processor-order-appearance/telegraf.conf new file mode 100644 index 0000000..6e48584 --- /dev/null +++ b/agent/testcases/processor-order-appearance/telegraf.conf @@ -0,0 +1,26 @@ +# Test for using the appearance order in the file for processor order +[[inputs.file]] + files = ["testcases/processor-order-appearance/input.influx"] + data_format = "influx" + +[[processors.starlark]] + source = ''' +def apply(metric): + metrics = [] + + m = Metric("new_metric_from_starlark") + m.tags["foo"] = "bar" + m.fields["baz"] = 42 + m.time = 1689252834197709713 + metrics.append(m) + metrics.append(metric) + + return metrics +''' + +[[processors.date]] + field_key = "timestamp" + date_format = "2006-01-02T15:04:05.999999999Z" + timezone = "UTC" + + diff --git a/agent/testcases/processor-order-explicit/expected.out b/agent/testcases/processor-order-explicit/expected.out new file mode 100644 index 0000000..6f41ac3 --- /dev/null +++ b/agent/testcases/processor-order-explicit/expected.out @@ -0,0 +1,2 @@ +new_metric_from_starlark,foo=bar baz=42i,timestamp="2023-07-13T12:53:54.197709713Z" 1689252834197709713 +old_metric_from_mock,mood=good value=23i,timestamp="2023-07-13T13:10:34Z" 1689253834000000000 diff --git a/agent/testcases/processor-order-explicit/input.influx b/agent/testcases/processor-order-explicit/input.influx new file mode 100644 index 0000000..2bcf853 --- /dev/null +++ b/agent/testcases/processor-order-explicit/input.influx @@ -0,0 +1 @@ +old_metric_from_mock,mood=good value=23i 1689253834000000000 diff --git a/agent/testcases/processor-order-explicit/telegraf.conf b/agent/testcases/processor-order-explicit/telegraf.conf new file mode 100644 index 0000000..3729221 --- /dev/null +++ b/agent/testcases/processor-order-explicit/telegraf.conf @@ -0,0 +1,27 @@ +# Test for specifying an explicit processor order +[[inputs.file]] + files = ["testcases/processor-order-explicit/input.influx"] + data_format = "influx" + + +[[processors.date]] + field_key = "timestamp" + date_format = "2006-01-02T15:04:05.999999999Z" + timezone = "UTC" + order = 2 + +[[processors.starlark]] + source = ''' +def apply(metric): + metrics = [] + + m = Metric("new_metric_from_starlark") + m.tags["foo"] = "bar" + m.fields["baz"] = 42 + m.time = 1689252834197709713 + metrics.append(m) + metrics.append(metric) + + return metrics +''' + order = 1 diff --git a/agent/testcases/processor-order-mixed/expected.out b/agent/testcases/processor-order-mixed/expected.out new file mode 100644 index 0000000..6f41ac3 --- /dev/null +++ b/agent/testcases/processor-order-mixed/expected.out @@ -0,0 +1,2 @@ +new_metric_from_starlark,foo=bar baz=42i,timestamp="2023-07-13T12:53:54.197709713Z" 1689252834197709713 +old_metric_from_mock,mood=good value=23i,timestamp="2023-07-13T13:10:34Z" 1689253834000000000 diff --git a/agent/testcases/processor-order-mixed/input.influx b/agent/testcases/processor-order-mixed/input.influx new file mode 100644 index 0000000..2bcf853 --- /dev/null +++ b/agent/testcases/processor-order-mixed/input.influx @@ -0,0 +1 @@ +old_metric_from_mock,mood=good value=23i 1689253834000000000 diff --git a/agent/testcases/processor-order-mixed/telegraf.conf b/agent/testcases/processor-order-mixed/telegraf.conf new file mode 100644 index 0000000..5be9ba1 --- /dev/null +++ b/agent/testcases/processor-order-mixed/telegraf.conf @@ -0,0 +1,25 @@ +# Test for using the appearance order in the file for processor order +[[inputs.file]] + files = ["testcases/processor-order-appearance/input.influx"] + data_format = "influx" + +[[processors.starlark]] + source = ''' +def apply(metric): + metrics = [] + + m = Metric("new_metric_from_starlark") + m.tags["foo"] = "bar" + m.fields["baz"] = 42 + m.time = 1689252834197709713 + metrics.append(m) + metrics.append(metric) + + return metrics +''' + +[[processors.date]] + field_key = "timestamp" + date_format = "2006-01-02T15:04:05.999999999Z" + timezone = "UTC" + order = 1 diff --git a/agent/testcases/processor-order-no-starlark/expected.out b/agent/testcases/processor-order-no-starlark/expected.out new file mode 100644 index 0000000..c06a4ce --- /dev/null +++ b/agent/testcases/processor-order-no-starlark/expected.out @@ -0,0 +1,2 @@ +new_metric_from_starlark,foo=bar baz=42i 1689252834197709713 +old_metric_from_mock,mood=good value=23i,timestamp="2023-07-13T13:10:34Z" 1689253834000000000 diff --git a/agent/testcases/processor-order-no-starlark/input.influx b/agent/testcases/processor-order-no-starlark/input.influx new file mode 100644 index 0000000..2bcf853 --- /dev/null +++ b/agent/testcases/processor-order-no-starlark/input.influx @@ -0,0 +1 @@ +old_metric_from_mock,mood=good value=23i 1689253834000000000 diff --git a/agent/testcases/processor-order-no-starlark/telegraf.conf b/agent/testcases/processor-order-no-starlark/telegraf.conf new file mode 100644 index 0000000..0eb2e43 --- /dev/null +++ b/agent/testcases/processor-order-no-starlark/telegraf.conf @@ -0,0 +1,26 @@ +# Test for using the appearance order in the file for processor order. +# This will not add the "timestamp" field as the starlark processor runs _after_ +# the date processor. +[[inputs.file]] + files = ["testcases/processor-order-no-starlark/input.influx"] + data_format = "influx" + +[[processors.date]] + field_key = "timestamp" + date_format = "2006-01-02T15:04:05.999999999Z" + timezone = "UTC" + +[[processors.starlark]] + source = ''' +def apply(metric): + metrics = [] + + m = Metric("new_metric_from_starlark") + m.tags["foo"] = "bar" + m.fields["baz"] = 42 + m.time = 1689252834197709713 + metrics.append(m) + metrics.append(metric) + + return metrics +''' diff --git a/agent/tick.go b/agent/tick.go new file mode 100644 index 0000000..f6f9e6f --- /dev/null +++ b/agent/tick.go @@ -0,0 +1,281 @@ +package agent + +import ( + "context" + "sync" + "time" + + "github.com/benbjohnson/clock" + + "github.com/influxdata/telegraf/internal" +) + +type Ticker interface { + Elapsed() <-chan time.Time + Stop() +} + +// AlignedTicker delivers ticks at aligned times plus an optional jitter. Each +// tick is realigned to avoid drift and handle changes to the system clock. +// +// The ticks may have an jitter duration applied to them as an random offset to +// the interval. However the overall pace of is that of the interval, so on +// average you will have one collection each interval. +// +// The first tick is emitted at the next alignment. +// +// Ticks are dropped for slow consumers. +// +// The implementation currently does not recalculate until the next tick with +// no maximum sleep, when using large intervals alignment is not corrected +// until the next tick. +type AlignedTicker struct { + interval time.Duration + jitter time.Duration + offset time.Duration + minInterval time.Duration + ch chan time.Time + cancel context.CancelFunc + wg sync.WaitGroup +} + +func NewAlignedTicker(now time.Time, interval, jitter, offset time.Duration) *AlignedTicker { + t := &AlignedTicker{ + interval: interval, + jitter: jitter, + offset: offset, + minInterval: interval / 100, + } + t.start(now, clock.New()) + return t +} + +func (t *AlignedTicker) start(now time.Time, clk clock.Clock) { + t.ch = make(chan time.Time, 1) + + ctx, cancel := context.WithCancel(context.Background()) + t.cancel = cancel + + d := t.next(now) + timer := clk.Timer(d) + + t.wg.Add(1) + go func() { + defer t.wg.Done() + t.run(ctx, timer) + }() +} + +func (t *AlignedTicker) next(now time.Time) time.Duration { + // Add minimum interval size to avoid scheduling an interval that is + // exceptionally short. This avoids an issue that can occur where the + // previous interval ends slightly early due to very minor clock changes. + next := now.Add(t.minInterval) + + next = internal.AlignTime(next, t.interval) + d := next.Sub(now) + if d == 0 { + d = t.interval + } + d += t.offset + d += internal.RandomDuration(t.jitter) + return d +} + +func (t *AlignedTicker) run(ctx context.Context, timer *clock.Timer) { + for { + select { + case <-ctx.Done(): + timer.Stop() + return + case now := <-timer.C: + select { + case t.ch <- now: + default: + } + + d := t.next(now) + timer.Reset(d) + } + } +} + +func (t *AlignedTicker) Elapsed() <-chan time.Time { + return t.ch +} + +func (t *AlignedTicker) Stop() { + t.cancel() + t.wg.Wait() +} + +// UnalignedTicker delivers ticks at regular but unaligned intervals. No +// effort is made to avoid drift. +// +// The ticks may have an jitter duration applied to them as an random offset to +// the interval. However the overall pace of is that of the interval, so on +// average you will have one collection each interval. +// +// The first tick is emitted immediately. +// +// Ticks are dropped for slow consumers. +type UnalignedTicker struct { + interval time.Duration + jitter time.Duration + offset time.Duration + ch chan time.Time + cancel context.CancelFunc + wg sync.WaitGroup +} + +func NewUnalignedTicker(interval, jitter, offset time.Duration) *UnalignedTicker { + t := &UnalignedTicker{ + interval: interval, + jitter: jitter, + offset: offset, + } + t.start(clock.New()) + return t +} + +func (t *UnalignedTicker) start(clk clock.Clock) { + t.ch = make(chan time.Time, 1) + ctx, cancel := context.WithCancel(context.Background()) + t.cancel = cancel + + ticker := clk.Ticker(t.interval) + if t.offset == 0 { + // Perform initial trigger to stay backward compatible + t.ch <- clk.Now() + } + + t.wg.Add(1) + go func() { + defer t.wg.Done() + t.run(ctx, ticker, clk) + }() +} + +func sleep(ctx context.Context, duration time.Duration, clk clock.Clock) error { + if duration == 0 { + return nil + } + + t := clk.Timer(duration) + select { + case <-t.C: + return nil + case <-ctx.Done(): + t.Stop() + return ctx.Err() + } +} + +func (t *UnalignedTicker) run(ctx context.Context, ticker *clock.Ticker, clk clock.Clock) { + for { + select { + case <-ctx.Done(): + ticker.Stop() + return + case <-ticker.C: + jitter := internal.RandomDuration(t.jitter) + err := sleep(ctx, t.offset+jitter, clk) + if err != nil { + ticker.Stop() + return + } + select { + case t.ch <- clk.Now(): + default: + } + } + } +} + +func (t *UnalignedTicker) InjectTick() { + t.ch <- time.Now() +} + +func (t *UnalignedTicker) Elapsed() <-chan time.Time { + return t.ch +} + +func (t *UnalignedTicker) Stop() { + t.cancel() + t.wg.Wait() +} + +// RollingTicker delivers ticks at regular but unaligned intervals. +// +// Because the next interval is scheduled based on the interval + jitter, you +// are guaranteed at least interval seconds without missing a tick and ticks +// will be evenly scheduled over time. +// +// On average you will have one collection each interval + (jitter/2). +// +// The first tick is emitted after interval+jitter seconds. +// +// Ticks are dropped for slow consumers. +type RollingTicker struct { + interval time.Duration + jitter time.Duration + ch chan time.Time + cancel context.CancelFunc + wg sync.WaitGroup +} + +func NewRollingTicker(interval, jitter time.Duration) *RollingTicker { + t := &RollingTicker{ + interval: interval, + jitter: jitter, + } + t.start(clock.New()) + return t +} + +func (t *RollingTicker) start(clk clock.Clock) { + t.ch = make(chan time.Time, 1) + + ctx, cancel := context.WithCancel(context.Background()) + t.cancel = cancel + + d := t.next() + timer := clk.Timer(d) + + t.wg.Add(1) + go func() { + defer t.wg.Done() + t.run(ctx, timer) + }() +} + +func (t *RollingTicker) next() time.Duration { + return t.interval + internal.RandomDuration(t.jitter) +} + +func (t *RollingTicker) run(ctx context.Context, timer *clock.Timer) { + for { + select { + case <-ctx.Done(): + timer.Stop() + return + case now := <-timer.C: + select { + case t.ch <- now: + default: + } + + d := t.next() + timer.Reset(d) + } + } +} + +func (t *RollingTicker) Elapsed() <-chan time.Time { + return t.ch +} + +func (t *RollingTicker) Stop() { + t.cancel() + t.wg.Wait() +} diff --git a/agent/tick_test.go b/agent/tick_test.go new file mode 100644 index 0000000..078d50b --- /dev/null +++ b/agent/tick_test.go @@ -0,0 +1,395 @@ +package agent + +import ( + "fmt" + "strings" + "testing" + "time" + + "github.com/benbjohnson/clock" + "github.com/stretchr/testify/require" +) + +func TestAlignedTicker(t *testing.T) { + interval := 10 * time.Second + jitter := 0 * time.Second + offset := 0 * time.Second + + clk := clock.NewMock() + since := clk.Now() + until := since.Add(60 * time.Second) + + ticker := &AlignedTicker{ + interval: interval, + jitter: jitter, + offset: offset, + minInterval: interval / 100, + } + ticker.start(since, clk) + defer ticker.Stop() + + expected := []time.Time{ + time.Unix(10, 0).UTC(), + time.Unix(20, 0).UTC(), + time.Unix(30, 0).UTC(), + time.Unix(40, 0).UTC(), + time.Unix(50, 0).UTC(), + time.Unix(60, 0).UTC(), + } + + actual := make([]time.Time, 0) + clk.Add(10 * time.Second) + for !clk.Now().After(until) { + tm := <-ticker.Elapsed() + actual = append(actual, tm.UTC()) + + clk.Add(10 * time.Second) + } + + require.Equal(t, expected, actual) +} + +func TestAlignedTickerJitter(t *testing.T) { + interval := 10 * time.Second + jitter := 5 * time.Second + offset := 0 * time.Second + + clk := clock.NewMock() + since := clk.Now() + until := since.Add(61 * time.Second) + + ticker := &AlignedTicker{ + interval: interval, + jitter: jitter, + offset: offset, + minInterval: interval / 100, + } + ticker.start(since, clk) + defer ticker.Stop() + + last := since + for !clk.Now().After(until) { + select { + case tm := <-ticker.Elapsed(): + dur := tm.Sub(last) + // 10s interval + 5s jitter + up to 1s late firing. + require.LessOrEqual(t, dur, 16*time.Second, "expected elapsed time to be less than 16 seconds, but was %s", dur) + require.GreaterOrEqual(t, dur, 5*time.Second, "expected elapsed time to be more than 5 seconds, but was %s", dur) + last = last.Add(interval) + default: + } + clk.Add(1 * time.Second) + } +} + +func TestAlignedTickerOffset(t *testing.T) { + interval := 10 * time.Second + jitter := 0 * time.Second + offset := 3 * time.Second + + clk := clock.NewMock() + since := clk.Now() + until := since.Add(61 * time.Second) + + ticker := &AlignedTicker{ + interval: interval, + jitter: jitter, + offset: offset, + minInterval: interval / 100, + } + ticker.start(since, clk) + defer ticker.Stop() + + expected := []time.Time{ + time.Unix(13, 0).UTC(), + time.Unix(23, 0).UTC(), + time.Unix(33, 0).UTC(), + time.Unix(43, 0).UTC(), + time.Unix(53, 0).UTC(), + } + + actual := make([]time.Time, 0) + clk.Add(10*time.Second + offset) + for !clk.Now().After(until) { + tm := <-ticker.Elapsed() + actual = append(actual, tm.UTC()) + clk.Add(10 * time.Second) + } + + require.Equal(t, expected, actual) +} + +func TestAlignedTickerMissedTick(t *testing.T) { + interval := 10 * time.Second + jitter := 0 * time.Second + offset := 0 * time.Second + + clk := clock.NewMock() + since := clk.Now() + + ticker := &AlignedTicker{ + interval: interval, + jitter: jitter, + offset: offset, + minInterval: interval / 100, + } + ticker.start(since, clk) + defer ticker.Stop() + + clk.Add(25 * time.Second) + tm := <-ticker.Elapsed() + require.Equal(t, time.Unix(10, 0).UTC(), tm.UTC()) + clk.Add(5 * time.Second) + tm = <-ticker.Elapsed() + require.Equal(t, time.Unix(30, 0).UTC(), tm.UTC()) +} + +func TestUnalignedTicker(t *testing.T) { + interval := 10 * time.Second + jitter := 0 * time.Second + offset := 0 * time.Second + + clk := clock.NewMock() + clk.Add(1 * time.Second) + since := clk.Now() + until := since.Add(60 * time.Second) + + ticker := &UnalignedTicker{ + interval: interval, + jitter: jitter, + offset: offset, + } + ticker.start(clk) + defer ticker.Stop() + + expected := []time.Time{ + time.Unix(1, 0).UTC(), + time.Unix(11, 0).UTC(), + time.Unix(21, 0).UTC(), + time.Unix(31, 0).UTC(), + time.Unix(41, 0).UTC(), + time.Unix(51, 0).UTC(), + time.Unix(61, 0).UTC(), + } + + actual := make([]time.Time, 0) + for !clk.Now().After(until) { + select { + case tm := <-ticker.Elapsed(): + actual = append(actual, tm.UTC()) + default: + } + clk.Add(10 * time.Second) + } + + require.Equal(t, expected, actual) +} + +func TestRollingTicker(t *testing.T) { + interval := 10 * time.Second + jitter := 0 * time.Second + offset := 0 * time.Second + + clk := clock.NewMock() + clk.Add(1 * time.Second) + since := clk.Now() + until := since.Add(60 * time.Second) + + ticker := &UnalignedTicker{ + interval: interval, + jitter: jitter, + offset: offset, + } + ticker.start(clk) + defer ticker.Stop() + + expected := []time.Time{ + time.Unix(1, 0).UTC(), + time.Unix(11, 0).UTC(), + time.Unix(21, 0).UTC(), + time.Unix(31, 0).UTC(), + time.Unix(41, 0).UTC(), + time.Unix(51, 0).UTC(), + time.Unix(61, 0).UTC(), + } + + actual := make([]time.Time, 0) + for !clk.Now().After(until) { + select { + case tm := <-ticker.Elapsed(): + actual = append(actual, tm.UTC()) + default: + } + clk.Add(10 * time.Second) + } + + require.Equal(t, expected, actual) +} + +// Simulates running the Ticker for an hour and displays stats about the +// operation. +func TestAlignedTickerDistribution(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + interval := 10 * time.Second + jitter := 5 * time.Second + offset := 0 * time.Second + + clk := clock.NewMock() + since := clk.Now() + + ticker := &AlignedTicker{ + interval: interval, + jitter: jitter, + offset: offset, + minInterval: interval / 100, + } + ticker.start(since, clk) + defer ticker.Stop() + dist := simulatedDist(ticker, clk) + printDist(dist) + require.Less(t, 350, dist.Count) + require.True(t, 9 < dist.Mean() && dist.Mean() < 11) +} + +func TestAlignedTickerDistributionWithOffset(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + interval := 10 * time.Second + jitter := 5 * time.Second + offset := 3 * time.Second + + clk := clock.NewMock() + since := clk.Now() + + ticker := &AlignedTicker{ + interval: interval, + jitter: jitter, + offset: offset, + minInterval: interval / 100, + } + ticker.start(since, clk) + defer ticker.Stop() + dist := simulatedDist(ticker, clk) + printDist(dist) + require.Less(t, 350, dist.Count) + require.True(t, 9 < dist.Mean() && dist.Mean() < 11) +} + +// Simulates running the Ticker for an hour and displays stats about the +// operation. +func TestUnalignedTickerDistribution(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + interval := 10 * time.Second + jitter := 5 * time.Second + offset := 0 * time.Second + + clk := clock.NewMock() + + ticker := &UnalignedTicker{ + interval: interval, + jitter: jitter, + offset: offset, + } + ticker.start(clk) + defer ticker.Stop() + dist := simulatedDist(ticker, clk) + printDist(dist) + require.Less(t, 350, dist.Count) + require.True(t, 9 < dist.Mean() && dist.Mean() < 11) +} + +func TestUnalignedTickerDistributionWithOffset(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + interval := 10 * time.Second + jitter := 5 * time.Second + offset := 3 * time.Second + + clk := clock.NewMock() + + ticker := &UnalignedTicker{ + interval: interval, + jitter: jitter, + offset: offset, + } + ticker.start(clk) + defer ticker.Stop() + dist := simulatedDist(ticker, clk) + printDist(dist) + require.Less(t, 350, dist.Count) + require.True(t, 9 < dist.Mean() && dist.Mean() < 11) +} + +// Simulates running the Ticker for an hour and displays stats about the +// operation. +func TestRollingTickerDistribution(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + interval := 10 * time.Second + jitter := 5 * time.Second + + clk := clock.NewMock() + + ticker := &RollingTicker{ + interval: interval, + jitter: jitter, + } + ticker.start(clk) + defer ticker.Stop() + dist := simulatedDist(ticker, clk) + printDist(dist) + require.Less(t, 275, dist.Count) + require.True(t, 12 < dist.Mean() && 13 > dist.Mean()) +} + +type Distribution struct { + Buckets [60]int + Count int + Waittime float64 +} + +func (d *Distribution) Mean() float64 { + return d.Waittime / float64(d.Count) +} + +func printDist(dist Distribution) { + for i, count := range dist.Buckets { + fmt.Printf("%2d %s\n", i, strings.Repeat("x", count)) + } + fmt.Printf("Average interval: %f\n", dist.Mean()) + fmt.Printf("Count: %d\n", dist.Count) +} + +func simulatedDist(ticker Ticker, clk *clock.Mock) Distribution { + since := clk.Now() + until := since.Add(1 * time.Hour) + + var dist Distribution + + last := clk.Now() + for !clk.Now().After(until) { + select { + case tm := <-ticker.Elapsed(): + dist.Buckets[tm.Second()]++ + dist.Count++ + dist.Waittime += tm.Sub(last).Seconds() + last = tm + default: + clk.Add(1 * time.Second) + } + } + + return dist +} diff --git a/aggregator.go b/aggregator.go new file mode 100644 index 0000000..f168b04 --- /dev/null +++ b/aggregator.go @@ -0,0 +1,18 @@ +package telegraf + +// Aggregator is an interface for implementing an Aggregator plugin. +// the RunningAggregator wraps this interface and guarantees that +// Add, Push, and Reset can not be called concurrently, so locking is not +// required when implementing an Aggregator plugin. +type Aggregator interface { + PluginDescriber + + // Add the metric to the aggregator. + Add(in Metric) + + // Push pushes the current aggregates to the accumulator. + Push(acc Accumulator) + + // Reset resets the aggregators caches and aggregates. + Reset() +} diff --git a/assets/GopherAndTiger.png b/assets/GopherAndTiger.png new file mode 100644 index 0000000000000000000000000000000000000000..d76a4242f8636902f78949e831a386d66ee1cbd3 GIT binary patch literal 74224 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�+lI9Xa*=($TKc%Yo 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 literal 0 HcmV?d00001 diff --git a/assets/TelegrafTigerSmall.png b/assets/TelegrafTigerSmall.png new file mode 100644 index 0000000000000000000000000000000000000000..b51871110180b2095497eeccf75cb1d779a16a15 GIT binary patch literal 3448 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 bLhB4dQ{!(2yTKX4VgOT=rAe)kYwW)O)t!_5 literal 0 HcmV?d00001 diff --git a/assets/windows/icon.icns b/assets/windows/icon.icns new file mode 100644 index 0000000000000000000000000000000000000000..339a8daefdc240792904062c3acc42f1dfa3926d GIT binary patch literal 508472 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

af~)-5NheMNfQ)=;ref!@=J_fEyC{e!sw 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

=q5JEy7b)`WX3RlLirRdY}gZacF>U zz|~MMvlvg~{S_jWIf-5w9M#$okmUx)L?V_0IBp49%d>4a>vQ7`@dmeF)&o&bgp0-s ztuG+Zq81T<_+9`zZ*G~XR?K52#RzYws$-ii~}4&uDgDnpXC z0wVC62g}d}kZV$p9125lR}3aPe|tg3GbB49tstn+ynaHo?dcF@SifZ8DK8WIpFW5+ z{w@fB4-QJJvQC1=5Rx@x$ZzCYUTAkhcV(5n3WhYQY9wL`myr8bUDowAYXV^3JNK;1 zW&2cDuW8)uaUv@XPPnIAsL@S~SZOq+`<7W0!MKDVmoE|Qk_wzIm)OzKmg=@gzc=sP zAu6gW#WWOVAKqGA7cJtEf9+EalW`e zF9zoV(pTfr3&_(4asf?vKSx_Ua9)dFBO`_ZOUGY$Os>Dkrmd_9z?uE0&R9*>{{-2; zHJd?bJ==x)^(ZAUF<-J*qgBf^~C`69C9!e%A>!3GWzSl-M(Rx@P+EI#aC*GA3INkuP9XG~( zIDyw713$)c&TSkD%{~w}p8U$WDcgvB=KM-{A-XZppC zd;sKIhVll+q@>fZzypmZq1CpL4NmqD@3mUNw!=$s87%VsX%c{q{V@6FeaOcB&=aV^ zhP7$M$!F0cyo+;V(cu0+rJS9~JiN97$nOJuk* zv;;Yr4nB{OJV3Uaa%h-7Z~zklyQ2{@0!zdGVPiNNzLIR?brKm;(I1+X?( z2K`vi$KH#RC@=O9F%2_{cmm}d<36LE0Gxdk%M*8t@vwP{zCH%)wJ{V~yK0?Ks(Udtufp z1I5g@>`!@g8vf_hWNV1saYNR(1ch$W1Iqq+h%Gw?yA(C#J>uzy76IoSsce1c>~+=i|RQC+=Op zy`ecqzAXSL$OU{p5R_hjYSS1uPCM4+XlrgX${Plx^9wn(XLmp$h-4&^I4Pbd%1(pr zzj$XwuFnL-9hMnO7wF~p;rkzohYyB@51dmnAnSkg+Z*B^e*vE~1;8a=j4dW79*Wxy z|Hy-^%xM$<9I4t^b}a`qpp4#uw!JGYdIzst$cEjq0bYL}qN7gy8Ad?3DCJ=Le{i@$ z7PC^UGl$ltzrXPp=8Gs6oiO3oA>ay1Gi(>^5PCmR|`$oL(b$A7CT@ zT-=8zpnu6LLs?_@?5K3YebfrK+OYWf)j5O|$9o+<*H#9vKbMS#G@Ol$4J3R%FoW&{b<&)Se03s#hMnV-+m3P?Q%O`A*bu~2h2$=a6h0*bxC z-hSb6yQSGR80Zi#xLix(fVEr28b7>0DDHmKBPJkX1wdexz%~??Naas?{Y>$;9VNz@ z*kxqS^eCFrs6jvkI%bN9^LpCTO#t*XuIJtz$Ugh@juOF`>Oz6sD73pP5HOvwP);4| z=@);6zozb1(R!c*ZoeJ!(a{G(QYO9g#f^kbG2o~Vg*WGMDpGr`1mG1sA?Z-!5Y@6& z*T&zK_ZIpyqXawaoMId%@*1`MbMI@aK^U9+KUg%ikDo`_9)3;yTQLF|EAb{%GU3B0wk>6A%J& zhu|6)gt;&gG?q9-kU9d$#&rBq0#A*9b)-rh?|=glKI?j6%7*gvc@8K10BrAn{>e04 zm>-Aba@;Z5mnf>DbLou^jnGGgA{HHfB%mR#FO{(oApgeIi{8=zho$cys1z^mEPMqM z&YO;Amj}J#qh8}{>SBk?W0Ul}bMxHsbQU#j4&cn*)5pMK9LD)*DDrcVl{ne>M;WP* zz|)qlwfr|zSX+bV8~*eF#SRhxHS$x|XCl-(Xpm`c%VJo1hLhF3ET7GaLJZ&vEdwAUXuG+z#V%DcfjItxqym{+b5@%8*SpD-T?N(Ur$pDaVYrv_=h5%g0a zmw)w;QhsN?fJSWY?{t(&q|5VC#*L3}k`|O=Dj`>m+6{cC-LRVErmkSbl&*JR+5{kO zWevE%&Cys6pZ`XOsE6{e&_E<>sepTLL09GRDv&FB1!9rCSO)ZXXh}aYDaO7=i)cUw zpIq3zlXkB9(FXC7@g#M~C{-*#g(;JUoWQ%4IZKQ`Z<^s9_~~1n&!km>}h0zO0`|$xJ`m6;-1gBeYU?K-5@MI`wp-(QBJZF$iBM2im%w_^|b>%?1L(L8# zU&<|()2UTM{;$Pas*9TBw9_;ir#^>PlMZkJ#*4lt3&izqi=*;S-`sPmJ=t)QzMa#Z zryb2scNfIdKZWaA#_on%1K=hh%YU#D&LhZWpL8Hv4dmb&^GH_0x4jhO$+sJ_aymr! zT|j=;`D4|YO@{w+Do#-J!!1sk!krvJA%ML$RX9X5EKIf{`3m58AItLlQ zKy*fV8;R%Ik~N*Q-&#lHS*tbtDH=%0N+jz<>o+Es+=CR#yWk#4U+H21j)Fxs5AvlH z@Z_SxZ!ZYr?gr1Ht>=^7*S4zL=qC$T;WTqmc);Ql;h`AD=he&{Ghlz+KuM(}`=DAKnUjt<( z%X#GsxQ>h~X@dMuPEHx6n6ELU+YkL3801xfH6mUZ4a8yMa-wzRQuG8oBFj-(G~E`mZ!OZV?pf>-Jp7|#LV0jo4$-iO-nr5m!pv=fkz~rQ$TUqNWl5sl>_$dXu%yio% z1Wyvs3Q&W!lof^W{xt!YldX^DGpdWFNSM;Zcm!mWYAG*FO#s!9Qhp61m}v#E5sZ#x z-hzBX-nAnx*xCXJ8D&VQ&4SQbY>sSSd@dG^+q4|)>x(;KLb6nfpI@61^N46;o(aA* zJ;3>q$`h{{W1#hP6};!VzyfxmwjIrpPZAL4DdT>3Z>bo(52Lhq4)q2rW$WskB!v0e;F0Y(C^z5Ye)^}m6@Q7YyDA6 z%UGg~ky(#^g3d|tIWHe)1FPZ_l-lZ<^ozYsZt!C+aHddZ3cUH+U-$c6W z!O6!t?$TK_nml(Q9-YyAmr?mvnItpzd?(n}SK3ik=t;x=^$C&-*i&ak#UMArg8j&M z_&8plw-E75;jn)Ubs%mb75dncU)Dp2t&i5fBmgdCM&5x?=@adxa3`nZkx4j6Ns1Vl z|8W^f0s4>-_8(9iVG{Kp_&p~@Ov0u=Moo%~iIyYp1b_h{EF7_hxOaivcVR?w?X7o- zRP?)Z#0=j1qykaW0kg)wdOON~uZd|80Oe9}U3l(S!YlNZ4kxN1 zS!Iz?rt)HXG%x;*AlRMeJtv3>%c@bs@4;UK*?z>?Q{ji7iWZo%j9HS$ksggnU;7ai zIEu98UgSH-RTMM296#IhQNr?J33nXU5y`P6>yTCDkwkBUdEE6a$J?tRG;)j(xt(B@c;3tn1h! zDkPya8k4mmle#pOl}nDwj#BIN^EXRTjfA(Dfdr0q6Gsrep zSt}XUlT&o{=(Nq0v}XF8dQ7aA^Hhror@I-YyEewddx0Q-cViZwgY}}lf@R0(5{;8T z5-p^{wm1$fX;fdpe<(2c001lc#YZdHU0(6w<`YoX}Bnhr_+-iV~l62?+on3Y&rfoMS`yv?EG)lQosyZwNS&x!bRfc*XE^ zG&4>ss;Zcw(Jh1hm}aTPQ7B#Jg&f_6UqeVv+J!(j-ZbG!$2gewC zVv-PTCg5D~TBOcm46^=jkz{sgc2(S;-1z=;Jtw@2fY-P7lMnho-pFRDI!;OeR(mVI z61(PJcDt?DL7fea22_n>!&h1g&ff`21y2{kg}>K{(%R6H%MH2V&f@;U&2Sr=`8F&E zL{=rpXfPnsv+XQ`LViLYu(eUtyc@y^^C=3Ma+492kXTr9C9*fXH2$mXIRJu?4oXF{ z_pOf!yU8RT%d5mmBD(_|P$k5+r`tT@)ovGR6@p7hV;bZ_C3d(V#-(4oi%LFy zlX%}~s||<1W&$q=?Tj}pK1WsOFZ!3D;LF>IpV2ZUJ$G)2Tao>hyM)bV{?BMVuOVGz zlX!B?;WX<*HrZ($XRAm_tQ!5Xeo4O~;K!e|-x!Td_h2GR+81=xNA*toEY>o`6(%?nJn(UW*4e6J`8+@I|0Z zNh?I5fIEvsU=~{XyHh4HfFhjjcqR0Aptz6>$N`nXZMO}|)JYJq0EmEcr;?zQLBqd* zB%>4=QZ$#WtDOBNEf?IQcpoEktK!Z?P^LZ~o@Z6(jqhAJh}g;~=d1iZo6l%_0Bir{ z*_-Epv#B8|2f)W~O%1GGo9z3`!*yMMjIa5N=unM)4zg`OD(3b)^x*`842dESQ7^*S za;hFE@K+zQ0sl?!q8J5>u6FRC?7Odtjz8|SPD|xfsMzZrUlo6IeO7Kf*IdW38>BvVk}a-61FDAA3Y#-nzK@HfE@ z{?i@EfE=I-4m7yLOYr*3Bu;%94ly5Go0r~W1z;^zGuilc5y;>IZ(j6cHV&MYT;P}-$xh8&ob3yzQ*!`;`D^Rv-rzDTfhlkak z1`k}zOTqQA2<=*K2!Ie5u1)n_jP;x9Um|o`@ZR-vBk*LJPwQr#H<4nZbec4WF@Zxh zoM^}Ago5g7RPWa7u9EG1({M3^D<_ zk+QlDy~>IWXp!(k3C7@-bb*T9n8}Y81|`JIn=C9!ZlKUW!cK9Hir0R4^05Tk4E7;K zGLm_%Av&;+`L0`$;AI!Y9p)+EG_~%{c79;}FGEc>sHYvPo|~cKg%iAK5yLk$Mc9mF zo9xi|TA&rL5m%r{`Rx8O*eRF;f$+;|-lwdGRA%_07LuGI&wt@wP;S!6k z+DodZbN4j>#l;k4;@|WwOFO)>Cyr@%gIjc?!f!){S&)hM+;GJTc$Hv_)o&~LXc-zl z0fIR^1B60~^caxX({1XD=GolL{=>X~r>_t!r zv+D3gD*z>lII`?(i$VI*v^fG!SzP6en#K7vd^hL3*{Y%K#LMixS12RMOd zrgK7wpbeN)Q-%N>C;-X&a`BbG7eP}CpMNj~a~K?N#-V-R-4GUCNIXJc@qC>c3|OIl zq8Cmd>eGSVa=VcPwE^b8Y*LMpkhn0XMMVITay<(DnJhi_x-Q_H=nY9^`EtZ6<{%%_ z0z}|WqeyiNib7_QX8G}a=zDw+WvG|94-vBu@AD446X$SpFRS*S9OU|cI6j(pnTl*T zT)Ua&hx4NRPhHT>3BMFoV{=nJo8{*KPL!W`ecq%_KU#h0d{tm=f-uNCoP&5Ztx-lt zt6BZm7*#h7*7+7pDfQ3+5OMj(f(}*qP8bE7NacwSi^+|_KPAlKH~!t53V@Y_`zm%L zs}0jjO(q}3M$0A4f(Q-46!rk&u1eqrXa5Hqk)jHx0XIaZKpT6h2hoVsoFzMkGVLJC z=NQ(VNlX({ptZp}kO@(ivBlJy^j;8vI_!fs=!n4Fh{lj&#dFaJ9?&;K}+=XDc+ z_xdi3qU_LNcn1z*{~78X$kUzi(cK6c-3bpcZYC?(<~?<0d@qCi6^4UFP+Wj{Z6Qhh zy&z7EtEf(U8`{~U%(#k8^?a-I(F@6Bq0)Kg8X~-gA+E3}rV?oLt|>*XzgDXZCQ|;U z_cPa|9WvzuL{e_-MQ=;Fxt}TC%Mrh!7icyt1reav=Y4ojGEz`U-zF9VIEmpt42#cm zt+{bWA@Wbdl0hBR7x1p64vOPQmH>vxPZ8#Kc2|jGZ4CXk$c#?P7zT2N_ol$1B7&4I z@5KbEZ8aLBy*1Y#I9%I#2}jUV-~tk69MyO<gQedNr3iC5t`Tk)K?Ec_V z)OLTeg|BuaVMVP&x7}YoM!6ms|8J2&rdT4%Vq+{pOu#|Z0XU35MosDkIuChZ7Mw*; z*fiv1Wrb!eF+zkRa108Gqs=HemIW839v4$_4MF_8_An^^9;Urp2;7-n?_Vv-#hxXJ zV_l0Q&2I7ffimPgjFxZbyh-q5N*=cT5ROhC;?SA_cWOLDuA;L)gz0Z6leRgJjNsj# z^OvCN)Gc!)>x?g%6mkL!fJgOJZ5B7n7{nTpCoqkty484x3S#Hn=@!~>@IZiHNzj*D!nF_9QDLXvp{jU-~J z`c3C|5@;sq$TX)RNd^&!iBY7;rs|X~!&5K`(&Wo`n=P=3s54JUj6rWi4L_C9(@^x$ z!%?e?*ch4ays5$}JsFwfpc?y-*@(GMmB9At%{YmC21WyV8#kNGcO))m*my=9K&-FB zb)9GMxjpvXsDH;6R)OF)iSTq3Q399Oh9kTko`Cys((Hj*%>w_V2Ne1f05=N}^VYae z^o+pk49Lou0%jme$73x)vyU!QfAQ|sd8vF_MIXl552B ziLZwO;;+A55TC;A%!o~O(3ZMc5~#ziCF0*4Er(MN3y-jXjP?PG`EL;6a??hrx&O#z6bH* zW7vkNdr+g}%ezV>TTBi>eLCpvD|SD}Ndop@3Jy?^S+zu<*uDAqm#?P`qSdKACDOlv z&Mw&i9fEMk%M*1J?@0+!Zfi{zm8FtRFA-pj2Ay|qAU)fMw-&^=!(RAptj39L%0BtI z6;-UCZgHd5K#4d87w!fq{74KEY)#3b%tKlIF|t72#=+yug}fFqoxMKYH>e(~p6|Mq zfXc>^YwRkLhLmUbx|J?G&UU>b)NzUN3FvIJzLn7}{E zTWUoTTPJI`3J!oTgc4b`18f{VFxQ_O{qd!y3serRzz4p6CJ2X>jcCY?Q4U=OE5O!+ zr8NrqV`F30U=kGuOHD%bC?t?TlVf877b7AyDJr#qpwo1AZ6umHjC+EB*C*xkK?FjP z4Yz?CN@s2PIITxhVDBFyKLgEr_rPT=!_g?#w(LOhALu1z{=sVKaA?+J)@FM1)$n~P z?$i3n{-(h8v%iJh1Z-UjS=O=^!L#B3IPt?ZUG3n&&+xO6z>Q5EKvTI>+ENp70qm2= zMp2;)O15^GiD-u%g$ajlo9p`~ZfFeFVyN+ToCK4I-)19jSR3hWmM&1f8;05MZ*DBg zX<(1g98)Z4U^y+4RFdk^w)Pk9?Z7g^mluLo|-GV#+@ef ze>a;Wf0E#qj4$)Fp2TT=5DpbAH=SzX`Mb2of?^+TM3!L>l1t)wBwdvjfkXo#h3=p7 zOSTZ)p!7|5fQv|VvQTT>gUGyI#E7jVYa)g=f#;ya;2 zj~1X`+*%RmZ_P_<4aGL)``Xwt4gs75zl&TA--Su?_jbEw2|LN|t8Yy3oqC`_cn$vT zwFT%g5_1>{9#8A?+FJN0w8o`%bCR2~CIEf2eW5*NZ2=?=c{@oz8U4hUL~}oDypxSi zN8ZE18x;$XZ;PH;%(f$=?!eC_V#TOjBC(+Zh}7ERbRkzkc9XI;+f+jkJCaT!bULEF zSP69WIRNG4^QeBz@K~+qmG@`*nd?DB2_pjJHV9ZERyNc2Q$5ErTuf*F5|m+0_*Y|@ zQZi)?CA~R_+b1!yE`A6^Y-%H-k<@{jdV@J@K95 z|8YROy$5@Sishpy33mV`;#p;g8ISZ7?WB%^q2QO`!cHzjO}OGZ)_ozefX(@Tj0ILN z4$Kd1+<3a%0$E(@QCa**?Q0d$a^@+Y1#srRBr+=-s~WpewYYC37kBY zV7n3eS&p1`2AZpt-N?^Gek$Mg?{Ff8ngy(K{-WmimMh_rNF7Hf%(8~Pbj2+B4#{EA zg_>*4XhS9P4#G_rG#=V~wKO8;Q@$sApUCDPKegzUn5Cej+A0q1a3f{6Rcd_IvFFO?>AE=x z?KAWF^&;;;31XEiT*&x~jY6@2FZCaKS<1;LU$*jD7fuldBK^z59fkl~XUvZn^9~s#6FOQTXhrb8z&AFQ=iCj4-@V9smFkeWmzw%esQ(1X78Au`#IsorHPz z-qf1-HZ3Apq>0MBr#$H%(G3Y~7yefYi_NC6R5bMbZ$O{1{8G z>*b&Uo>ojBMq=Q^sZ6T^%XQIgNOtY-ClzB zeJ##>)B;4@-{6Ga!kM>}Wn2%Qgbc%_XCxhEas_-J=n6>V5l6r-Gdj;G#h=!g`R?cs zI>9PTIN6zJZv)`>5V$&4RQ`5|K|A2!z?Dsb-IobcH{2Zk!a305vlE*AqwwTo6=)WG zVbq?q>GOsRfMR4HM8d11KJu1@t`j{7mg3x*K@_RoPGsqfs0 zk0<%vNC;yaRDms{lL*~{^#b21WpkSQ>YyYn$EiiV89fClw~+{_2>}lqKQ`Axxc4sL z^no;jt%#x)*o42jvxw(6J^?Nijxa9qEaDI9GmQ7wJ1^c(B%!W>sKWeo446vg(2_|% zd)}4X_qEf+1AFT$h3LQ=SW~eAiQ(~9*0}4vMbJ$+#DUcK1UW_x_vWh zFA-2YBl0)Gj(>EAN4$hM{he^;;hdCughbCLyH4Un*8d7pfwKyb(SY~-4$^)7#K?9H z(*YPcD6O{WrA6eI<)3RZr&}Zh^rYK|v|Ky^`dZyE*U$@$dFc}CRED8R9)rwz$-D&f zlvyeZNg$L^Uq&+|lYK@@o$)u-Ey~*s|4i8xYD*9VAj1RXZOH);d0yXNB{~qYO@s-o z7eomq3C=QN7%lMpY?woc__R${Sc5Q#p0J(!chDA9#`VGiql;ohPch8w%q-cXNO_xG^rO>-pjrS9iaJYYBhID7m2 z0Fs78tT{OQ7GRzmhKJw`QZqG_7(=@$v_Gg<%)1xP>GgkSi~zKbZ=r(X7~yE2>rWIduJ4Xi+6H?|Z&D6C(c z-s6lj%_Vs>=}$~g-Bb>_5FUgF;Xw5H05kf|OE*r26sHT+N=uDpx({r^`?wl<)}&BV zBy++*tnYS}h&FiewIQdVWLR=AAnGBgfMk&rd^8k5tCmsX>-7)%FJ$fZt2MBk5P)E> zXT-E;<&eb^zJyK@PwrqIk5~z(DkQ zJoOL62ccDq_W=;kLap#hd)w$ApMDJa> zTbcEd{P4i33y@(>=p9(9`wzj?_69PsG$TV$w&t5;eetD^K(X@=H(@D2&Vh%}5vU>M zBBs1S-C_>EV?N2qCXq-lWblaIF5>UUB-H0EW&7XVQzrki$w?63nf8@6C`1@m{@<=H zAdOkpZu#+@n8ZbR{hf^e!MH0q5dn-FUgDNys%R*6xM6qTl+G2feO9tP0&}4k)Lu;h z_&eDsby17hcx1v6+*2$NhC>sRYG^S}oC`htG65%)sR#;#uKqF5EElWasQmo+4((4` z_wt%tYnnvW<1H6(m zMlKRP-tJ-HdHOfQKfs90K8eOhlOdzQv~YuV@s4Vz*oDwkE#R}84(ccSf0>8+Vy$Uo%;7BNf6?f6)$Qe+0Gz#X{w$J) zJTO@zXVjf%`@J8IIYi21Z4TjtCO?;u=oPyW5x1|oM0}?U!2%j!g%wAREXU(hcby0c zE)T$`e%-rK{S0*3Jf?|c_m1`*@~xqD3!)y3) zlELHx!XeYypY@#E`~)BuixX>e3PD0vI0St&8WJzI=a!Z+wezZmqafu@cou^IB_a{I zB}}okFydbvtiq2|6*15oPG2M1Ho6U$2cp*!2CR4|96#N)eW)_wjP zxk^xyubFYV9VUo<5C@bHdq)Z1lk(;aKhw_70x-Y9o@2`Sob&};kvNm#81+1s7XrYN zVr#;5S}I?*aXsl8I>wJ-F`RgeNbg2WbY}bQ`V06e=NS)QlC%=cWV-WMPw^x z#bWL~V%Prrm-KU{fDFUv5H~;vqSN#5gQt9JuXa`%UF|yFC z?#q9R9jqBBDvg*E-Mzm+wPG*!oI?FzMAK-)G=d!e?FKcLRx^3w063DlU}PM5%unK@ z;r`4tYh6Jpuu4n+{a0Mer3;laaqLdX0z^#0_=7 zx&EGa0+7oI4Im%f9i-{*o6Zdjn9H#jqHSzC>G>CPQQ)bz40ET^r&}TBW^|te$V_|( znV0WQ8eihe=&|Z)uOI{fonFA+JF91)>D)_?tPy1Ny)lM5?3*w$E1fxJdk^j8G37Ph zfh@NjGYgXaC!4!j!~m_epi`dFDgf@K9wd1g0TEDFe%2a;-fP4K;)LGkjJUrb1mNt= z^B3spWW)s2ZO}Y(3whv~w%c$%P2Jfh{7yfg7;U5(t%iv(*WLbz_)MX_83+K0mllw? z!9mbCz?#tOkE!WtZq5Y|7l;$NXggJ#1t9>b29?e4evto3cnDq@3gs*@W;Ww1^s|%R zfLL00X(ZlPm)m9W4UUV-vw5svu9Rp-&fSH&i-`iTjO>ST2lVRscm2V{5`wv<79hSiXQj*?$Gz zZJU_`h|a{A|8hN8M(id^do%F|_m;tca!%qW5*G|^INjz7Mgab@_oKnk>fE1!4ZVl0 zXJ{}r<+R&S){H_QK&^Hzfk;GU+GYWYMllaI#xc~Qx({>baSA;77eN4c>J>Z4HBYea zMvb0?k|oA^P(arB-hFQI@45r}2D>kvxKtT}Y8rTjdF@@akq)8ul^j94qs zEzRVfbkGU1uA2cckG*s0z8~I^#@qe5=ehTZ0|pE=<0cA9061#t^UTbr1_Kjx-bSgc zJ1EdNGMAf>O%9o;zZuYhiqXH zc_$g|M-jm2y~DlEJ)i9ujd;E&2mn2xu;C0Vc&J>M%P182dEbhx0jRvb)jm_69f2Eb zOaVx?e+QChT2Tw33F*))QFbi`EG&|fQ!my*4*#W}gEvbNfTGfGhy6JH{gRj%KuO6+vBBUf3YCz?~S z0-}J2tiU=vTnIxC5c{_E{=JLpzBk9bs1{|YfvPAMvSM^c{%dSVBtl4pYMD)R5pvv@gG*v!g(j}d z+Te+(e$-SP7wlit7Xb1oY@9U`?4Tj8zp;sTxWHO1K;pxZH z%^%-e#>Oso^>(6JWPY9Y{UuN^2C|R<(Bwx1YAB5+|75k~5+paZLmxmGMY7e&rI4T^ zY%2k6{XJu-J-NIJD@cYX#U@*@q9OpSD75YrVL18a#=i@b;KVw6x5?g9R>P&}Gvf_Q zZ#FhWgs&~N3m07gaf*_Isc>6GZCO+fAh)mtae-;piWNw!VjPQdj1<+V2-FK?{aJbV z>abU{^t;~n;_pX=ER*=JUY|EFslMX-*S?~V{IqW<#8t>ii!ekne~mTIgt7SMh1%V zET@PJrEAXM)|M3S-*BLOylR3{vI=jOQ|8`-Q8Z50&<5S!4N zUmV9S{37<<$bUcXT@t=Jy?FUjE%@+-c{vz^qn6X;S99D*7@if z9jN%14JzM63fc>gsNNcpj#|5qL?49urF4jU;*ids*)3M86mC zdQlR9_xjE)f?djhkxRXj<14G;-gE$U{`A?o{BQ@Q2VK5^o@gw9ItMm98Mw`ne5mai~bvY@PYFuuGdrl5?Y_>u{5e)DkZnT7R(*=z|VQsIX>esBa* z0@VSGX>h|On6kAGiUTSRGtIHczQ++i-#^O?O{?M|KI>U;<=C`7GX?{qqSjBkuPq0# z-dLv@rbIRvU|Sh47Oy|8scqZ^T6Yxa8a<`LA(4|DX?Ky@>9hVNY3j-i$Y-@0Y_V1FcC(%051^s4$`YVz$vbW3*nNIc&q^N zDGKnQwxNh4oed2-v=gpy5VE5W{9`)6aSkC+jMkxPh&o#l(p#wltxU+WMw7`UqxAt~ zMOo|bKJ490_)u&#fbsd%&@_ea5UvwAX#35gu5_qJBr zM3o!izX=?d=vY&S1R=E^o9rJnL@apG4p{glu*m6Z$Eif0g4Ka`b&iLThaUJDF#I^z zz;~Ih2OlFwndx^Hhe1FOg-d4=Q61K$^*x-<69u`as0qMd_WbIq&$sqEw#{P|wn588 z$DnVASEO<*-HmNf*D0In;3*AFJu44$Lr);Z*=G;@@J$Dsn!vx?zG2RI0m7zO)JapJFjJ0m)39HI-R!X2<8RG=C%9@Amw1=!g4Hr6%h-yQinoG+kb?8CFXo30dQ0&2kfFKsS;#Dcj>oT@TN^x>B2% zUJl|^MSME6`6FOi@0HSxH_E1?cR^Nm0ms<`5CEn{pT>zsF#tcwwBL6a&%$ zp4fb52`0!Hcuoeu%F{ED773@7sj=Z71fuD2hESe8I)C846cecJA76-$mwhqPum(N` z0z+dcPE0P0$FBTDzHhlc9rgB&He$(>*X+Zhr(v@H#cU4mk0=j-qd11 z+!(e>iQL|kV!Vwa^F&H`P-Gp(hfyUrnMK(O)wVGzDGc=RQM z08A=lQ2JdSTzSN$B)ebFZ&-Uj7XKc+{$AJfT%qpWGz5U2R2IAVQy}QuMlaT<4_1T| z_)+EY#Ie>!_ob)3GP2HK_l2oi{QTOC^vx%tktP4^!II<@B)!5lvfHtfj7V8mVi#{c zT`qPZ>4%H9eLWrH-U^)9B@h`JU#LLkWxu%8zkpLSD$^^QiuI|y#=gi!ytcnmJlE!g z-a&u=%J%ep4q!mb_~W6TXwLo9FiXNhvfzUffHxWl==!IjfcP^5o6Kobn}z_;lj?{2 zPUR#+1A{=ALAZZ9C=N7jl&y2R`Y9Uc2BuA(rn}?N36Q;?02@BVXfmOj%is#A=wlXPH~a|P z;8;pPY|219C~|NNr66Jy6O0C?Fl4iAS-B1onopB30QC1CnGZnwkC+GLgT@WeU#wn# zT2tIK1b~B&m?8@%lX(Ph&M;*l+ocI;1j?&k*Q(gt-~?OEtHlA_W>(g|gqQ#{=QD}qW4O5)``3Gd2b zxH&&mi86+a(PSEd2BN5<{Zh?qQxSmafcej>tfpUEERpM}CZ_jyo(ilg^gLMBW>^G@ zi3o5m4UosFOnbJ~EvCGsVhjXp8Hy|dO?;K^Xna4p04rp8qfcF$2P>Q=(NT>pgOf9~ z%KalNPovJAil~yI%iNMC%mBkk(Xg&Kw^7e1;)H z^*jXU0`Vmm1OTbN7P&`@XgN|2Wm6FV&SrgqFaFViQ^pps!H%HOW)!D`AKrm*hLfjR zYz4_~=VH^u+Sl_hZSVBm-^w6Kj|TlAPoxwHVrxXsU>fW{)58U_%o-eP^YOpbCYXjy z!5nxLJ?cz5koO$9`~BO2va6_qOo zr1p?QsW@;!ia@G*=nv>mfD^fq8&?wqs?-Y-QWJrMg49Ez019c`ME$}^>taAr8{*jc zu)RFbCMMhUI{unjdw1Sf+IT&l%*^}D?7Q>veyIB75%pIqv!klYi?W>K5gui&3hHv* zp^KP~&MPRYp@<(IZevprA+owLgKH>F5_BNoVBM3#?)qhz_Npkh0A{_F)l@Fz!8P90A)ioz<|X7Q>-3SWON-_x0BC!KYn> zO9u+jgrpZ}YW@8JXP+9V2u0|-nEuB?>o1J|*vKkT*101;Kg8r zTLJ_K?(Ux8?(XjH?vmi{PJ(-a6Ep;O3j_%g2=4B4$=>Juf&1;&o$3!gRb&0OO|R)* z^~8QPoK3%wI9Mo?u*0Em?V_@*>mPwIh_Anj7xKA_$_Z$UD|dpeellpP{}A1RxIS67 zMQk=n7$%E+phWf+7sxuy>+L#V2ENJsJWXQ_eg0m1wr`}(lTQl6`#AIQWT-YH# zuh-^JVSNy(3!+?W1o-1QSj)hslFSJM2_F|e{yTB>?nC#0E`ZsoXV<{@%YXq7Xna*{ z*n`~B@15?U@GW{ic#i^4SD{|Io*K@3g~WC1T|*tub{N<*6Qhh@dul5pPyv&?);(~vys*?VXxFyW=;=_@q6 za}C6BY(__OPUX@?-hTsADSUB`L*mJTNiQFGfe8>aKHpB&6}UEY4ZjxRxj(T$ngW?Q z5>HQmY?>u6dL*I)<=$e5Aw_B>dLKh(pO}a?_q`>LtY#OzZJ*#>{@h4j_PX{{j#n(= z?4HZZXETf+Vuf&mvQCk)Ngm$vZsFO+34ewYw)C(hZf`iKSxhIA5$^d2PgzH*0-XMx zR7wj!pEvO;QdgJ@I|koz{P%Vy{N!K@`F*a;OfN0Yj=rP=N#C7fy)Jkn`v_4n(oF~ zN&RN)oRVU0J_L18(W_*2xZ6{;0}QOneCnh@@d@CU${c#%c`i4IFAxtK&Q~}X*)nQn zSLP6PeaLHltEr_|$k<`gsN8;aP_EA<_q)&G zFpuTqtt)r(=PSIAQZKip;x|;z(gM%ozmE6%ne0%zZlC%Pjqx`ImV7WV-z&uso-bf^ z*O7>$$n+hn%l>emA)rnAZg7>{sZIaZ-}zyLFUJ|vZP?Xz zB*B^YafB83-pp;`f*;2oHczuz%wMe~t10i#^W>}&gT>E=gfF|2u`$9J6H7zQmD&#s zEiBXXtIWuX9YFApk0nYI2?dIaVj~pDSWXD|Oy7+Q-JL~wvzhrNpG&&I!h>IcHvL^E zhRcQ3RR-B0fyRZ?v%9LD8AYbDPVx#;EO4vF!})?8hY(F@7EUIZxk_<}UI+>FkrXJZ z|NRt3h11F<2@vs?ygM8c`Rrz;C5>qvFWg_hlhSov=jId(6nd^-jvQLpw@?KdXr1Wa z9lnBD=(n^tZF=sVVwD8K*;s5sd#b>{?!qcB6!{2)jDqUUe?IE{QGyAr7NGM(cII^(zisan z_>k#>Q|exSx<~+1juW7=*hGFoG5t+qdW%&RFn4uhedTJ7fH{sIBf<3Rart3;I(7^& zoz_Dp&}qPMCbD)~*H$iKt_b}oi?xJRIA5^26y0hN)tITMik!gvUy-WAW2tOVq7NF4E0>y78b5RrijU~qncRgYOnQJrN7G2!g( zRy`ti4<=jlf`Tw20f6B2jj}N6;@T%L`w61daY__W+Q~Oqk5}5T<`gVeq!eO~v`)CW zz#Q9cvAk!o;ITHfSv07XwQ`LFWBbrnK+&^fUO>RA{Bs1gXW=a;=o1^5__>2c#}OwS z@O-Kzx9rP6GOeJ|e5oSP+7-&lT6NnoxaW{Z{z=sFJ!I?$4-9M>RMnX}%R@6Au#*CF0>eh~G+wW=UwI;I2 z#l2g^Fo@>n8QtGQrHID2Oaw5nEVdFOkc2FtZY|WUg}Sv+w-)NwLfu-ZTMKn-p>8eI zt%bU^P`4K9)efQtTButKb!(w+E!3@ry0uWZ7V6eQ z-CC$y3w3LuZY|WUg}Sv+w-)NwLfu-ZTMKn-p>8eIt%bU^P`4K9)efQtTButKb!(w+E!3@ry0uWZ7V6eQ-CC$y3w3LuZY|WUg}Sv+w-)Nw zLfu-ZTMKn-p>8eIt%bU^P`4K9)efQtTButKb!(w+ zE!3@ry0uWZ7V6eQ-CC$y3w3LuZY|WUg}Sv+w-)NwLfu-ZTMKn-p>8eIt%bU^P`4K9 z)sjDWzkw88^+Q4m-+0El?WQh~Q; zFWDtA`p=ha90kyeg1~740ODu_1ZD&w7ywivAb?s300Y|#bXslsiWT+dI{y9CT zFvnZh$T-;0Ur%r9aistIBxFEG$G|AqKrieO0;y?-K<-0y3@rfzqjAW?+0ek%9c0Yd z006Wip9WgLogI~x?>xt90wy{=kbdii$Hxl$1xTN+p`LEU*!93xkk|a^<;VwJ13=gH zXG_tLhux1)Z41si0N|iezc+j^Iea*LSg)ZG44`N`OsrqbO`WbyIq8G|D8f1sfA21@ zZ+4<}Ekgk$1H+o3;o*@6W5X~21ToMH(FW-m1iu6u9H#dY=D%PWLMTDZYz!|Az`;t% zKo>$AL`P4@KubqN&%i+UPF6)uL0OTHmVuFhnt_qdF4D%r%s$$JhLM3DV4xTN7!j>) z6ch2`JuL$Vz`$S|{UOlGG9)b8=H+RCS~SWs(IU`aB`7*Vf)-$;HA}GI)sKwO;CGF; zpkv^n6SWPu@O;njWF2ZPLdOiya61~R+VHZ!wooy2;-UcnN@`tS>p(l}U@JdeYKE6! z={RgXLLKdc-R(JP{{>4U>Kz^&66P&V$MF&@1HG2Dm6eSiBYijk!$2QG1EQxF{s4qg z{!gSDAu=FIMd1(tUO`$$L0URkDo9#JN=i(gPgYu5N?A=)ONm@o)N?uw*%Ft3@ zPtU+gUrJG0Dp*QJ$*MoPuNLeE4|!ARdiUqwn1kW?_#(J)YueXXaVW2Er% z0Wy+0rut?E`sVtkI#U1IRYKmt*uv1z+}Kb->R+f*DkhfZ<`$-^(l4Qcq-C^&4PXs* zWTjq0m68dO0?A1I3svS{s5WM7oB)i1UzD<<6dE!C@(UV`CL=Ab`qIT;9)bWc!b^7P zJ$DZPFiAFIV#+dNVx-EhPL?+I763q-6p%P72U2-8AT;fvC}h!*-8{Mi5^T&FPPUTbD8LEM^4vi5Fg z#Z4%98QcBc8Ww<@Z9`dP68OHe$Ln2~7|F`1sdA#MFKtp}*dGB%Y=QuhPSDA+ zWLV%W>tv`X`da!rQeT_@;V~^p z2N5so8 z!qXoC`+;(ZcsH6nq(x?hA+E16)!V1rXuZmmU6QMYD#~A>rE)31vN|7Y?=EO+qmm_` z?Bh6eYfW$TDeYV^JZPDJ9uH%yR;&HECH@LiZ z=2MU(H%gLOwH+8VxN%JE0p>*@-DlVu*dbjfH6C*$KeiZ`G3(HJx4H9H8a*P|>9M9- zrWjr5$I~BDOyM3jz>$VCyr+HpxA*bPwS9%<44RTB4KLUo29)nKAaT3nzgD1pvuV)U zf9k%MwO1*_{Ahgkpd?QpUmZY_-<^5df$`*BbL&n!!Fc)#_t*doGYEtyI@d*rlIjr3Ec|I2743j* zPo=D2po0uP2A4d<-|~E{Kly8c;2i*o;;K;gj=u@oSrvGRa2@|7gomXoD_<^qp)xSw zXP0^%O7ce6ewb-y+5US>X;3S?Rh|Mpuh+MgMVX-QRTm)E=PLEF$6%KNua> zJ@Ff%!il166GSV$XW>n&RYxOST}JMH6MEu`5;{obW3ZLs`Je4N&b~D7>T8v|nRBUV z>|fF6iNAk+!+0sVJIO#&XPCy(plvzw2o(8_?6+`?6Bal9=70~bo}6i$}WgX zZ=WV{>Uf<{+w<^ytM6t23{O7|rZYh>O(Fgt27FW*hSZ--}Z#M&&`@mubkL>8=g)v(sle`F@VF~Xz^pWsbj|{dgI0b ze+sj%B_}&fI0jQXA_?YerOwi`>0x{fsx?+9Y~Z)eX9Rzk12jlejG5V)`E?L`K166} z74i`un0xx_yU@Bu1V;oHj{^5t9pwYj?fo89WVSH6)_vbT=#?kb zx%blT*GZj8;kHnMZBDQ3C0$_heb!kVAuIYEE$D)a0etG1&Zs@gOl3K-FSQ;VCR~Mi zI?ImLMg8Fvo*Y(C?Oy)fOP|(YMPI**hr#cWu;VmW_pXT1Yg4Vs)j}sJo3Mjpy=f2Y z`T8+f><%;Fqx094nB|M%Odo+`nr+U`G8c##uNDv0f6I>; za{aFzuGew*s<6KLCOsE1M+6mTjG|45^t_}(7EEUqAOObC%V}S$vo-lS zRxWQx9{3I4bnw!(f01HltUI40#;gh5td^YMh-}UDV=N<|0n1Dq*J`(dM!))$j>P^=*Jx_>e)wU>R>WMeV+eTX$USED|5q!0QQ3h%h01MclvEx zElcCC2!R0Mehb2DJvE*`S~&a`B!asK z!341p*F8;s&GzzQH@FiPyX|24;mmVH07nEn#Wi)^y!kR!z3TN-Ief6_B!4RN6##kh z{F^v8LW6ne1A3}d5w>us-}CFcxi!FmURvuk;Pm*z$@ahb)RrE_Wm5?e>0M^3+v?lX z5|1BVn7b@+sp6=A>fl5+#c{8^SdWi?2M3!0-(Y?cUuO+duU>bY3m|PO$ekOxhj&Nx zc(u6xrzY`@UuGQRV7!D+eqDStCXnUm2fVW5;%68mMIQhE&dvEEFEi;o*rxWR|MaOI zVNv1!(2midvymKX;+uJrS5J1#u7vuM~@Xo}4NRe z;aEE;k7~7wUhY3{V&Dl3NiW@-XNOIc&5@AE3fjF3+!-D7-EN?3c)*DZtk`=)^aBT; zBIid)axJo)sCfe^Eg*84v4=H=Dax)$I=;zOck^{wg`f#<2YUXe z>UZhkWSiJnj_+`K2dq3OkSsgxJ`W=-t?a+eF$MBf_(loUqsVl-RMcSAX!Uw;>qeI^ z{nd7OcxA9%J-k}Z+ckfZqkZ!b`qx`|!9+^n!;M`MgZov{65RHSg@xzsc~%%xp&C06 z!!E6&kDyQ&q3~bLNnokw$XD1Oz)DJcWRTt;-V;qJ|EG70N^7YTvJx@b?sF|YMmO^Q1cUvScpR_g?n@4embJ#x;#tYYS6i|!))l4f{>Boy z3^onlf4AV~koSszspp<4QDY1#KTCOu!EHvzam`At+Q4r$bY=;$>V7vfghiG-(}K0~ z#ng6zN3qn?AEWeUZyqe-)4Bx8L3X-qB|QCrxUGa9e(W6EUh7V0$~a}$&qIqp8}m>7 zM+G@{)T)(Ckr4Ub4&nrwXML1+Wi|6YG-H+_TND3+<()4d4q zvGZ@W`LdY7ZBZ=WjM7w}ka{C+4RUBsP#xde>{`p_H>!-=e5Jv)g(}>j_c!ZeK#!YH zTpj*;ta=6UzvB+(Lr)-%bgL9q6Y)nkF+2}_Be^-_gis}HAdZPau~_siS0QIY~32&#~LH(JEH zhqS6H{EMu^Jjqd|S+c&hrZM~+vG?WGUHCUWECmafJvFG{wo`*?$)koSPuDaVb*#Ut z7Sbp^>EqIFM zo}7Jcn*KCB{;c!WXe}H!QR6zh3jyjvo%Oa0BDiZ(Ol-*Ml}}I4HACdXT^+^~>RCom zQWF3DuNF)QRZ0}1EY8Cs;m+Fa;cQL;ZZ^!A-p<<4j%iklEycF~?~5pY=i55w$fdh! zHsDD3sLd{1aQi9y?yKR!XV^S9f!92c@=>Sv3;mx+JOY35Oaz%5Z#j?u`>}fs)&>Q& z`f14r==?TH2{*=~>>1DOo@QRbvgXUh9wd7;3a-_n_~xyj8X16_ zu8PcnCD5`P-eR%fd%`x63mOfji!lt`?x5pB95pr#_ix#Hn%JM0{4&-?7Dj%$s8!{j znSHArY%9SaFydG{%O##82;DA>+4sj=mGU8E{DUsk?L17ZDRg*Kn)v>P^!uP&p5V>d zqMlvvYZre^r0Wmw^4}HhDXm1fP;=^_uaa;cJ3}<=22w9~%Hg8@`aFb;b5+~ep6b>( zC+m+5=7sU)G+@Dl>X2T%AT%cl?s%nXV#|Io!4vIGkki9!yD9=yWde7}*D5^XL%C<2$1g1xjss)^~}`}}vL zj49vy`eN27zpLm(JJ(O}U4~bso=I}VSS5M&lXaD?=c|}Ty^5uxx28h@hn?;x9CwX; z97)_rDyD2Po`xH=dwMPGTyO2#UtdHZ3Y02OM^H4n&u}!D$)qR@jP>s|zEN6GD%YGQ zJ$6bR?;Ni`KFUdB>P*))^4Las1GnPV7Jj$D@>iZYE|!=xFu_j#Yrp~4^YtS`#)t5y zFSC0I1JXZku46idFd+soEuVP~K4jl*x(?ePTvV=i)Eg`Y*^ZvH8F|OrkQ5Y*SO>%{ z($9~T#)tA&Hi_ztsgD}mJcE?zoC6>=-YbxF>Yu4NO`2JA=P`(4T{mjHj$ZDl!cJO( zCF6lA7>^+s5rNAi+2XcdTEn!i+r`AuT35eQKW6S9u_ie4D4>g@sG{Uh!PLx#oSy$M z@zf7qg2-R*-z6_%E{l|}3m@&LmsUS2K9-_F9CCY+?K=FFe(xR%?RiZJC%#BJk|pHv~7Rfs|w8oB3Bi^-|5 z4{(PGS;3k;Yt>Hrd_cG1U`O;V|H{O{Y7jg7W)|stBo)rfPg>2O$j#JWS@`G(-P42B z(U

R9oufkZy`l%8XT)-EPMwmpDD(UR}X(?W!oB{)$+0pJlJ>HB5b&*WNE@jKd*Y z(3lJp2Ek})wznj);ok|b8WPNMi1>|}xLAOavThz2c2ZtT!IdoS{QRfx>oOs1huHUW zibaT|mhjA5_*lIY$b8FLw&hb#^_V&`LuwEO8Msib!1cf7Xs??btu%hxU=3j|a^ODU z36!|(dEp0#-_m!XKkWq6ejcpoy|X+_FlZd+~nH8a}vSVr*FcWj9%iAA*=tIs@_kITbC<;Ag$9k z&ijF7eDkf$hh>c_?#}BkwBgi9Dr;JmWV&_^l4R1}3j6s*I&|{lgZun|Rs#_jGDK z!z#a`e-MtLSDvBOc*zbNAhK0ZF4<(`mcGGH!20c{YRAtPN)o&c_gCFc^2uouXX=OD z;Rl7sugzXC?t0rXdQ}=#@!h^bS`V$Z(bl||(cD03;qQ+=7QUP|S(Oq;%fqOp)tP*G zN;(6M0WG%N?u<2QEZrNZ_qZJAV>B+x21|tBp&gqiJ4{R)mI_ISApK^bc%Zx9 z*IA5J`Ls=SFG9jZ^zdb1Ik|T*e2ypj94AtX!0yd{Y!V+Zj`glaI#Rl?$EzETh!t>s z#L*|QFh=L}GQjVxP`rtF?z<{q;xpzaRld?y6_0)gY$(#0fBZ!;e^tx3%OhZ9F#2fh z+Squ#?sgC`qh~iBA)pbq?P&Y- z9d1nR7Gb#9!s@NVh9qzf)3XDsOnjC9;CQmi57q{A_5-PA0{yAOfrcr%va3_%s$99; z`n=i8;GPh6O z_38IA_IKYtjXoq(7xPdNlF%xuNCiy6?IHavHyKNePKO5gQp9U)?z7BmwU!0+aisSt z^V3QXQBQ3ur{kSye2*KkWdR6hEgd2_U%)huB0VH;4}Zv1-1!(f+Y06>X;ZuCpDZ%? zlQ_P5M7c#zku}UEDRm_Rd2tO<)Y0!^hPSm< zyqz5e#LKZ=oa+|`3Q_fM_l{rM+xZ|$J)p?7?|74V@=-AYEOl3ldvr)OO%upQO_wZs?FU$G5& zmL@b`A*t$H9DZ;OWV5pqaqeghrnZMNgkQ;U27XGxw+o&1bzha6j*veexZ3w+lpwKo zuwoCy^TBic{1X+Mm7XqpJC~bB*(*BsRi4P^NN*i46jca$okzg()tf|ayTwYMLU7Dy zaz<8_)@{-$qVbEEabPAxX&f}f};P#iDJ$s#~s|>;} zU*V~y^f;xze(w>4LlRsmV@%`JfR$pP9&!1FDh||V)}G2~MO`&dR?AL|GvoLheP!D@ zUmt-TgOZmMQ0j8LL+hhpN)tjP0KiB~Y2Pq$azA0^72+sy0t)fDZSj%iuSbvUfZ(^W z6XnH0W9XgJ0JtJ*%E?aXo%-!|SWWaI7Ob!~#ZpLf&UUZ=uZ*6LkqGL~d^J1%?;T45 z=P!NG5UGjANHPsi?L@eOjevl*mjLPh1?awSSzE9X0z^g@Q<3iL>te@Y5=4@`c7DhB zx^k1xOEH-#$-)Bbkg3A&EO#xj0I1YXWTs!xRAzz0cn6B~*I5dF%Z6YU&2E^{m^Kr4 zkvt?)89N={5HkvsKM)_&Nlb@z~stJ?*W0u|lESq)Bj!G$>DgAs$U zzoRj)5b+jpw_JHN9fdgNjXs;v*b+)SMiNnQp@yoA~o=9=*yG zCgb=<^w81D!-w)G7u5j9Qg=N+ONA4%=PlNCBY`-!gvbz+wK!yAGxDuWjw!`Y<0eXQ z;RPQ2{-L_AS!l&*Q*;T<#?>D0#b&0#`A4x2-Ugd^?^v$wYFq~4b>DII3bLoE^}g#J zX9KVdb7?WqhEu;#5uI#Xj0!SgctpOc48ptX2h=oxUOK0t0nS=m#iKQtF# zdJ$yIS?U(vcegE<@i!#}{YPd?JQhc(I(E(t|JpX6Ev z;uzrtXA(W?!(sVz*2F2IVDeruQag_R65Fc(g5%s855}Le>8c*Re)p$c^@2FR#hbj0 z;_K&uHxi`UlQ)xA z_+u!uZw}_XJlRcfsj-((^7E5=5P@u^%P|wCNBHjSI)-`#oPNuS%5u2H)K?}d={BV> zych>d0T4LQYW>ut(xa~Z-munN-_8Ei4P`8Y{Rw^#ukz)1uTA{m_^``c_sDE)8#E?i zT8)Ji%V7D)3)5u#sK3-Iqoo!^uLcd%i*oM883A-9ZO0<$MJlt+}u$2DcuK2UgM=mJf z$jQ;eS5@{y_4ta_q+Pcc626LWaPyP)eXhwnTnIc&c{O}_x zYVwE^lS&$^%~Q1U7@kk^NP5PngK!qh+stV=1>GENe!FCGpe^&YHKFPib4`YVqZX3E z2ol3ah%!yTKb-VyQ7fgRF_J5Z?s6X&1i`e7EHUwqE605!W`Bf7L)e3t*<~jphAyIi z;19|y#z>W*I}LQqWQBN@;#I*UA$O~47$PX}Z%{G0{7##TqXs~P=f>4SJ7SDV>!f8q zMW4P-Qvwl1pU7)C#vmDlyl5_ zwI6qJh!qen8E9BD5Jc~2=Z~q*{7!F?`8RFf;FSH`bDfMrOp&G}v0{xhH)=vx;Ic5|fVi=ZXV3@C#@J%&*y87(i>Y^&@+5*dG_U%5s(u0+gJlE$x;CJMpT&ver@7Z+ z3bE`H!QJ0FZGM3C_Uu?EuWCIM6bjV!mz}IK5OJ9E-dy!?0HWLnC8~R#+;->4g1T7E zyv0+B55Pshmuw}?uFk>Mr!Isi*;70)#tt`FdD6{Uf9op~wtPcrFsit`E*^F{=rwvc- z*KvL{xXfAJBpHW%3=fs>L63vIX`T#qoEmu*&z~Q!@6DWlZP9ITgZW3NoYhu?nJ-fGl`bSARmJF%bC@gXl{6)q(~Ylln=Et5IXA`l#6U z00&7Y%Y;t3rV=d*VV{+3uhaIHo=-?x-FqE zW3dw-_(aBIxItz8bT*Phw}_ulq+lhv>Q|#85&5I%CBOTsirc93k#=Mf9lR`hG;K|Y zgkV8$%~8V3VZ7|OSp`@_msA~i>_&~(4Tuf2UHXV zJbCi{fMWm5b@&{J=w!H|31Do$#1-?FliC<5%-xnTk~T}V7G55omwl-+p+@O%;qv97 zKn*0BxTfHsskVojbya_@l2b#s)hdkSGa(upY+?sryA87gq$d9)-ij7gkpJ&E9n%VC zO@N-72zw4;#A%E)5|YRlMpZ#j@2U_cCz9{3!{J4_EsbKzJ$Keu?3J3I^-=Gbm$i@H zE>13+0*#S5uGh$JS5A&GFqmh2JSpjo_|}|Y8_GxY;^im=w&3!+eGZP-EzR4m3eV{M z$`_a`@S>C2>wKUTIJVOnX?IKf8YKyF_#?Q8o_SXk`_*$RWrL5gGr}|DbKoa@ zE1jDQwOPq?%xvcOz8>p*qTB@;1mR_2`4%FWrX6Q@Du{MID-S9pjC5Z0sHRJpXqpBxz%5|{(DkjIL0@DLVLN&PJe!2}vK z+`7ow?%2aeMgql_U@`e2&(ERa%qk-BAyuOOY#5*4rdsv4p}b}Re|bX*o*7IHzC={z zN_I{XyqIB>AK?UCmNYm)s6gLBI@j!$$nFt$ZBxd95-xq&K!9p;{7u4}P@6XxPv{rZ zbO?Q`U&e((Dl8zhdM98TzQ()~Sn0;qVH2%GLIMvOZKFqe&n>5rwV`a}8|4lwM5UmE zzd_nk5kZsDi(7KOKlGLRizVZP$K# zlWC;HkvKCDIfZz+hg9C3rbPHm}ES(6uuuyyAFP;ivF>{ z!R`^D{T)c{2_=GI@$SEmnU}k>-$u>P9YuGNw{Y3vFMEdBu&F_R z_sjIg^L%f0*r}=+3}6&l4n!qC+eS0;CcEC9`gxq=MQZHMiCgPoM@gxwRG9=F#Ya8N z8Y6s(xbPAGcAg!{gNihRU!hvbj<(w^aVh-)^Hws>jn^3+l@5O2jDJaH-Mr+z1*33H zEMKVK=GaZ~k>A5syX6|u-zCcvw&I0 zeZ==a7%HMvjv6KpVZ_Rx5Y)g8L-~guVOZ;T4bx=45-IA_2+h-!Ok+(8n}OSby+P6T zM39Yso$`QR)Q%yxub$=S#mPi(K;R{ zdG9<}n%5#^-z~>y@VI|C@AclxxI}##S;MMN$a0fCh;HE_i=rv{0Kgn{$FJf9=Y!tK z^5De7R>@48iQR$E+RM0tXmK#@0_79~y&r!x?ggo#u3yZW@wutih~2V1j4ek8xVRaf zJr%M0eBGhGeD@*1w-fT?YyF9HZ$G2tC9+~0C5JA>cq1oS*c9i;2k{xm*9`WS|J@`( zG+DtS-u#ANnQ#@k^2)cPi9&aFO#3bD6lyBJ`$QUH_pdLd;iBaEii6!XAMWG7#lMFo zjdi0hVCO*g$yN#UJKW?Yy~@2r5^z&OWy1_u${a!I<}6C2CF>c>a5*?_vVGfa3>?xi zJ-z(xK^Gwm{{GD#Het(5c(=$FWiMY9#_stp7NoG1bcDn#f+{Z8;!M+m1S3tT7_}8e znognz!NZW-F35->zZdtSu!*@{pBAFPnXWUA^c+EP^?APT3(oRAB-F@rfvPxT3RTq6p1 zk@AiuWRD0?XVeU`sZZNaBP^i5(%F338dkm-ktn&+pAn-*)gG1VTv9Q^ygZKe8gKua zyGYDb5=U$lq`q4*$nI|E20t0HRlK(%H-}v=k|ccXY;5<|^Yn0Po50)94Ag^@GxsgD zS`da>qME~{eiGgygbZ0aJ`N1(7BlBf@_$#Jea7(X)z_#fvczjGK5#i&0vvUe@~7yY z&m@)WRz1VnyC?&_rM)MoR(F?*@@T4idQ45vz7D4GnxHQox?$gIhyLOSwNIs>#-PbUv3u1~--@irq{8&}WT+8l# zH~a_ucy=E_XWaxto~bKOdFUi6uTr$B7HaTTN~uwRvJLe8L*=#R$!yidbnsV6!Gbw8 zH-uao^0LnG9Gpn z2K@wx>jD@wFOC&U8Az=C3#4pfUGGONq|LL7df*=pQ+gOA3_FMifXM9(3;8^Z)80qNr>hU zch{mz=ddaEC9BNRWM6v7p}FL6R5CYD&&lzzcBVuS z`g67X@Ci*vw*A8D&i2eX;_s2&B?s-`1BIs3bo}g)?^iEZUSOuY+1`Ad`tH|t)Yp^; zjw~K1PYgbZ8PoXhE*u(PPg51JOdydTkG*dSi+e0lsw;-$)z*Arn1ZeH z?&eGQ5x(mM0g84Zu;55_XAu$Nh2pHYla(WdeOuFwPE=nOWxtFBCKS|8-2}HfQ;Jxd z?=rsWElty6>dqxHq4nK@E%ZR16Z+m?QUKV})2_uU9d$M1Ai?=A z3KowIIMW&5eaqhf{0k`WSE*-y}U?Ps8Dk3Fr~HF zpt;gV1l1TgeM>R(jY!QHS@i7RkKzwkYBmDhe&?uKOolmZ zby>9F$RRm38@(M9#U-2ri`u5a?oYD{f*BTF#|#S~?&rZ!$j=9OtiV4@bgL8s-DnSf z+3RhubrCj5q_XD=F zT{s#I)#2J7wv&53e0>apV1bw8Bd9&(SFVxCS4?L#c+ZidpT3w;sE|^jnW9i>vA2X! zCUL4|&$e;`&DN+?AI(I3);-H2qXOhiv@jDL(ryEapGkXZ22;M3Q7Z6(=gp1c$%bu# zjm&TGN}L$K8cML5_x&2NIJFZbR{>V}+d%nY$@p|Q0Y2vg+~v>_l0TEW)yK3sYr2cn zO(7NZBQ7{cBPs;q`A;!(2~Go<+mb`ujrbsW-J{w&m4Uf9JD>Mb{f!OXJdKEM(WbQY zNfP!kZ-}uXf8&2S;J|)4pGqc0NvG#nOJMXLn<4kc13Z%VyTsraX1JYm;2hGg$4(`^U>_Qf$-7m^Z>zKZ^2 zyw~Wns=-Z->4!nn;2Z<>RWK;zi49G2=PFlf6R2Q%$1H=v<1!=#Hs$wkFuI6u6)+(a z-+2WVSz7>#KMxDV#}T(IQM-Bw!q^NI_91+%bC6O!UipC-inYvZ<~l3RAXlDWe>7N| zGA)Ds%4p^eLqb0chq8k=w!rNbsBB1%-#e$V&C)Wlh5G>B|}%RKl_8_QovE17z3uEqR4 zSt&{D2UVdj_EE4?dwnTvUUT;uigB_i6ipBr{6*myHfr?9Hg=W?!e-p;4DCUu{4w29 z+dY+Gd+-2mezx;1!E_soto*(5pMn3J&+|IFR*Dmypx~eXgrEMef?@+*#iOk4XnsB| zu74s#jr~DOrZ^uWUl+!>wE%h?gH|BE zu$e_FS%E`EQ*j8B-vi(Y+Je65@|ef>Zo*KdH=M3FvGIllIg z6Ve)oxZCT%kIuy<&)**L>N;%xxHvtDOn2jcFBVn;NJ@A}C2~6wuaOdv!9Dq#Yc4&R z*%Y=WiPV4JD9T_Vk*y?^%ci?_%(d7*2Ys4a51JiCocZvzC+A%)_7ATcqE%8wi<~Cq zY_L40vPo0?N8L&}hP{0ZY7Bq=7baW->YgD5w|$U5eVgKX2Hd7D0BDb^5RA3 z&T19@7Ko%FGfR&B{KmbBjmtwyJzf2q0j^4B9|kNuWBJi;>)=?MoWa5?$2ADs{KPu0 zChG8n{sz<*=wGmK{dCjImBg1r$~FYyXII-VpW4wgNV-gYT^*4$z0A+s^`fxAjQOfuIQY{>U?P+MCuuxqBf(rl z8QY-peT&g92ENzHoK^9_>5Zo$L$a_*{;}iSSVp}B&L6L<=XA0^AS1Xj7*NB&EF-58 zkwmML%1zLPy5!eWYr*pI!sM>(S_|uIU`eL6i#K`KAC`lUZgMs^v$igOXrzL}MuEvl z@E4m#0N&H~&a1Zb^!$jE@{wsFUVTHS{>K8XshzvdzO~RL|To&wt1?G*wHFB9HJ=ssKZ@sW^tFnVXlGAwtBgR2JV=VBiEi{ z6uc)py&@2DQ0(2(C~>XV|M&2+vNIk z2WIxJWu4%?PcPQL4TtMAmcZ%y%gNsfy#P_brPw@dK4j$a+;@Vf?tm?4mSbKjPTFjJ zDWFmavsH#{>VjL|*4gZtaI*F6O%L3k(9S@{&76xA@2MEF=s0a8Pqn_o?aKYhm@ls{ z1IrYaxu`?h455 z`rF`aR{*2Xfdi*FM!g<+WO-KBR|K}@ju10#y};MDhr2SwTZ%VGkmHncJbK@8OXjI0#` z#C}YQQ_Uz-6}bs6C|MD?3LtQ^WAgGB{BZn3%B3CW{Tt4os0hM9Cr1=oDXIkQ#BWMf zt2K}&prr+{P<4L}f`C}~Q@)pcN4svp^J;m)RSdvj>_Eo=9JHcseuvj;-18^2^k=mR z1|si2YG>-6lOG-FDJX<87@N1vWomd?sKP^%%!;5Ou~w)sC<<3r>>Rb?jkvsWIcByK zL6*8_@&z=3TM5A{=#S{Xsa52ytu7N<2h`+9{A6FuspK&0qh$%uN%-1u2E94K5^(0K z16x0~d7yxS2qw>cDuq`bIaBQ||smfTQ?b^b~G51j?MMimLfsty28i%}-V5 zFj_6rWKqCX_5!GS7t20I2IXljZe zQsAQMx@J~3=2uUq72@YBmc42oj#aHQ+mfmalEWS;*CN*@i5;hLjr`@TSNzrcyEYbo zS_z7%z(^&=`FzSEZesh<&O}AHAi4o(NeKL1X)`cuka~7m>V6XZJe0PC-%8SUGzkv7 z9-vST{*c7yWL}mv!QZCv714)DU6@qyCBX*M3Gwf&k!vqP;Hf!F=A~(AP2|(^Kx_0+ z>xEWe0NT7lSbv<%CLS0s@tMr5|KOs#I=5<$0q7ho2d*d46WLJ7`%cEVl&y}2#OVa7 zXO|M%VhOKavoR#jj3wHSRI>K|rkDT`Je=G-NxcQ-1#U&U0tJ^*p6g9n*Ka(aQlZKj zivfTMm{Vj1+4+c27?)`vEj4ZwXk94vZ;R=9q(n2ne^|0+5zHD7HcF-{#sKC3vp`GK zpYzqwg0K&BisL&!m9_p6m}BNANN_~Rro8<18lD$i<^Dbofh3%f{^#Yy`jQxcY3)U+F+RkpV z1Vn!bJHvU(ss}AH1@X4iwRwNce-3=qqjF1(| zVZzHcOe?OG#0AU?(lX#=NJ1g}64FX7Ro0C|mAD;KkJpQ_hVv>ao*zvJ2de+=eGY(V zHCk=V2ZGLPN`LT+0Ioq@3c*;?enwoYHH%0i!2Wfu0R;9yB)-+ct}KjCjsUcLG5Ag` zQ|l|$;GUiQnUEagE0e178p(~JlU=*MhBOL58+sv;l-ekncu;s{^M5yAn48^P?D#92 z3(1uCR=g@NP|y6i9;(Q0RPX_a(-U&V?tf0+)Kp3%4jrQAP-^|15=fi@{6uTkpAc7tof>ujtTZ6l`p-?G_E$)zG*y@a z&k$#~a8te$f-`$_vsh`0Np1d4?#w}gz))%cMBnE9TA(&c#rp{;*)K-cxcJjhCnfg#IwZtT{+NdlqxVvmbNE#o3g( zcp`1zPl@nbiB)?R;%{5{`fL~O(;*N@X}`>A!?GWj#8~C^%*TtKn72wx&Y6dF@4g;T z2n;0yAR_!kZRA%;=Gv9!DHCG8R4nE71fB6?z9Po){Ev16Zz5q~SI!Bsl6j60Di{L& zcdZ2oSYosXw~V3$a91Xbl7uv<@h73ulHOqqO0o|?*ddm@)@%F>Aw>m%Q!y&{ir#Dy zPDc_QbwUy$(iRgbAnw4foz45+!8K$E)Tz$M_mXEJ9ps1ROEejsSnD4EnVw-I*;BYbkJ=o0eUV0;Es)e_dZR@?D z7DDu6{s9X};Ea-|oR>oo`QOJyq(BI01zc+n0%%Uc>U-y=zeg|uZo!I^Qt8G%w~{Jpk-pV zhnpd?INgD)iQbUL-8#da7!x5DQ3jzSiFdNmA2xqV39l%g|B=ETNr$|mB0kIyudI;x zw{z=2A|<9Dd%slwvQHCc34?=&Kl600a}aFP6M|y;!P#PHu!N=5O0h!`~4Gpyri}2`{-MWFS$}WMw4rDxF$g(GM zYt1|JgT?QkOQloms!2m0e70{d+Y=LXGH6=>06+jqL_t)rvUXB~rdy`w1Lh>1v+r$P zx$$>x<^SK`VMiE%Qqf#Xrp-@eot&0;`8#@Ul@`$)V-9UUh@{f6$omDo`R$c zBFYfRYjVQ7y;87t^z$=vn$x|IsJ|xD07!mJ+MY&|wCztsAC*5&et%Lff(;S;4S9%P zTi%j`ALWp%mN9?{(Z{A+2oGNIL_aTc1vL*K{;#MCB24IvoYDyI!_kkdl#cK>4c?Yd zgh7SbvO<7fzkV`nO#vha;uwtNKvaJ9-cNY7b(vv*CUfjZs!qGrGBA#C!JwLepPzC^ z7=SA`Y$c-4NY|JhN&GAAv7?muetwMZa|a**QpL*}35!Z;q_gEc2*I`PKmd57xD-v6 zjaw3z)alZmn~{P-`$X)LD@CdGb#K<71)|ESVVpgc^*FGbC#2pP&tiTsvZZ4xkZjWA z6AoeLx}vBpdejNvkS~nd0`<-11SA0#WgAYQ)T%k~iu5RplldjD^R`AC)u*glSO5JxKel z(OB6jmI>2SN10Ys->eG>f2_}d@W?YY1sZj@?{`oTec*hEPXNw`^d$jX1u6qZ&t}fk zdEt)bnv%{(qNmE?hC=&xG!~oCXV2e&bJ}U#1A=eW{d#5ISq%m|za{$Ghx#fQOE{o* zZse|M8v+n~Gy!Oeh_v7{hh6h_7ryP$xC{FMfuUvqgk5s7aR;g*<9%)}Eq`FHn)^oq zw7gFjleNVAwRr7}_=|<3^wrC2$E9+;ypXl(;rWS#3WK0>b(psoYk-3woG6(C&nrp* z`}vMivYpa85Kn(iRrB!3ChOlldHO@hTWt{gdrHcKkH=l<(wCNH77$YZug;BH{{t%M zQ93tZ{wP8uTfVNjv4Us6O7}i4=?Kak6KaUspFZ1F45 zXhe(v66lzi0JflYplo%*?)$)|&V>(B-&e7T0r0TT$kQ5?A2z@s?thSG(8MI8 zdI}7H#)ia;1Wd!>Eh*JE48TKq*NZ2xtzDiBEj?j*w3tV}fS~f*+3AWUu=Fo_Zto+d zfXy?2Xn#I^oI zfc-cwEfks|(k%1Y?mw2Nbsn_;6LKSH83M!20JIE_;kp2IUPjU&&Q&?ZRHJ$&OwBs} z@uO>fg8<-{1Ge?UAmuIZk%&v>lmSFgd?2}e7T3skQQN=|c12j15RVC_np4Q}avZW00#{#8{_ zX?n^nDVcwfN}iekJ1ypG7h*D1QE@T`{`Siq%K(!5VeVnl zItGSF3rE5`lKL?@;ONI^u7w9^r9u2h#91KOe`Pvlz9LV5G#vBF;ZN@QwCob3oemg< zR(f{lb`t{N0QTUB^rT;zNy%R$W_?F~b$iq1d+6r9JJq);1itOXV&9RQ%bk=W(bVr} zo$C9besqsTWqtWD=EoL-koWLuI_T`^f9Dv0=&w=xBh=o+6CCwFQa@4|uY;7GnfYIW^V=n>inmn6*@vQEO+ttRSyHVKE}q{h3{98iHHd`$^Ft>Ax!CZ$GyE zhw(8N#*0%K38r8GChRMYfPt;Q?HjlYy9NQ)%{ppo@zC6qr4_7LhZRQF|o;B*LFjt>Li`%*~yum9-M_ZBL(*q!pV+)}d<0eJq;rM*Sf zIM2(O>#{an*EiZB>($cN;Cfr>Pik0RLC~&67Xnt2mKh)>&(#xSafJ*f6@M?4>`u(u z<_q#3q(G2pc_5{?AgW{kCy9@02|a06<^SYUlW(+#*hUZzV)oH25KekRMSRFGHzzf+ zjWdUV(MdQzx)yB+utI2W#-trYbClEC!GK}~DD7#5qCJCSFgkLI`DRILbw^IKcT4fg zk&^%cwd2D87_+EcO&3pL!Q>|I}PJ8_jH;DYH9kyzKj)od2`{#GuXwXt0^9 z`*#ku|Ci@d=B(navCSf#?Zf~58<@NEGY|;ZWJK$;ptV8`e>xvGmrti{mcKtP%S&74 zfm^EudFt;zi4tgm{@ZIF@06a={&0P(re25z2U6lm*)Pt@WI>k0KRX%hu@U*2z!X6D zNj~N1|1(P+$qz7URAC%Z5p%*v|2dx);rA@V_-MP-vPmeClN|IxDLPkd|Ie${_)n`T ze|2>yvD}F%b({gvUMl#$2X~^U-&X;LUZzN_2NEwW%sQ`8jZwU(R8w*6CYzrei7RO< z=^oDo?pRG<+TKgGqW`Y~sC+tVk$)bfhx?uZ|RF@BdB%{=Hs%nx3&UlNkJ7c$i7L5=#9RDGO;o zBmNEkG>3Wy0kMUklDbtDP;|_wP|n`6&X5^yGwgXX|t=~JP zqZ$CXuJB{=M>$El5rHp(aSoylXv#0A*GerZU!{Y;HVl z>G~&|dVe7HeAm1iHy2h%^<0eW49Q~AZXxnTDzx#~;)#=5VGy`$g9QP*mihx?#zrf% zS`enEjVLXxEvQ4%p6#+E^9sKy^iQ6Cm<4DDZs_2rhJV9*vu!XvV2a3z_>V~X$59N2 zQi}MD>od6}TpJDuu##wT&>s4FrMe_$#EKk6YBB>v+Y%rTt)MC&W4&V%Ba<=*Y?>RB zTg^Iq*I7l+7XMNHf8VQ(3QocQIu{JePn~7}B0q0!VoY7HXERoEd7w@5zaEx6BDuId zpNb{^TWzd4Ayh&?BHMU)?V&%UT)i-rvPoEQ$Z~BsAb^xTF5du(=e%-KIsc0ZbAKyg zmX+*hS2_G|D{lbKf-nJ8b!&$SU=IDrrmtPNg&) z8*ASzSW^5tvPl)LQo8Cn0UF5ajJ_*8Cs(d|*h0>b5V46aGu#(g{&l z92z6t;NDTk5`%qS-sF?A(c;XbuUs2&2tbe_{ABVY2o>oYsqEfHRSbX%`N(^FbEjs? zC6#p5T&sSYMgiR?u7`uz@bPrgd~I&TO8YO*Dyv^c`%4=vtwjHf$L*^D-&6+-AN)b3 zP*%54j++xQ1#HUXw4;0xMao4ELQ^n}9*rMsldcJe|58J~b(CR?M&zY{dq;cz+v*oh zaPBDmMd{k($N)gcGx{S&z#p&F4%cD&RWI%(d?lK&CV(id+Y4g>Arp3mx}U6TDG`38 zH0SyM0;mS}3$1a0nu9dLd?H>Oa}R}kU=CPwPbvUq_if7#VEfk}2myO3E2aaD5+S74 z&aaKOm$zte;pj$Q7Xo2v=7iRq^_L>R?gelR$TQ+{5CasEwo(+XF?D_r!UHaKpEZI>ez%c-=E=WYr z2VtL5snwa$q{6f0tR;J`RsV-ib417OhSeSfo-zP9d@ARDIc8p(O`C~a%{#8i zTxUTW9Qv2%c{B?6;XHpiQ_r)0erFPGEgO03KE+utjstIyovT_?3i|H{_`GpZ~ONet*AU z?r)UMrku7Q;_bAWE-b510O5z@>6E;{#lb854?^JD@qqwHkF1X=IeoCtCWT{gFs8&b z)gvR{Y$^@!Yj)&VF@5eY~ytp6~gbJ#(w(dmsPq(H{?V zR6pu?x<=SOx&BFM+w5E~7OTJ0R=KYQh$7RN5|{XO$xp8ekSC4eJhLW|lBMgSP~Bx- zB}#RTNjmD{alPPb5jCkA++H91B22Lso6j=fX2Db=z@5klf_T#mJjc40U#h$Os zfLn^8gn)L`aiQ_FnmvOp?vDp5Pk%0zN}ZL<<#^oq)55EJ9-qzj)t~cF(Tx(Htpf=S zM!dD6c06ADmel?UagB@Ym_casa{POFHlrBrn4JGq zl9eY@Z7@bZ2oR3;7|8)}cfD#owb!HpC{@M6g77+km^VfIf3vh{Gyk0$1rAAD>?bc( zFg_-(9S;Z~RLoDrUni{E{0vK^`XcMw1w0{~Q{DiS_Br+4S5tTssGla#C{p44D>p4u$uacYIK zZ`KOFS=Uik1|X#WPBrYjD?4RLc{QaRu31fk?R&5ukxqf**!F|Ue^jBMpvJshqpAA1 ztMt>N|3ls4)kNMTd?o)O7fkOsUTIybg7r$1($-NE)1lWrB zV@WG#?Q>xXR@8N_9S;bE>Q@{9cNMa-D*{bsz-AiTBs?0OPmf?DObn!i<+a)SH0s;^ zK6nry6x1f4Qivd$fdOjiy@;=~GD~CL9jL)~3(igh&@ISzv0rR*c@^y@>)R>i>Ry=K zi`9lJaBb)z0P)`v!6)4BPpa1T`JG*}qtB@98?}Q7|6y!H_wQn@2J?Pzrc@ zgfLSAd#D-U_FN;F55w<)Uy&!g6F1*HowZRXS0C(}hnpmx9)#vEs=B7C)0S5<*~CXG z?(-2oYJ)KHZjRA00NsRcm-b(IF<0AK=eG+dV-lH3byT)2w}XaUeea%#xvrR8Hp3Fu^^W^$_oq(Jt)yzKa| zYu~TSr}bB+kcf12SFg5B_ZfgJS;`Z)Bq#h*n@G+SwMFGN9taQnUM)ha_dyLek&UZr z7xDfI%aKaJNn@=-ad6Mq17)55wq^g{-mCssmym0!Fo$IK<25JS5eNM|*i!MJ27UuD z0hk$RTLn*{fi>$HPR$7zPuGqQ1VR&lV$&_|85bUcK`e+H9e{`c{1`A?oKL6Y-+piL z&6Njb^J|5yKgq6#=l@*VTU2T7ym0De+5d-{QRq4YAT`UjY%V{~X0v~E{J0PVYy`POZ|FxBS^}^_Z){c zYDG*asSkVS{8Um$%G&ck`C`qM5I*cWzK4aszge=(L#389w;pE{8DPw;YNDOM5yiD* z0|81v&&do#=;x_yZSI{)j%%>x`s!a!16aL1>0=q;GNp&`1T#J#9+Z z2ATtVf%`L55MUpHbJ%kT9x#-}fxf?+7dpmMx^W1TT6oz5qe6Ch@8YaiZNE}DwyRaH47U=Ew&N{<)VnwYJ3 zO_r6P#7*)}VRv`^%8gIAo4Dvmr#J@SNZ{+u#XN8jdDLwb<3RG~{eZ>c_6Ar(dKVH@ zp#j*H+Mc5z$sapxy~e%?oI_FDN^>Nl4dEuOE8g7H4;a<^vZ`O;+=n$Et$w{;LGC-M z3-9R_GX!HIHL#4O!>%pW1YHXuz}`Zu#C`%N;S8E8lN?A{Y+wKeqWRbZ#`p39*b(zt z55O~KfgVn!=-0fZ|8VX9yxpsNItHLukZ$)rJZWmE+;G4FiH}MBFK5c&2lsdAApr3w z`OdDK|JJ1eAU}U-ldn5@_KbB9r9c#ET!YfC`pPyW_q?k7fv(pJ75PT#O^Cb0*WlDA ze^C&SArN&hjL4=udSpdV|ACLelM~&Wp@#rM33~})g!};PjSW?ODT^@;?B`JjfhQiu z|9U2soC-%OjzIQ*Ux}}e2Yz)7K)CV|ePtVR=ovGoWW#-RE@ipyF{R@?9$Pe`3)7=v zLHt!x+j>~vT`QS?S}KU>Qu(j32Ob1|ZY*VMxz9^odwMJg9YuW`m)M@w2KwfF)`k+I zy8Uv!WIg_w+9CAcR5YH=a@iDXo>|&Rm}?IzGAjhy1s93ZqfHTk+aP~Xd<>zas;Ge1 z=10Ut*32K5cg^*O)d5Kp?9WP)`q1Z$n~Blxtmh zL~0frV&UjmouvjisQRtPt)#dSNpU3qamcm~(1z$I2r(+vva;`>a^EVEk~b*VTW^}| z8w7frC~D7agcGTa8rjnxA;IOOQQ{-}3S?drVYiV5hjfmV2e!oeKpg@Y5i|g@1Xu}> z`#R3_5a12j*Q_;r2U7rLf|cLJWTg@yQ>nMdpR!+~+aUHnmHwVKJ7BwupME#Q?|RAr zY;0FHCdLvU37`F=KzvSn<88s#B?YRp!7?KHbE8RXXQSxPgetMYd1H5VZTKNjQl{01 zTS3Slsd&lA2P04~dCwkww}|-6M8Xz}!ugK~66+JN2R6>jYA<2^M^kWNx@rmf-Swgk zF{}q&J;QQFte6{*b`^<`R7FbJ0Mt)Pbinzh)Pvmc{bq9mjLIKCTFLtxiZDqfq_L!K zgiKYDW&nn7En1yXPZ@xZZ+^N?4ra5Ph?9v)oZ@#hV8;N|SvBlyr}Jr>^$#RHAzND@ z#nrjU{WLTXAP@ijO-b6S_P4yHvcCnX->r?c{uGg6U=mL&QsnGp()s`-A@(76px-%X zMBhpHSC0Rrd1*$fIr$ho-mNsj0Qh16$}%5RBt$7Bv79w=I#U1Gh4xvBdwR1jdb zF-ayR(FOZ0s8bOu@ymg`XQ<|Xw8`+4dE0spd7QQ|lOL_W)~@a~1JK&&j_KJvHaKv3 zdZE#2?6nW}{Kr{-<-=JJK4} z%NN038_#&!XMq}bER(RN0GN#u6@U&wN!CG8_ah_W&DFA5l@r)}K5qRERC&#@0mHvd z?F`W>v4<$HGb2sX#aZoJ?S-v-6{{6ECSYiHniMDcSZu&e;r3fQyJo%Jj@r4-F#zpA zt=rd#$n#Jk{S&i&N_JdqxFB>MG}ne70-@vImQ?aLS4v9MBip|yGU0%Y+J3VUS^vhx z0MHKGIxv-aF#tBbbW(xPdcU%xJOScD#D5&v!cj0BN)g|9T(V}WY%;A9)j@VRw^I)U z-B5l>L9&E6#Ti8eD7xMztGd3jYaYvI#kIN+*iiDVkBY_WFUkDZi{wB1N8=cP{m_WW zdk`lc+emUF(y8KPgQqR3S=WXi0uWVfr`Y-nI(S9Z4pUH%{@d-LKS@z^Qbms`-+xp7 zBDzNS+a%@1&0b^AaV=i{+luoKiT(4C55LDDaYtGJd=AJBfGL2nU{*Mc>3F^`_j&Lk zfY1V-BBG?YXSM{7$rT{jyMsT)F3iC5^>6FSjlb)uO3R@Hwt(T@3f*ThVXMc>y5R2JpLef9l zfM%LaEF}UC(|Jbw4i$coBDgF+gpkx9+!G;+kGJKVSdN*;lK$6rl_FOCOzbfr2VdpB z9X1HC(}+;QR0-RN`AOTtY%6iqmUR{#wiyrpd>jK1!8JrBJEI~SU!Bb;JPWVdAd8zb zszz|Jx-cZv{Oj`izq=kp0PHB7s)QJ&b|@*hk|$O4*{Qfe{ZID4W}3ZrPkN(N z@RY($zg#aX(a)|?Bx2o$#Q$isY_>%7ABh2Yyq%N=LdAkKj$~kcsC&KpaX26V^9kbz z(@Cu^%rTc2w zAQ0d%nJcw##-xeLrCc@bL4x`%B*#fKt(1 zlfTeUv?0zZX!Lze^Ky5m8vWiu*kh?=;P@vs?D=WRw#IGvU-U=sMtD>RU`yYULmeT1 ze|lUnpWoS$H@-^#*30^{cT;lyzcQDR+BIQjl`?uo2yQ++U%9Cyu z#?#6^SToCt`Da}98c_pFiUuGg5c9*h7?EUL<^&M~_O@%o4*^!01Ht8MvniDemNX;n z)$&GJa-PgsVgXThPLO!J}^sz?B=n!0F+$A1r?Vp6re5jx`Ltw2`<# z+#{0aDEh-I(w%F=4*?KkSx(br|J#!EPkG*5GyqLZ9m#z%OV&Tx{$+zrK>XVvx`7%u zK;vX~Bl3iCJ?5(h4HYjM3lbJl$s7kpzVqc=XrJ#U`e<+q_w#^2Kxj<9070o}OhJ5R zJ2s=u8jvX-ZJ45YD!=vFUtjy1TSx2YXjk`*0XW*Qhx2M2u~6e?MfhO^xX|O-3);Mf(wi(`w?>zZCf1fVWuQ|g8S1`2sj3yr{J!Cvr&0X|Jmt` z<(wBLg8ctB`(ORb+^+);fsmkXsIbm&zbx3QYImhFB@~d~!ru>?W>yX(9OQ|3X^OPJ z%EK;%i!VUCjhJrQxHJlv7c%ndugU~aQaWN3xIqhF_dePeGzGg7{fkOpSXFJ|J8N?5 z(d&sZqk0xWUW@(byZ6Hj0T@%XN0@%jPiJJtirF&O*BF~lOYBO^TK!jEV zP8siOoAgJX|2WdLqsEQUl-y8SfIwN&@?#O(RUOv(Pm=UOgm!dt$h!G$yT*+(Ae9R@70#H?9)3-GBXd^`0tC=XQS+5B z=1GMF!dNUW(5}i4DglA^=V~sV4yPre*`aQwEGXUo5?6SGE{XwPXsfLvQx(tRN3Mlja228K+ z58)?$CU*Zbikm$*8KiE-<_dG*+HgYv&v~2dM-nq0^fw^!t!xSYlr#y% zh?CQz$hFd!kHgb zOzbl$MT(a8HFsgx&gwe@aK&7ynycnMGgO7Z^P+jjEO~TLM8j5Z6K9+hM_`?}oS4+L zO&_I>DX4?f9FjG8_lwd7kXWbLW*w}AO>ovbg4zGj+rgmXQ^0-55}1;MVxXC-KSoW- zngL>}3(tJe7$Ef>Gm-C5xE_}ukYS!UsEYH$7m&{|z81yR-$ug*Cj5Nw|MeIB_59xt z)V?zS`v-Fz--BQ$rCud&npZx%c03>u5PxO;lgb}QJ6<7_jT)Mvv^ENRg%B%DMp+@( zZuyJASmfoPTC-Y-Ak$k}c>)OWJ5)=tNAQ^sc?2G9Rjj#UB$+&tgJL7txZfiN0qvd8 zCxvpslgd*;c<81aUe~1%uQ-mduM6fFfWCqsMDCeaW-{{LRstX)^Q>~Gb_56(1=YQ?~u31u4@V1a*Gtxidq9>%9C$wr_38PL+y^gJ&TI}6u_@i7@QWvxo zw`8XHXH_TkJ^U1^rl9d3)Zk+(DkV%<pT+>oAdUBX31P#IchK-6D66e;P$ zkl?W4;vCaz=C;1=9Cza*K>z|7mi*n8{U3=4&-q6A(jl5iFqBxEL93nWyNHG8vQ{76L#P5Y4R0hQ?XrIhWbm)>?)8EyAE5_?Tr&{eG zb8M_OM8@I7{w_?9?vCnQiT-T0G*agx`PDm0760S|dvC`)R5iUY9Pl6rfIN}JdByJk`b#tu2(Z>LtY|yg$SW#$oe;v?Rdzu3!!c+|dGCGv+eg=LMP;s$(g1vN{S)FM zm)^bb-OcPsVqJR#L1U(zm^Wl@(+s`tOEAC&F(sW2WZbTa! zHdOzp%_;mdB1B3KfL`T`fccl0!G zx~aXWHy-y}?;#LkI)tAKGb!!qsaBcV@5Uw&+PG1rOFfIn*w_i$=v?bpFO`kydVQNVJn$kb)?pFSnR4lnx zy*{=brTImc0T99y;8Z5qCJ^;=LUZBXi4y!;8VfVP(GPWhN`I1){B5zH!Jk@7a5%On z3%8*P54`_-BP#3|~~rai;Pw|hs@H)?knMpW(Zw?yG1cq1Eza3L+22(t5$B3GUapj@x}B$pGLC_}=+9KHH8Zew|Lozb(4?9WBh@ zGXUD~r}8N?BTwiV<;NaVb~O;W@TqIZ00LCXd$^^Fe>*kVJ*75R_)`g=fI4$$Z{UGX z7B$rV=cnT~0Z>29M%e5VD&9q%02MVcSxIoexw~V-8tq&TnGpQ^wnTsC^f*~D_XUHp zU@|eHq#u1^XzGC8{nSMW2&Y@zr+`p%W+Ej`KtkCf%jUk415qcywcbD=k_-S-|Jlt? zi7+nwaPhk^3a|cm%=n3C`5Y$prhVJW3~h56<W$K`6VRImiyJ7ZiMO}{v+BiI89MWEhWr}83_d1&xXPuEdUH`R?>S`;Q>Wq69_uT zK@(%HcE0*k(m5Mq22#4FR82fFgYhZfbIBKK4_R?C(PzHT;@906GuUgf7mz?{$UOdYU~+^AO~T0)ePmNHz2Ohr4F$f%XsD0N1((0mlGz4YWbW zAafl4rewbzmmN1Pm98uI+hw3fsCx(alyjYfIbYK;$JF)p(QI^g()85c|R7wG5DcA|)~=1I!v!8*IWYqI(l@J@*9y zAwI;1WM)ieu2jv8t_x50Wi-d@rVhqkT5nJvj4d`UI9$}5AoM6oa9skyvF{ceKLnqo zH<$r9njvtw!J$@%_!Ax%{EIL+VN5hU_BP3_Fm+{c>T3eKkQ|7b@c0B2^h&y5n-Jz; zz9GUua6>yP1jsRA@ukI?GI@z1;5lG#4MxL_(Oc8ga9eX(s(Ix|+Wq&#(rEzpL!*Q5 zL55?gq`ah+zEvL5U!9doR~s5Nu4}^&0h0c#DA~`tq}w}6`TM8kLO|q{0=H3vaFQna zLLRg8{>_(4bhKSxhf5~J8!H8i=+_E* zPNov3C{sXCD2t*)y`GJ`U%w!LkIS6)dm*cQ89P<;Sf+qgrOLjyUL25Wf!?-kdmqcc z<)eg&t(1!9TEAe~?0p>r&@7}{JP*WWC4Uk89BN!SNd+lfTkOc4K9CSVvZd}lS^u_# z$ToK?_H#3nVeeozBGVoPfKahFAxt;Zb=S^8jVlelA^}vWXw)}Ez979dYNG!#jRZ_l zUS^IR!7Rh!FjFJY4c+f-7aI;LW_MKfq%rONqV~d|XifFp68(C!Sgii?KStd7FWfwl zf6V0lpUvxDM^N6Kh$gg|Ji%D-pI1+K=TBH!C>%CCYkqJ zRb@$4uC`R}*376e-55Xkq1C_uHXuDr8*T{x1^wuspa(znFA)4PeklX?Q>zDP^k^^! zEc8gNYL`n@D%CA7m3Q9nK{8^#ZylaYCXx`_o&`vh~gMQOZpE*l1?lB^{)0}QHU$6`ai+X{Nj-!m(@oEG9Eh1S!(at{7l1+bMO28wH>7e&aG%HlXGkynRz?&feV9POX1{J!PCS| z?H~Z$2WU|pPyo|*Pw5|B^vc{jy|=Ai`{Q?iFuS_B^~ncc{+C`Bz)|L?P|Cf56X-wm zRdd(4&vo9Hx)uZW3{+p}ZFal5K2b<6jrB*6(`g~(dxp`mw=Uvs(tY%aZxRWX`hD^L z;tSrpz=c^JVj#hUCsGM7Bcy!Lg-y*r{MvAdujk6iz4>x5HHDmd&B8htDHCnl-xaos zz5?#(GLovChUQ$E>Ec$wTD&fg3?${P99tjnBunLO=5_DPzCNNAtR=sBQjTC*ue^W& zoifdn2S7G`@FT1gY+~e@v`!D*7^{pk1RXax;>bp7&kb&imf?@zCdO z(4_cnJNc2O{Wz&tz=6dp$2!OpEIoh#nIxY*?qfHd6nkDm_N01P6+u!5t>@ z8+g}G`1`{ezc}%)y50hi-{~K(|ATd>o%35ejz!C!rrk^UrGW|v-+pX}lZ!&>-BLAP`!?f(LpVe#P zh`18kKLr331PmNKElh##N3g5qimM2BQN9@FXYGSV#*kS6ED3vilJdYIHFcN4&uLWK zm)Tp*a0LNilQ4$`+&o$aw%FfcYp(#nz=sE_$uQT*?5&kBkS7?Fc||^g@pFMU_1tR# z0U;4CFkoWpEGQHLQV3!7m(j^V5eop_yG;jfW68WL?>f28H1_1K7XTU?Mt5B08g`ps zgIV-nX~I>53t#9tT;RdImw91GX)ZjPq2}*wEC>Fm zi$4_hYPnOyFsw0tH$0lRgctCs)c{>$VW2#&p5;wkC>+`iEH``-un=E2kWS&}$uei> z)?tz0JbDTAo{aU#%S?;fd8(?uG)%vY?xUilIc;l$K;;#6d z)p}4^IM1cRRiI1@)dgm$X)pjm+PV=`2dslf8SGE^Tx1=*|L@=XH#>bh$%EBTNAE{b zyA$rz{>S$Ofc+3T!rw~slMuaW3ja*Psjg2BP$RuR7V=3Dup6Ri8|s6W0jW(NcXJGjjP?0yC78sM<#IB+x)lWLFrsBIv%^iI{@LZU=#S=atsU@z zQ`JJF1@=P-Fz;M0Bp2EDqI!Rao&R=y=QT#7^=EFa457~@_viDN$k{b>BuVZ}r;M`3 zPuu!c#=b4z{Ag)AEI6M$-vE!d5n$QLabX)qp9-?_dhs=L@i@jv#xZhZE&n76=2`} ztvZwItNsNO_zctKPY3SY`)NW&+ivT3*9rh^2Rz7jz{P5=GLo)=?p_A=&c&@ps_9b` zmJ7L&Na$`uilg)=2p}(>%TPx(qE$4xl?^m~G=3}LEyMhk=I1bvt1WL)5iTR3`=6Zy zsC|9-1EC6KjxB1>mn%ezQ#ZV?N*#KRH6(-`OwLB#$2`C_Q5sX?d0c2C;pf<*4{C;M z2s`HgYZk88)Rx5^i$uvd)&9k!6R~2{>uiJHJ711vi#^e-XHY8FB_L8S`+ z0D?e$zq_CeaMXkS$-*p$JD_@*A(S9Z6XnWiS59JA3IIP!euOHwd|4$rsr21JzQ$YD z#cg+LMc5)pswOvz`Tr!e(36Ie#51%b&Wo5wH(-YP!JlC^4WB8Jd@#pw1*AmuHI-@4 zAo_5r42}#X{VCz|#r8H!yKZ!J#b-VINe$>Ly6eXo0Biz66M?IFDEqRgJm zjyy2PGpWVmAm>!GXKS-CbMHVeHZgavaO0=cO(+7V5FGif0hMX20Jr4t4h{chf4l6R z>%ck~DhOKl6qcPM1<77JIt02>0Ki-_oaCqe7<~V8)Vvv%+)RkaM;~uT?%<;IP>8>b z8T$7xVV+h9Kzlha3)bc6nq1n|meiU)dbB|V{8li-*dmq-GGeY$x5G;IceR$X%>VlD zy^#zKmy(Hz@nn2*EXhkyi3*f?F3!&-4;Pk_oz0D;^6-9AU0aQ9bKk!_7z}lKxDZT; z$8@a8{5PT4R#-) z$>Jw!$ohlDBl~+6nwcBOYGJw^C96TksX5zm+YUnq;c3}qe;_W&e1&fxX7PSZ!R-`` zd{)dK&(P|ib;|0ET5&8;q%}a?ZnTBl#<``FdG@yN=NK9tN`@5xO2uRh93CDSesR04 zEn*C|%E@+rKMW1aM}8p5VKZLAwYAJ{cqIg)$NLuG^0E)lGv3HRctL0szlTx$kC#&u|HGwn@(qE0YEn{OJ{38g3SKR+xV_KTg#owE+xn zTUg5_Up~XyN7#K*VE==MEc(lV=OF$vT>D^~qLbzg!;8Lua&pAs~Y&?G%I> z9piCdr?}`?i<~bJT>b57m5EC7$YN=Yc*l|L>RZUodS?s_(A;Ed_$_ z?!WG&{_Y6?ZGgNI>eX?idkFYNn9KxaEY;-B`T~_SN+3=3y1&T6MCl6SuQZZd|(KYimenp7c?@$V0etD>FBXt%evlDP*@ zlFhZX!b@L@fn|_V!M!|JyeJkeA?>!oB&M6vy zv4k53SJk)v`FqKgH*O{u5M(c0o(>!yC=6i1dMSkl?&1azk2i1u%!0dX2m-(T^*<$_ zeaPPkv`e@{N_|+lsslk|j0?yUV%C04Zg`}}cA@J;tA}&0@KdQ2!-aI0ywU}*{?ihW zG5&7v`@th>?o&~Zd31n#QTVZn=%+MT~kqNA3zRcK&C)c`V-S2`o z@M6@qDUOa^Hvs?Zj@##}{hR-7(4Tmtb>ir~s@v^jy+AO_?=;;zMwypm&H*F>-VYTH z1Gapv5Mc1=023EDwF}#$Okdoa7hMur?1mXCfxDcY!)DC>PMY)Poc1$7@z9tR1zGV} z93C7Rir~KjLhgPcHt(LuyPeY2<=Y~^$z$=VAWUwquO`S$xB}=e>&meY07v-Z`Dl)l zL-$dn0)r2}SD2T+C`1MLx)&Nnx`-v9G7ip-Tizbu&dvuP|9q7$pJ>8WJy$+P6y z64n6vqbROfS85VWh`*i3RvW{NEo`k{|LX^9$zx2&rieLy2~(|R#XkeRu2J&$+cU*v ziXcFv=0kw2^}|#6U91)QEl$i)55kl{<7E~xvnxE+YOW*kP3CN2tqH6NTAd{Rt*)_b z-j<0k`1ONzaCj@ZH@6i5t5zeF`PZAjy?qw%pPTu~5f0kVT)*H!NzyEG> z;mS-hGCqduYA`f^1NrthHF@#dL+gOC0$RNModUt^ljj6c?r;@C6N0ueH3k`Lc~lxW z3J&k@OSk@=j#9=itjU&G26uMXn1X$s<<>RB0%!aB2m0PE_Vr)AJ#_u+PZz$nMAnJ5 zu41lO2d|UO_2=O9O=c8zF8n7a2ArA?jlz6tS^)>J zQeC}$J^B6r^?Sj*FW(03WCjRh>th%Q2%m^}9^}WEFX>KG5?j+V+_oQ#fnGmkC>pl@ zer&k^zjEh=w%xsj8+DZcP~FMl;H!=?j;^nvETPtPYXrB4RlU;uZNE9YElqh#%iT&e zjqbN#i>6c=VzW&GRw6B`I6~TobfMpv70wHnET4|0{Kfgha3IRrH`*$q}_@p>^fuAKKytwO`{b*vC zt#tQff3pi>Yv5QQ3sfOsQg@kVU8&*W^jmm}S9xkZC=6Jb$8wRA>=~azv$>)9D`Pg& z%#<|hUk0KZOXlB<=AS)T_tPMFJA~O@hCe(?)(YnTfq`O}{j=*DIS0f zZiJC!yS$ZDaA&PhDX|Y&*k|`l80g2gEDrC&xRGa^)@xJ-bSG&gGizpSkh09=m+}!i zFrKh2y&<5+Djx|PV+h+7B$^X$T_pgVFf5vSyvR68u%CI`MsZ8bOCY9%{VWr6vhK){ zmiSbYhl|@p{Ffu@T_WB}Gid4xk^JKX|6RIqHMIT#BB;aX-y$G$PzmoLJHGnHbp(RG zWM^?P`R0qyl73RI2Kok>I|K0205yydO*MzA2ybAT0cuYu7So6s(%}?f780=`TohBo zZW*1L{hR8*DZN;;z2jAz-y%(O469FtKtSue*UITm;hnIb04^u+&0t#t3rz_N3sHmc zPwWd?=@lS^-2N9!MnfYtHoi4bBf{?k$eQ50gu;W4se zZsSf^o}EbMzIu?%&XX~K;Qeq(YXzmS$%>#{075}aPdZgUiXj3UvjQypt?+2T=9Aq5 zyMEsy89G&PXlG}80ziw*0jQW@)oXy34%JD>qc-Tja$J=#RH$>e)trZ z)e1Q5R>e_sfakQ@bT?i9_U&Z+!bGCkf8yeWNcjtGzQvm=0DDZZCfD3UV&Bh2F| zf<)W8dg20rk^jT*t1B=H3sTE#8vmF(Esm! zRjmgRiqVX6<&(@9pIM_+#@co zB|-KmeLSh(Dh8NMA|)Pz1`p{&BY13+xpf_$l2&B1pzDA7ogeJXttHQX_W94KbaDLc z#07xly=OB?uJjlE`Re<*YHpn6*wtl!C192}mFZtY3Vrudx_g&?sk7Q-{wpv!eYX$M zo_=+2HF9y65derYj2XFX^% z8^7lmD-zE*?z8V+Ek!2D68UY`+OO5b!DU=7>lAldwM6f;BIf&C1j98_9LQ9{tXR_n zBK{xF;<`c*(6VsU76E&=ZYGmx{$o>95y^klduG2MAO-dU!GI;=07fRpLa=aytuLOg zCHG~11Hw*C6NK9cSKrj(!R*Czpr#-1sQ2xbApaHlc@%49SR@Q%hF z(4|+&IC0g6@82zMjd<4&e$=L>BjZ=gF$y}JFDEq6>1B+RJMCgCzuBw|Le09Xe=+&NDzn_qOD4n)?FjRoh^5f2wo~>J9Fkm~Hf~5hhBV?gi#j>3yooq9#3IVOI z57EW3ED^hqLuXWQGA>8PUp;YZ-VSIsc8?5a+<0vQVW5vf38$)vR;uiNpQ*f(-|0WG zp!X9)nIGKwL2+s*nSqO3XUZ*?cq*Di+(_m$6)82}1_?jIbXrm&YIcyf3ya? z1X(Zys9Hqu!=T$P0CLZ`x6knY{8#C7Ope1b$p~^pmTLj92eq2NvDB|eBkm9Hr!`p3 zSE7|=i!}1ATKzcf-#HgDE#u^@hFB`3TSAv%boJy)zqg))bFj_axm~dGo6~z(Q`6T~ zBjaym-VVFZfuHl>Py(3fOu#wtx>i2q-rh3~xxbc1nLRMD#r_k(!rb^B1R}}|rC*$r zSBxGJ)3e3C33%25Ji#RhwG91{}^{j zy(Z%yBV}ov!{D`>ll{r{iQRhc67+N0jGwuTE5!XX-nry%i2Y%{{fc@D^)z#10e*+M z_nT$oDUxJnlrx0HxPtv4&E{>9Xz_n~xIxVda2N|#J52xC)L8^*kW7G*1+6Su-9~Dl z^-9g(7?yta%IG5k&SMAjmF0tk4nD!eMWNYG_g;$xM@t6QS=AII}avYwPmBFEqG(z zzr^#%iwoW-u@3DRqNN!%cKK^3PxStV2-Dn?-Dk<)bzPXXU?ATDrsOKx{}dav)fCRg-^U6$!JmYr<)+`o_O+kCD0SKI!0MJ0+y5fVL~6%Lr7h-<_xL zTw9~8DPgJRro3j|d!{4~Py3snWkHt~p?Xe5%3)mZGo<70%2qFa;(eWGU04QiYF%ij z_MbgSA;Tl>c=qYh&ocH(McnmBixtV|<58R~jR50F>#z)41+#H zoK4HND3@^&8%UHp%=am1?0J)W|Igm}0l1%Ae6m^n*ioG!r|$PT4Xuh zCqARX2LM9mp9ugn6fJq@B0I!^Gb3&bDnj*Iz(;}TGG(;KsLOzdCMiAYhgoM@{lNrW zuv@cV=Kf@9n~3;wWO7(lvAD+s?scZBYUz8%E(nw7J;lh(B`HL_h@XvZ)*br098R-+0+ z_MHpvsnJiJhwbD!sR7ce?r+se(gA-=b<0Ki`r$}%-Hd?8$JOti0MG!WT}m>4bGL^j z;uND+t81sfx`A#S|0NP1i5moSg_4_E0C*e6Q9HwJQw@(B?nvMu`l-3Ty^Ge;zuwzt z#MZ%k%%ovT#-gE1U>yQ$q;)l{00srVB%k&ui~Ki=T(hgegY}wsFm2R;(F+Ixp3j5T zs2*JQejgSR;9_3)!aDx$An4$j!1Fi&%zh+J+LjT@v;a6AW_Ijv3JJOw2$~N;Kw+R0 z?WF~vy?2lM9$*1L4v3}&U>hO2pATes;&iCQe*Y4M+uNxwx|{3NrAp1DaLX!C>ZVgL zI2|olL>x5>4xA^5ldQPo?Dw$>07m{_D(2qBG&8Q*gVlYkgKZVCB9j4JS^+$t9^`6u z#Od!8pk;g>@XuiU!MKlh+gE-qf!kc)NY>d4T?U*M%6{dN*8kYOxA*t(S$ms*Y0dDE zcp?kL+(xXx?u8Om)6WbZ(|_!_5fgG|+O}r776yy|XffI&SM2S|xqfdpfX&((7l^M> zXo@{1&~CNj)M~~7SPvdAd{}5U+2cVN8+YM+6Z^;K>A5Ygs{=Z-gPUn%bv@ZwS&I_D z_PJg9w`-!jz8S|3maM7^(S^AS7g1WC??>(`tPmto_lk4C|6k08V>JfAbY5Mw#+L{S zEk%v2*B3WBXK#*G0GLYFqv%hL;6Elz$)~G}{$#iy;eKa&kO=NVqyU!4T{;gwHnpY4 zOBI-&)ze-^{!3ii)zr@Co;^=W_lJ^E>Yh(roQ@K{?YO_p+j}q1FUHwt?QIfIYr$9X zo0`urb1#FHQ%C@6q%w>R#w|1Y=t;V5tiFFYKC0K$L~c{0#G*g9F-=|^F$)1Ub!s$| zdLwMl_XNhFH&!7sw27FYsPF5CX?4 z08|S@dBRjI_j@aq?7Le=Rg=)aRDfz5^k>lt7grjod>}l})Q7S;&1oKzoK7qwckJ6( z+f3G$*C3vQLCn*V=SO!y z5eBHXueD0fm(mx_|Easi^I`XhhacfZ3&8r?T2fpsCS_t-)Y|*nfWvl4=DxAM&i$!4 zi7*hzw|5}C_s`T-m*Q(4_?-s&dIXTa_ES+vq1!d#@o-u$ESmA=BpaRdXlM@;Po;B}x65^Rh9m}lzFaT2H~7n@P}4m`7)Zs}rD z1Jjh|`%W~8<;v1hvM@WBEVE+r@%(|Ip%fP+IHi3WM(|h}jL+{Dh)DB~; zj5lNOD*7u{TPy2BR)b8B!}{_9EqLSBx8}HO{#R&x@!erR?tLB^6DaP)N^W4q)F$Y z$p9BIpDl4TVD)YZB%7E|KmG3?CtrQ`MRN1b8*F|0Rs`!=7|5d)r@1MA>&vSVSMZzv z_K(TE&%a7GSBL}PSqC*41@(QBS1p+JlR#3CGVmKcFWq`L@^YqT>>T(<;+{?$MHDj8xkAoCcfFJGi~{}8qN z$JxLKiKd070K0==G5d5j`S09&{@GkId-pNf25|QSnnLU1dNp}YHNbITacT5`i_Z8* z7G$zbk_qtL%cUs!{or{y+~414nI0dD z0ATRnNM&nK^9Izj<5JC0L6z}$Xn1IGS^f#!)LL{{1sR? zSP#qi|2;N0UJqo=Fh&^Y3USG( zege7R#s##fdIZ$#)|OTx5_|T^^W?Yx_;GUoi@V9^|NS?~^0S3xhaB)7?V|@QBmMPL z!v*HMU@?xU@gNa-iq`+Dd+gOoPVpQj0*Py_=5H==kE`PY$z_grFBc;9X!OXfP=-s zBF~^=CRTycNC`nUo%nu>9MmBk3d05znz8cu{=?+%r(Yy@fBQx9#jih2R&X(FE)xfU zOW+_J7RRoP7ZI8)uboRSk#>5jHpi(yxlLUm-dG{<`6~1SWkPGNH6iLO;ijI^$%|bE z{r!Dcin;zvZ;#&o>NoRW9&ElmVkbIo0hmhWib;Or530Goe+T)TM8fI%$p6fYYg*C` zij)>8|HYQP~)!XT5;+Of_b1#Hen|9>-2 zfFfUPHo$=t8pkj{UY!_Ze}TT(1Hk>t9b2z827w^l@Jxm8n*`I#>^_FMB@x_r_&uE3 zB?!E8P};~*u9?!Xn8P=W1%V-FdjcGOht|Id%M${on)kDB9w$}Qs<8_bxB_OiG){oHuom2Y9*h5?tW$VT&MckaRH!H9q-hAl^!*vNqnx27m^Wdw}TLJm5_7S zTqJNrkK zZh+;b<>dL@M-c}QsZ-g-hnyt@5d&cGV6H-W;0orq9A#!HCyH6tT8y6I%=x3g|7CK2`io@h(hSFR#I%e~j^WZ`q;J=+7DX{Bbx_g_N+zZKZ-}PtuPZo&jRjij|5dielFQfIS0WLj! zo_viMKYC$2x$*dI{Ha69IKsgA;6Cf4vlFk;s&fI9~$4T zb)nuo$>g`t;-m?4FdF|hr7X;;d{~QCsBH}4V>IQ@y8pV3tN~y#pPXE(!&mzl$@=2-hz&G+-QU&zdHH*KzMBrDL2Rbp9+ zY~y?B*0to~t*c3CXeizfjgT#{+YDG;(NabIfW_yyz<&Kt5fr<&MDG96M$`dtBcNVu z9s=qKGZY7!VqUf@X(?{AMXKOJW-V&|u4n5P9V1cZFb==BI)e#r27|@~#Ml+wy^Y@4 zK{b8Nju!nf`d=hEm(1Up5+EM7?4179k=M}BWZc}HP^V~p?18?rKombw(L~0EjXvAr z*9(@&k2XTuQmm^80qdMwX_|@4aEoo8p$5tS7pDJuj3cxQcZlTBZ8U&Hpdi_YA+Oh3 zgMe#JL9l=jFh+48h0tZJ0M=I!tO40Wz{^xdFdzltUbL{{9CH1Oi;nmvZf{5Z56|An z;eJ8@H4CK_ru;Icf``Idl|3rHU%dBZ=}~DMvL_0uBAW$W|M&0x@72CSe(A41{5xX-+Sc`s2>@HS zpW*x({5M$PzDU2{ogh=dlJ9 zFyE~Z%|ADU3t-QjgbM(l=@t?G5h2||KNUREC~?xr80sPx08Rg!1fDhGH!h-`Ud3HB z27#HxY+WGuNI|mKT8BUeJ}m*)$m_S3f(3q_EV*T~X?>}+=Ab876|WpwB`?2~FSm_q zzPxSCcLuT=&!QjSAOvdyEYB{5Dbr-5x3GrhlQ7xD8Lox41U>j z&gT<9~$5HAYET&rqS9EQ5c>|TNFoqwJ*!l!5=of!@`wxHd^RIut(XMWH zOaK@g?jNJ`KZKzED^{M&ziR~mwOe_dnw)va7e|f$PXqr>koUD~j$6Nva6y9eI1UTI zK^-k`l#|)}Pg2c>`Pu9L_j;K@8VIPXqBT>gO4d3lkMl$dbGu}Ybg@l{x9>gbHJOwJ zeEXiQH4s0XwLzqdHh?a6@%#(Yj%=9ffr?GUHoZh?o*jh`Fz#U(G=Vb{L6 zpv`aMd65%iTv;G=6W=b)}j$ZXmLeE=`@0yZ}u(L?jA{dd*{+IBO=Ub z?Y(uwcaypAR64y>Q=gzw|I%Db$JX-^iWXXj)VeJ7Yo>@UBk|}QqfEo|+USMC*o=T3 zTr&y-2IuMqSb>lqW&_BWeKY*C(f%}ZozI7O(|AD;NLy!cIq(ssENzWcOuf7)G) zBws{aiPK=PuIp66-{M~BlXi&Gl-x!{i{g2DDjF!}n*kx%|}(3i@5%6XN zLBI?E-$#7H*#%X@;Az)|uFWW=%-J{q*JuG1R|{RQy@Y_!P-oEv;JF8#m$31jN}e>{ z?V_`_s^EX#1*LPX=4OjVpP9s5Q?BMlaHZFPfQv(75(K3OlUHy;aL9xtDry%!oOuO2 zZT~}f8>18J6u7%)#Y^FSu2IwRbEvRr{?}cnY_vB}w(XN~if<^cxNfzQ7`qd&;xj+* z=7zA6Q>h*p7`XYT-}%9HOYFC!zwNaEw4+DIcn^JLQ$quR4A*f1yfrfrNTIK>*HX>P zS_p1Ztrpg6FCieYy-L3SzqmOVRsXCt-m@CLgipKQ=~jsh3ne0al6j z*L{=u{oDQAZoi*Gk!7-rWG_wPf^xm4DX87v^W*PdpO&NkYI1F|5HMO`m(MTfNV%jg zK-ONq%RcFnGr9(w8~sT>U-@2NCHKu_ar-Cq?8Bq>?tBXXK+hB|cWg7bNb|pefO*VB zy_QC@yQ7_ll5(%Tgn$f5En;T0KP*S*u~hU+XmtLa=!d5z$x&;eLJEL;ENHRY+&SNf z8QMP}aD8gM3~Lltfb$KN!|^d&w-+ebr2?q1Bn-P=fJ`%sZ!xl4q`BVB@AS7NxV|j{ zz>nViqw(Ql;oa?|asfcv$y1>(spFRZ%&+;91*W#xZh7mJ2$I!FsssL*sDMQ#`md7rp8ZYoakA3NoU}y%&>T_8SHDjO zZUy3<5@Fo6GKD5Fi4`CsL>T}yrq^~MAX8IP)=d%tR{}>u>m;9&Io=&g+fJGcC%~66 zwEqz^Mu3kkeQn!gdN(=%0$Knh;Krl4W`(`$_B^lI0W1It0hYNf@V*y^ascA&`$$@* z6=1v4hk}C+&FWnw9zfhW9W7TR#r}P1Fy#2>X5Y2i@0JCCsP+HO@(sXtOLGJqp)FB~ ztq!Eo-vt3N7z9E-j49W0zwSKd-=_!z8XfM@t^-(VTrL)g%tVPA+L&Dpo;d|oG>|Q%P!LFAFZ06{LoJ4WOt>2a1QHK;E?Qt7FUCSl0)ug^ zBCgY3Ya9ZSd;=$4#d8&2|5e~dxyKL9@^l9|(> z2g%STAQ+kEpVe>=A9rv4yn-gu6AL1ZAlls`a#oFNfgSQztySJk&ipHPJ)M6TA0j+P z5gOmRSPTtxjDWNr${hcEs=*n=C6T_N33s!aEK?cq{v5mTodfrjIF}ul*tg{OrqVhT zlt}2cCLmzYqh*%rR}>##Wa?z2KlkX-5CB})Y07s>-v+S+ z?~q}#agM;)vH;K!guCgY-AT2McoE`l%Ae8yJ*!#$Nphh?)H`;bjV-F(DMj(wi)~r! z-{MqXA&v|gV1=+~pcVgv+4OMd_;29O%5b@|HO?Bt3wk=5{dD0Bgvm@z z&O$C}klX1P!O8Vfjf34ZBf?mdnWnNLxz`q9Im-fo+N90;2i6Za@?Y0cnvRx!*Lyu# z2|P*;+TyA?=k<@@X$5xp(V+{UPGJY z6UKxoL&jFkt=;-qekBj)LF0dV=LgmD=Oe4l)&po-04Th>dL8T2pX96kmw=C{f2X2Z z;qTH&Ar{WX(KLVCNzaJwa89R*#sVTjkL&(Mc|Y6b1>!Qw^;1*d5&wfY)skTDJh zArCk?(W^s0>a)-xQ>*FR_LcxrG~GnT)3{Hzs|*M1~f$>Phw8 z)xS+XN$xf>=IolL1pvGwSE{+f50RU0Jw-8>guza!6gc2==;Aw@s?42xd;Ff z`Ch9H0YQ`%7%>Iz&8dN8iKy!hDrcQ#0l;8K3n1zD*Ytm7Ol>O-2CNOS-nYjE0fRG9 zf{EDS;gMw{Y5dtJSkwpPR)NB^Hv(4SI>#ugqmJ9XJS|r{$ z?jF7Eo~d&#L`^j}*Z1aNLZ(V3+&0-fb-4yt6PVff#5?1aM$uG9I1I{FYt>wxjkD&B zdSBLr0ANf=YYP`K3Uvqsl}H5?yC87g+NwGB1gPqcugaU7?Pk*gK(h}x$?H?X;2!Pz zaPyJNZWTAHh-D1zB>Q(7pRFb30y~aLd~OgpGrvwP_Hre8bjD1s&W)*$Z(hV*gm2Kj z=(9*`@v7Il3jzxG7e`VdU(3x{0n$cIfc47hE?T88dKed!k^VQ?vD6aCqu`>&f5gWg z9cvFB8e0*DBa)H7bx#aoER`P7+Y?)kzObMKMi@hS!l+k{)ElEVLbt43H z1I&!{B~zHADis7aOjX<4Nm8alAYR;V>~ceWa$F<3!Kb%yy?uwmHCauLh(+mj6Qm|UkbFJPT*0f1T8wBrHaiUKwv5b&P=z19K*gj+<&a@GtvjwZ6T zZM8rwEqt~O0aiHB?0S-9H=EyP`;d)K`7q75unJz}A=*clMPvFz@Ejo#>#UU%jN043;*Fl;iZn`o@){}BV=Lf^aCPw5;U zd$)yIm|0=|HzwQ~x0)<&lpWhtLOryR>RlY zv$Y;Oo;CA8=h?MhB^pXbd1De&`QT2nKv`Ee3v9GyxRc>cc5d|d?YItIl+AqzRL1q> zE`Q&iw$?!(L8yg@1CXBiuh)(afh{dY5UJHN7EQ88)^KNjIa`jp5^fMwIpgI3&a?pF z5*Z*ZNM9L=5+U8KZ?WYs+Fa@AxO1-WAU`w(X$(!vGqP3GW6wQJSUlUYsDk;QkOYvC z$7cKBxJDqlLsYn!B=TRgauf^E0?=z+4FRLLZKE*HH>T4}mETbuXdXh|OcQt1!j)c6 z0(~8Z8ysCCtHwGObY-GQ0t$^2Bw`wQrF!2QK8Q4MJ4GW)CLz+9R8r!8is((GL4)i zI(gRx;P#qoEt=BSF`+3KP%sdIV0Z6;hVS0oh0;S!rqL(oHmD@?&H``70<4QjbE{>d zEwmD;LEKdTV6SyK1a_xLca3fvO}bGg7n8YKUZa^RK?}H-As+>}aWD#0LGPi-IL>VV zh28aV3tyk9t5P4dk^Q>XCKRwS|2r1PVG3%L;cmmT&+{#UCoqZPhYUYv|S$!%>mJFjP20C2Ic5(%UNu)esREPc8ix&PDT&(2Up z!?dCAUMsP{(i9uhYB2syktyw>Lx|z&Un$=<&E;I#! zPBn?+B}$?ixMyzoFan7}$M2p|9@bpm2AhQTo#`S)WeOqG6c7-5d#pDIye_%Sl+9}t zZQ9t*MTysbY6Gle+I_N8j`)jM1nD6UHlFlXf7PpdROaOT{ z*O1_KvU&fs%yYU)iuE280GbWl2Q5PL*NP$W?FodPoVCu}+c}IXpWNOGpqVwGQ5^I- z59z`f?gRyZxxx-iA+-VoP8?AH$QFe6DxiQAITTu_*>A#>WixH2(Eja%)~x7zymSU; zXZ@~G(ieK*T*}-x$PigW(|^32*8N{cVOitg>%{#3m|k9vI?cxb*Th^@x}QaIFl z6;!%YssL-Sp9MDH0@8$;Ps*wNKdEk$mc>N4UAu+==VY7t@Ep_Qi=U^bS6;n;9J_Cv zlYVTWac0_lwx&}}rZWC?&J6B3=x(pvI{xssYJ9p7vh7v13c3G5=S7#-`_ud6Xb{j{ z<6IgPC^H=!OtVs4+s<`8tnmA|hKsEhs=shtW{hQE6CognfU9Dme^`bQ*MroeTi~{z z@IUY{o(UH1{>?2|8R>Ugs$}p};H{P`g-%^*mYcTtl(@(xDf2%XNY3rAohRo-_s=?- zzCnMQ`sY_ubN?y|ipM5AKvzJ6B%^EK365#@U;IBm|JhP2ojTJ3z(D|!Da=zUbQSeq zv+?Z0X86~xQPk%8ElWO@N--UF^<>pdq1F;PCq= zJmVkkt%d2|pwD_u6aOTd*CZvPjr_kfKEVA8FX9R6{l52o_d%c!iLQV!`Zlhq%b3z1 zE^Hq-J9y z$Q1}=B$mkb-hI#)X^26{;oBF_0!Lx|;H&X63IGbOe(x~~PDktk@42McT7*Dl*WCYX z)sp2fedg@bryJqMNnHTWA-rH6+N1E6N^UJa?ezZa+z9|mc$Nyq%@dOKDvZg6*N136 zh?!3b{4#!QQ`=(ox{`Yfv0)5XUQ#130yF}dF}W#BRY+^f2jiDAN;FrgvbBU@;L6h# zW4gBA3GThkk0qiW`b#6Ii-$-&htck?j`x!ug#aM&UVX_nEeH-6d%2zWx%9vWby z4d5vp6~@-erV*y@fGsKXo`osn=cfn&%nQF!>$f7GK~fTStMqx+N?7rQfY2E%0N&63_S)HifDG2=z7M6My`hVj4GF# zJ5&*+-i0`#1u+x`Zo5O}bzNPWnFmlHj4F4F>BARW5`CO;lOG|czKA*2#W@9&RV(+{*i17AHhHfQ#);}}yV}?8?WEt(-5{nC zUN<9>u)0g1rc#5w{M<$V^(>M-H+YO|VI>N{)VBaAI1JEFw~GEYb^k56BBAegntTuj z9`xC9kK?$X_d3?S{6xlT8QowC#QuEiVkx4(A1rR74Q@uT*UPJ4f472Z>Nk(pV=suC zlN8|rH!Of-DMb+5Gm z0r8&YABD)I1B+N?KBJhAv0h)zZie;8&)wNiIF$_5V+&S(FNb$&1LNl<47toL@`RfG)xmZcO1TV&Tt>rU5=OG=Ilsz1AQE)TlG9 zdU(%obPuG&SyzEURcKH9q;t3DgodYt5{_@+l)!f$_BQ8a1?k?+iI(!N?M1Og!dNJxwi z@H`c%ZkVQ_0&1kTUZI#24o$y8LxY(50^G6Yhft8+C)1V`%slo>UeM+c;7sdTqyphA zSsj}H6zb|VEeI1OEITlLtvmW?^~J_>>ixKl-)n)gdBQRsX9LRAR=m@U^f>A)7(b%N-mRY|h$`=m+{An@?(q_o|#gwqoM_TjLLe%o9%7WnMS zPVx_5Z(*uq2RtI$+(qyLfji&1HiT)B_tc4>Mi_{+qkTkg-)(z;9smJd1h&1z^q>;W zFK8`qUcBGE-v$JH4F+js_NPzRao=nP<8&jBdToID{JpEgFot|`d#aF3an@3?w?Fmn z(T?wfnM2JCFf&+5&2yRL9=uXfQ0XyyEBIN3aaI^t_?o$1;uczuOpN!MqqU@DO}v!h zwv)li;G;f5_7KiaV?P#f&jnQE%(U$#E{hSi<{hCU`nxS1tmexYH{ z?c4HJ#(ifxAG=pBZ1m$BE+lyv#|j$-0J;O4pX(wtKm60D<>WE+;PPmHs7r z_;}!rdLOnG0;2c|)>;L#-#y<+QYg8wCEQ_4};=>UE6-0k^et$8xjWGh(NI zvYqt(VxTy%_`yg2x#|4>teZy?03ehbz<7~`!ji6H-8~yzkTHdt1-(tSK{Sb89&`0T zo`Et%%SGDsKab+ymhce|6r&G<(4z_gpGIHyVokH4bAihQ)c~y2rW?nFe;84Jaev-8 zZ(}fhqyHn2(9d36&}i>lzfNXtKg$v;-fM9(P|5Kuv$70kl+dYtmifK{#j6nLDC2kG zdEVR|yW)=ZEEFd8HVe$Olex;ot@W@MPA>!iCbGa9F-SABIykr61jg-fqycZK0H8U2 zcpx>WyKu5#xU7V8jG>Kl5o=VfA1lcq!iw{~LmyUs#;YLP3%>YDd|CmwEW^; zdxo>rNwRMLIK$H-gKR?K4AI=al7Y(0>C+FF8#-U{po+Yd(^SEE&znt zq5m=S@ga+S98&f!oskco$!6e4PQ*h4o5d99S-B?&3j}YxBoRvqnL9)CKnmH@17Z3od? z+1g5;u9bt?Pf=iGhWy|QM7FzB;_F@0Zx`G53iBZNu|$UNt> zVCsw`m^wd@uw}F@JNtq6ih~!=w(RVChvQDT?H*QW%|2jn+ZB3W!+RdCJs@Nd-}A=) zD1^E9hVF#7W(K3KgS$$;cc~cKxx#=)yP9)r`dvR6Ja4d7u$%m7S$VQp4u(?eISOBo z$Q%d(2MOmJ_PSUDcgzy9WN)u^4gxHbWC`J37uZ8ei$7vd7mK)kMo}OA{2>sqP+Tj{ zQ?E4#ftCdT9#j3R5C3j~^TMCK^Ml*0FO`5Z*+i=toJhv8iAILfpY)-%UN&V!ntnx|T*rr^lOc8)Cn z*5Rhh!oI8VTerZ7W#bprWYl7^%4F^6MyEz|FrBUSwAa6rnXa-pthsT4v@JswwVYX# zJ!hF`Ru$9pV*RuO96r@KH#-ssqkU!gmKMG@ zZ>}#Ubck}jCb6Gkey&dpM1Hq(CZmxdb+XwrO_`5KPm+O1ync%oW2%ywCaDV})nq!^ zk8ZiQ@Ngc>WN$oPE(4D~1R)FPP&JZ_jO$p|u8(W2VSbdh+tjo?xN+5mVejjDWgj)F zQo5Emb_+?>dXz4iuja}yAZuI{B9PJRvw+rGzwLcj8v@eQ?cLzLC4yXZjTsc{reaq1 zw4AR3vhhByp^W+0zU!I!c9ZaxU$8*_ftpiKHp|I_c8shi0JI3jQ~)se4AXPpPO^aS zRz^QFw!`68viZm?H(*y_%w0!E>rNK9WE{n9Jq_)@e?MrrTSX zfuo8b7F?}1oowFS!;MIutr)CC90?WXe)E{ENYQGv2B=^LLF;T+Iyuay?(JCB`wec? zjiYNo0l=6JYcd!NXthUo?X;Y3yW}%10G8sl_)|agK0#IwCI4fBHVv$(1AkpN4;ISF zB0`E8Kx(PIK)|M^{?LoH-zn6)PUcu6kCs^9`1(J7vL5SO>x*;5*IXm^q%AuidgHV4 z#U=#e*E>7;zuw7L=NGqg&)PApwg><@%n>XCb|b2q5im%{&TKGX26T~5->eyf25oKd z5RMk|aiPPE$8UO%507*naRI?A!t)N*G;uBkYX4EV@XE*Jg8-jp@!o3{S z0^&djlQ7q6!d^nH1;Db-?j>N=KQ;eOPlKjq8GNMop~&Z+TVB238^LpmMTAYyi1JvC)SW=G*(acM+U2wxrh@gMjeW+%G)colnb;(foJkw<69$E1AbK>&E>;(m+^# z#Q#>>UI8)$f!1%;%Hv!94RCsZaQU|grcW6AFP>Gl-Tt?2tt|q;&ZndIx9+U`v|QPq z7^Gkhz9v;-5FX2zcGlRC>+U>p9$0p6Ocava6aB%gBYpGb>i6{d{`OYxr{(h2y1SAHU(e;^Y z`d5oKC%BQ>(Ud%lsn?u;12nBx=V!;!3|dmNRXCL3rF}k*C!eloWa}))n~3_x)V{_% zJKtrj0R#1 zx}xUHUaJiO=hJyj)(8y5Wn(~?RM4uMGTU}BSQ*7I={XAg7jV&C8DkeogvuubXx59( zkdY|Ne?7NJtU`bC#x&vyaXxf6tbVmec)q?3*BwKSwZL3v75wg+y@PV31wh}wFxTo+ z1_3nrx7t*wCRpQfCe}wQtjfZJ`Hi0Ny$`5u6##zr`Oh|geESc7vD(-F>w$rRoB4e8 zdpz&% zz?Q>M9wVG9gda~(P-IXd#Fx;Humt$KUV9Y+n$p+M2Z$ zUuLd5wf_0FwEl&a{QlcLYxk@DZ-qs`wIaQgc6zkh(hb}ClM-`rlNb+$yr&3t((<15 z?Nz9@RRHkTf0gVr9nhm2f~EK=f`EDt~ZX8{$5yn z$UK)|rsmE|OzQd20pSbx${>t{@RT@Gv!LI0zB%9a(@YT$1({x}4FMq}+*~}uF5B;* z-h9`->%rf;{#n-36)r zz0o<`w@6=?z{AJ6ErN$S)Y>ipbf}*ly{$;$Mlxm0Q09gY50r>LCRhxU@f$M}Aa9l6 ztulVxN-&?V<~9Opo9+}3+9Fi~7fJG*h49O}5Dk#@HxDTs1oDcs-@aVr`B(L281WwD)pLX{ww3fWQf4O>*EEA{}f_=CDg+8xSGC9tC^YB z=6HIoaR}%!St3A8p?QMT&rZls3fh+`JX8Wt4Ai{OT3=t+42|2#O$-ide8&z4vB$w2 zI|}|IcxiRPw{Zmw4^V1Y#&gi`&iH2vP#(_PtjwOZ`e0!zd4LO4w~iSwS*o9cyw@E? zup2_VSHm~6>f4l&o?s57pI67ya_k>H*-E}y-U@+Z%f12s?q7nrRe<<+C<}kn*O&ih zE-AGo=l>wo>j?lt#l;LF>gQLpgcoB4KzoERln51815t9-pdrGx$~;6onZM_47}|Vw zJG2c>vDL6r@Xe`Wm^$r81@XC0yXU!Xz=4Hp?1U}=Q-idg2%maQ0$jwRq5x3Bf9w{t zY6Y#%U%lrY_C4JX{Ibiw@3qDuz;X-A3G#Wsu<>6uccoUpan!`h?q)^08B%s}@O_-d z7i*b`T?8jl+Ys{D8Rg)goU2cTf#!BM?9tNsR6jpflBbydBW{Q9rFTb#mE=(+YLIn4 zMV5~#*H(HoEz`AD%@LykagShbk?E)pJcd~W_4F`3-rU^zXtT6A_p{G`UdJKTdZ#)j z0BE-8%afZ0f1Q1YU5Q~C{(ydHO=p8rn zsyCiaf3FEq6QLFWHE1KR707C8(!z?40m3i`juYE4!aQbm-~H}5n{#e|Yxem#J9L_! z1>Ay=d+t!bT~{)a0vz1nUu#8Jj#xZf!vb)a&=&pSMWw(1Ht!*RYB3bYvIz7Jb-Sx> zs{$pQq=zzFVPNcwwfhZz)e>M3uWQ)#+-!^W%u7ZCGjqQhzm`(X{$tG9D90c)Q>%_N z*)6hl-|D8JiygzEX2;XO^``qRvgsZXFr8~1696<@P!;GWmCDXFr0E|rb3bGlBb^&c zd+sc9e)@Ei0v}tL1q;b7a*)T=9Ip%pLh0*!`@%pVm8Pw`b7>jcXKMtqv_Rqg$?7&{ zF(iVu9fAeF+zN?yiahlxq}U5cwC_z1B8cdkNDJAx2wV{7p{=rTKY#8%-)3YGbhWV+ z1f-VPP*JU)`mqXd@3M2-HR>=}@l7|&al=hg=e8YHh)^8O)4uaC%_lxat$k|!mBAct zxDsn`Aa-c{7N}GBdrgbsrE0eYlTJ%KWScxG))f$w6`y&89f)>krjBmXM}>jf`R>+MetB4 z`xX-mvMgaH!@JDa{(O0Fx{_in?N6G9swmGoqgaIn1YiTle z5AXt_{S=GaUCK7MP4z*lgfS`Y&SKiKiJ+}C7g4q-TtKEFDZQ?3=aW_bHvQ@Lc~t7ZP0Hc>slOLp(gk?G{ZO{O9l5~*^`!>2T@(LmUc-KP0xLZVk8~A zj}qm%T}=y%t{Um`#nJu{ur5(qbp~ZgnrW<5r1tVmEiul+3K<;+4)@x@5a^fyaPZ^0 z|5MRb^Oa50(W3SIS;!-lGqO&I1VJ;QZ4#f;^~pjYd6g}IT?FnbW{`_(Ul)NU>}H$J z1R32r&vrrGpD&}qV(J>E>evvj0+4+SX*Z&kSrjM2*qR+wlh*^vfL-_y39_I%5Tn!bQpnK~xPMcjb8{oK8Ahjm`7iJRuP zf66w`GN>!#))Uc+sE}U!x3%uuP2b7XSCIf*pAQzdaex>0x zsR1t;zUF*4?RtBfOdgOxfog_B1?&RKm&_koAU0T2!pc%?SJ-3vYl{A8$z3z|_OvvT z%_xBQAIT*BW~b73Klx;4z0+Oq2>|;bEb~#5H%d?c^CIa$GJB<7n*>QSl$6M`0VoEz zXsQ?awH_GtDnjO4+_u3!=w9$x$LzgGYLbLWZP-nr^>y8ttfHwXAxF2)+>2A-+BJR7 zLP~SMAPuzSi#koq$V90S#6tl|3&2S=F-7fFA)p@#Kn=6k8izmzKVf(rLay^O5*7f{ z579P>38?VkzEyit8~3CW3JcG%+KIn1Ny!FXKQk?*O^l7qB?J5(qU@-oxXD#3!F>k- zCY|%tVy3_UB2^kK*rd7t(in;ulVm)PX}+&CI_DfnH{3-~E5K>u{~$ObRqhvm{qfK4 zzA~;3{?T~>05b-Ob$6MnzsEmwfhF-S4mL6Zy1&VQpHU64TK0O^Tj#U$)61+ZD&3GD80&a)E&QUuLG6}2xO+dKEIdt2cXrn{@a4!SI6e81k zIb;wg+R^TOxHMh?&Lf0?W9p{9WX;bPi61fJXBN`DE|Q6dhxEbEEq){JY7SpQF)(=5 zqGEX{t+;ubn(IxRb?r&V9GgmrRu0dPm&(EX*BGbQw9+z=2%Df`gz%?l-JAqfVr@0O zPeDM-o`IUW2lfNgz8Zs|l3-ugh#S&{npp)}>DzhuO~(ZQ(im0=1pM1lsq|k7lexhJ z{w08QyWp;G7OMEw{k162a}`sdTAWPXbQ1|v8aO2LPteG%B9jn!QN7Nv{(lJ_WtF^TEY1yYn5 z9)7#7{>DZ893u0@^D^!f>#~~~2_*u)htU~nf+dwT9hy1u_Dot0%;^7)4P003`wcPFDo$^$cl)fNro$3Ib~Eojy^mB%VlB06m7wI(vEE!YaApH^EIK6?8h7JN?(95mEI9CgYCNs_B^g{-{m3 zddT3llo`CM_OE-@H~`o3eulsQnRdf$D%~y~(vP~?Li=xW4*xz50pJB#xBAvL2a?i< z7QZ1Hn&dXz0o}Y^@a_U|F>8vpu!ZKlQ4q8iW0A-!sk*sP#n^yx&O1~Tgc!`>S2Vay ziFKJ272Zax$KYN7araI9j29(wiwCK37?88Do<_!+`ldFl*(`He97O=x|NKt;Eev7- z1E*C2i_|uj4g6~WI1+2!A!>`01pb-2d622F6aB7rPYIiXhy+dlWHuMIeskWx6K2kx zg`9!`u;yY5=a2&Y_IR31$GJ0(#4^9)m5fE4%+~E;Jux6~9{hC&(1{X)!4CMy#og+f z6E|IEGIV2~v|P9??<1o6ql7O(kkUZijw&Hu%m1cZ%pNcL@k{vijbWPL#q&58fQ$I~ zHTMr0JjpddXKPG()^D?>6ikd2^4x0tVbcRT@(-$;jPjEz835!md?=4R@-3UV!LbSe z$;UI#lJ{1BvR%nx)Tw@-+0`9zy@~!F>!qw=7Ce!pNWYr%TmaMfqb`sqyjLUG+o_D{ zK<|@VxCM5Ic6f8DABlM|d{n=CUJ28b8vuR$XeA_REe*{qrtDhJk6D<{*p*Di@+ocs z7nUaQKe#>=rnEPw2V#>G*O2uKy1B{x=P0P88Sg8$S^ebEdc2qD)@u^#_bv^xrK`bz zY7j;V*Vi2C-S?>9Yr34mEd$A8Y<i22zu0+at1Ftw83dzaGr z72Yq*{VW-2tSx+H08J97Jz7p z$VH-<20_e;q4Y=Aw)b8>z}*GqaZ1%8U3=p?&3@Tjv|HT7ew2+e=avQ|E+DLEeb7{A zAe;h%nMkfFk8U(YtLc+DiMi2(KpxZ(2~sxJbi}W|I&S`l#bpGhucoFIKsX#WH?Q8I zvwvwgcK+cVFaR~5G+@)YcD%L5*4dtQ@7{pI}}1+GuW(R#ny`AZq7xad0DL~S;ZPT#o#Kt$4$ z(GWC-^i`REvrQPr8s)`ttDtx`m*3qNEwMg7w`(qJ}lWv;vY-;{rvg4lxJf3OBLp-dvj@9x_2~v}oLb#e9*7vW^ zxEV6iSqRw2v0S=2$ut$r)*(>FHY{N6I5mn&XF>GJ-CZx5+pn;L<25Wg*0}(LC&oAx zps%38k7Aa#8s{fZbGY#=7F2`L?5@WxIFx4TuV<+zLQIhLM63;Pl1)A?gB16kW8#bIpDf7@b8e$bkWD4&I3sA-!kUAn^Y@4sjl?|fCeD1Rz8cFeSxwJY9>qg z?)xCb53d|WQR4Se(?b=*@p9%q~Cea0QP4r!&W*=oD){23k>GH6&cp01=D^?Zqo^Q+xlelr=g40w&%H_GRZr3dfJ4B9Hqal^r4mC0G3AxV1JY3le>%CxsGl3Td!{? zCIIB})g6#yiOE{RHa!f6vCO-(iBS5KB<3ayg038 zLmZc$*s}4ae|7#f3*IxM3GxuyzUF={Z`RzHg$_jo{gKT5DN;MO0x!}z8NcR!OZuwx z7_2KiwE`F{-Ac<~Xh5|Jj|aw!5L#Nf-wFI?vs%eL`0J1V(}NRu_KQbCHczG@WIh-i zNPY_AyM^NVC*aGilj%ugPmMLpixIM#smC_*$r}@eKxpsKtSMclV01D62^K6M4d-Eg zXtG!o^xM0e)f}cRec_8Z##=FK*=P5{c3~uI)#PKMFZ8i#4KPs9O*P({N`0-C)r>t3 z=nwyotvN31{F^TI3~gj?Io1C4pJt1^R%a{;`UbTSEEy`ZXm%cI-Mii284GY7v$p2Y zCs;b}&E~@V>T?#3m~ zG|w$IzCjzP(KN~}!dzjutnYj>w@Mxq>rPwuU*Z+4EBvy@%2L4+xsm zZ2lZKg>ec;HTNsvrooQn@nh|f@oV++kiJOgvhlYn00muR912%YnS-xqH$rhxIqS9N zAaG&=z|N{1gs&i<;ZtquaNd>-zCsEyB4@J2~@A-=gYYD*<(C zHA8ZLj&$>p^xl_7`eILkuVzK;GUjllThayN=}nHA4qJGL4GklpZr(i(AUv_nFbmP3 zCd&$^5;_t)rcKA`aa>J;vw$B@3I6#if)6eWwWV+i2=F>>3f2EDYK6NGxZ5SGWp!h- zS6U|&0A@z22_YC^u~5(nqT7v~KIT3-cLvMKM8?USn4#>exanFs>83X8!Waj~+-Kqf zII8wvR{#k72B(RlUqJwvCGKOC3YBWWGRjUbHkXiV$sjq`m)ibk6!rOx{WXl1U&Neg zEI?S{c!}#<1a_GFQ6w&e&%ZDE?zIw?QTs!f8-vzJd$ibPOEfz-`#6PVHGfDkN&|HA z`9{PmZ0-s>&ED@kUw>i(Kx71bo-9!u2p2$W{Ovd=F5^Y|0M}SJ?hvK~t;r0W=I`d$ za<%~U)!QnV>(i3L=EPzuLrYI`VWS#p76y2h5W_f$D*hJ zpn&Z;BLAUfb(Y(KJrNv1_jsd#7I7|o5GH=Ca+>>7p*$6IOn;Qj`MaYw`-?7vn@}2z zaKi@~T|DZ&JNtXw-bvpxC@N-U1m*!8BP=NYt9?Q~w~P zJ|PCJv}{pGOw?kHG`>bP!4i>UOSlDGNczO*Fxz>E?5i-1TK>nw`XO;pa7orULj?Zm zQJO8FiEeV&Om}sUnNB9PE1w*8%a%U3ACALfBM+&w{)7l*g%Lli*JSilrGe0(r^(Zv zAV)kkE7tqv$$l>!HG?|O2D#nDbunDrp@7py1Y4bK?@s>dYQ(oE2cl?_g{;i(P$w7&t@;mNq*^0+t(K{MKAwF;{l9Wc&7bH8iJ zGUPIQE1EvSy(S%bj+M>4{tyysb-31dOiJdikw%!YAxzwT)5G`E(34@TqzVTulE&A1 zAc*bv+^(fi%gQ!d#3`|&ErTTgnIU|QSa`Qw>0f?rfXDnnPXK5V;4)oz=aYHPA^<#J zwd5}w&ymV z9;S3@Y&*F)z8#V~`2sN5G*HLI-HE3CVVeMeb*SOj3!BN;b8Nb#l|xmkPSZ*;Ln!q) zk(ieuGSe1`!K8W`EC2>z+H_sqnI1%A+6gnJ!H?&?iED0iZPA~LFi7K4x@}GepqRSp z)=AZQfS_#M3ANC57GpixRcqm0eD2Q>;%`j!C+}Vwhzy+^7PnU1i2Ly+699Zpx)pAf z;yC5lS3{xS6l3X^76JPjE3N)=+y9vOTP#+qcl^@`YnuCwkCtA2z7kR7=D~zS2@11citn*|pG*xG) zPzfTem4h`ME$d_YS8K1rPZOlXGY;NMoU(Boc2~Qg$x&B{<#i1hQ-JB#607^ik-^US z)zmEvgst%b66J{0-v6UB{I~EJfC1`4GXutX)uj`4GekHiyo;LMQ7AEQT`kubnmj=^ z^X3KCS$(cMaUE(A)kW3D2Qdm05)e4u$}n9o;*Ezn{A$NmE;V*YrC~W@h%oo_oxy%u zA)0NDERNlN%J_vrnEPS)3T#>_rBkUpE_KhfTXo3Bsghugf)%v?GTh(K`F{!;1@No6 zl@GrBzZSctvnMV9%q68~m#Vp+RCkhb#NhYgGJgSZE_Vxn4(o>t>HZ>RCo8M$T2-J> zNE-2~)N91>QCqg?%oMnS1wa$m4ArvULu;^T(3b=WYUaB~?(QRUjFtK~a3phTx>-QT zqBLtPC{3=9=F^hGM%KSWxz3^gzrA;fkt;jzJkO0+W@ILrOg`&DvPx3vQI>6#yX_en z?U@l8wP4+#B&7^5%`ljeF1epL4$V`Hm*{=TGH* zdR=HTCcVS9kku5V9A)Vdfq$&wg_v>dRy-d1!;@k9pF5M&4vfbGpuyr0Jj5_UF(8F9-<>1hQAaTVMX_byv-0r>3$puF1xo z0&`f2Q0xXp#te>>^3~CaEyaqO`D4wm7iBO~U6%EeHYh9~Lr9 z-lU)9{egvfCN9jX90J(3H1H}0mj-N zK<9LHCv29%$3#XW$Lxky024-w?&m~^&D%soN9)|9t%fls#%4H7$ywFIujN&}$l%qf zX^ggb)b&R{^^y40zmRSCh-JQGXTCt586H8QO z3DF33Y@5t@2cIMtYRGs*2q-EBh=5(m7yvn&YJ*Vobe_=c12{JFT^6>!A^tR zJNDTvD?RG9#jTdcg4nTtfmyyVKjqHpfC#;yG_l7-gdkEdleCrCl#I{&%i6i|RbhQs zuAB#Qhcpz3!MO5!JEW~)9o84-c}xSD@$~u&Q{Ih+rHfS(Y3NSI9F_~1qINe`8%Px% zB?lrw5X*)4D_9MFac9e~1~{wj!rA^7S$Z$`8n?r=kLC+=zplB?a=t|+lzOD+!3=rN z8NmRdx|ag>(;4C#v{FTZs$Y6>+Q(&_m1_n84T0dKf*+x8xIa(=23?p7STk;@&A(iX z_6qTvowXj^TT2IB>-he`ruy#vu-SYs=Q5A0+T=9;CJAQ~0D9~N1|5ERHmo7l=dz^m zx-?^wybNqWA^_;QOwM>i5v_t#W6>#sj(5LGd1 zh#gu6%=WaR?$69erZ+N~!MdRV{D!*iTXYe0iFN+?C&`fx(ZqdnP~jP@4PQ`$$r6Xj z+^?xW=!XgZ9wET{RcFwwyep>ophPmC z{tXoR25Td8?2MKwqV1nw!0eCZFA@SeY2!f{bn-o#KL;5Nacw+M^gmVrFw@70FTzPw z*xf8E^8d#P3jT|MOOyc6$kt1RAa_}s&u#VXIe~Xp6GE&k*#&bp=|0ieNaqVPWC}DEZ#;bw0m9|6B#ndM8%&)f z?xCG*=LtbXD-b>O%!|6U7w$psaflefN}9vbefOyoxA3NN5hIp~Ey(XrCN-ky$EDDB z6x#QKEGqcGG3|1I?>_KEKTOGAKN|FhKE-tWf|$#3E%(E({Dk@Yi&D~{RyFBAg5VI( zA8x=T)kZo^$6ic|uQd&PPJXmmcC_=WL6}FvfO(2s3}Z*@=S&U|0%j2amX$YStz`=5 zUcD3#wf;aq(Cmwns1ZPqi{Y~aR=Ar`F$u<-KQfad3E1eqqwdlFgklY?={m$ij|pKVMU9Ww#SIlDYrhnpPX=H!y!zi@*${;M|?H>+C&Z z3)=pfxheP3v4S`Ee?~4$zxA=&bxL#2&p`>Lv7j2ayR#=8?kbc8_6WfpNdlu4MNUH3 z`f2evTn*Fx>qH3v7e4t3>mx6J>$7jp7iV&Rq=AN&J@JLXSklC=YKvdYR7_@4?hd2w zXxZ>t818&a*f`pV*2hCcSO-inA0^5-);*y97y3hcNW1y4rlm}J=DO7IlJW#>No##c zOCcfOGx^9|Cjm~^EB=MbwTi0aEdXdc2oglVlXqah!mqu*QEg+L@q(7k5h*U(G&UtB ztoT@8lvaGCAm6Ucx(Igx7>!Fy8K)d-S5b{VeKfCSaAa|eVmZ>7|)HI*+-;tQ24Ka{PINNt7XTxv=0f^Jf=-Q=nM5^{9)!l zA@>^V`OhDhP_KDLedwoAN@d;xAg!OkMgpyIw;~i+=??;l5&)hwNm-IILGFeI_=jR| zFKf8Ju2I<9Mf=HB$$6pi$dJS&&OjwYAj{^+4(ONg4Y{W9T<;&(8LfiXnDExCkz2q| zBvBrS3>g8LWW5yclhjR+&e2Y0yzrxFXjvfg(in~^t<%%xL4lsd&V~(1@!H=&*LI@0 z5b1wXTB1)hqL69UV0%HPO|a;t?n(TOC%6)BSY@#w>(S{W1+M|FDyS28NotG6q5gaG zG8!ce|Fl0xaU5yy%6PsN6u80ecc(KMc|=Kb1VrwuEZc5YzFeWQr#Xe zlCL1rGH^ru=3&`uF$fQ6G6xmb8~>}9W;~u}MWp=haC%PKnZ|DI#tcpjK$HApq0AK7%Qxxy18rMtM0tr=&(1W$h#; zh<@|?ZtT-I=D-al^TOIgdT4}k{P6c=0V2T{+j&PjMn(z-CQ)Y1!87OChXOGNZaHEv zUY?h^Uvuks<+>w?@u)O^glw!AaUklmcNp$Ftf~Y`!u0I{ToAqW;0xr(H7e1$nZFRQk5YZ3`bfcGU3 z;X(#xEiXh70fKuRR3MD3HX!p@UiXIak0bL32igVkH<{5>O(1LlH> z9A?8A#u<;(B-g)_y3r0?8)(zysUWdddkoB8_h23{C+KrxiLlOr%euD6UJ=9d$$VN& zf3JIV`Z;|-J#kqu|7SI}h*OHwFS9*)BIZ_$Hb5Uxs9}Aq1Q;^_= zfbxfF3mREQaR z?N~Q%|6Tj*ZtI)W>j|JdAt6mUkL1cBaB{|*l<%%q-5njB#7-ooZMcQbElg>g6}{R2 zGg?oM0E$aYdhZhp5%u+JzQy&@+NaE|X$h)ll-Nh!8+TON^{O;^ves36#Ow3D61SBz znK3_Bj(dvFF`@~>=kYcEi!S~UEAyfv`+>6W6O8Aw>RKIKLe)t71d2kspMPK=+xM7Hfk@QPh9%=ILWCB_F3R7E$*e-Pyx@dm|SU>W*v1btZ@ zu5`cRS>jzouRxa%OuPUfq4>^p!M&|mvoiwsD{9{#>qzd3fK~@!&b!SX_ZrA9Bz>(S z;eZO2)@!C1{nw3~3Q5!J5)mj2UFBO5n#Ri3# z*d25qpZB}0c*;`f{@+hARide=)>M2FiU%q(f!>iN1~06@dw0x2z;_CDw~TEAZR+W#;D*N8uW*|Yivm&-X>&d8N<_Jnrs z(|g=5EV;yr7Ux_@8pMnhmQaJ;eI*zKG!A-#12`vk%X}dm_)?|H(u$|p7-1jlb zMHnHiF7)<@OqV1uVgk;{e#x?%6-~Znnc*rT(`2OU#W)Ko=l-$bp7#e8u18BOOMoT` z$X2cF1FR1E-8g=a@Ku%|hIWWAG)?Az`Xe&uM$6c+K;6`VHHdM*IDBS2sN=oL^vs9c zC0&K;!_0^U()8ca$icJ)D;uVMHYPful{deu9R9>zoY5A`EV~5zf}{krey&ZT_K)zi ztv}ncp0XU0)e)rq9fknar(QwxztU&~?>4gGig?#jpYA)b+az89(00K{Rd84sJ_u!i0H#G!l%DQE-~e6`bx7Gg)kd5KxxN2|$5 zL^DE5Q?3E!D)EGkSOVj`a^%1z9<%6^CwtVrv0O2ei$Q`!P0pivSZB{3rJel95b33*rf4WgI^ zveZ?ceEk zqWeiY;oiq4!=03s3paokTDFeSzB{SpDxtxTaBG-(*~s^cB$cJIrs z^+2l1<)vmFr8O1B1b_i`69boJc6CwjhnsnKd!?Z$=+H-ZCshD|K#Q&@OPkCrdaZnn z$`D3eK&a?sHm6}j66NyO5pP%PO}2f;Fe09<$xo#cuLATLfcD$%;3PZVwqKdZ*VLD} z5W9d9S;+xaYEXTJ37=Im#8iAnKK{?1Acwz{3oY&C%=ZLbGIbCZl3rq*a6jIY+mwyM zNUe_PAGc%teNx*Yh;P?x!P{v58<~9h(v3?d01TwFqUcKY3()8eXEid!u98{eK@0D~ zcguQs%}wvijiuV8PEMk>DV!RiDlMQ16lC*}a*eHc^_jHNni|4qw5J!hfPcsye`5R+ zKl}HnzkU2H0#Ew$*^lkr0SLr2f*HwtJbeXM9Bq*9Fbp2tLvTs3;KAM9-5r7jcNipC zaCdiiCxg3df;$9vhgrTod+#skK3&~iZ#`BwBh6;_lHo@9;sn11sXoN=Md0$|SlH>v z$f5go{t5<+zfH>x%Fzv?>T-SYcD7;4XzV^aPWy-gh+lB&do`61aJ_`GePrL5{-xvB)??#4ZMsi=E_R(m5EgO4bTRsU~~Rt;)@$Fy3d$w}%;jiEaesVuq(0vw`?Vpvo>b~GDswD5 z>iAo-C+uJ&fr#n_?j~+Q!s>ZUCeX#ZDgP5-M&pl0E<9lXP7NjfxOj<29zCaO#&n!7`|OuDvHW<_ON+ z6$_yw2YJP^{X?W&6zFJGU9T@{NL|oav)QJ)I&17DvnhN9I$6uBKn0|lPLFFKHQ&m- zy7xbGX*|7aGd0tsnj;$*+*kAc+BD?gB zP?ZGD&2~r`I;&9Z__V8Sog=zLGw6yv5U@R^ifa)%z zyE>V}96KG>^~bGB zK{-|6p4N8!$TuI0ufc&Os{Dkv{H1u)L?!@Q5EW(^)t;e7bf)D~h74I_W|jA~J~Csx za^Fb}c`OLTzBD`+u;DL!DN1!r!Gz$g~4Co@b76)T1-zM zWz>J>so^F`rUoy-P2V*p@o%&p3&?!4TOa1pM+>Sm*3aiP_Tlrav3xc!+0K1{BoWW2 zJg^a%L14Fex;O)D;>?-KVO_U;Z`vrCot=%?NwwRc(f5gVgTPzHrxUum5gtXha!bC`vMec_Gx=T6^9gpsXZj_y4m>^Vyv-PU|J}PX?iu$-Rm4Ef zrJETZz?kIxP?oq9<@_JYomi{(_b2&44EVzogkJ3D(2SKn9dAAvi2WyJuP?wwC0 zV+h~YQ;iV_xi2hU_f})S1qv0UJt_(pd+O6oj%^nUD)DaoDX0p6B7iJ8B-4#z#;Q~K zYFG!(cvH+-=F{W#nS$sXYp7qcCM;I_nWjKpeW+KVSScA6kF)dKY1_*+Z?=C zJSBX#>~n4_db8HOV~+cwYwcK;3;sd>bXS6Z{j1{Gd0&EAZdQK|%T9&T$J0u~P|c+N z>IN~BmX}9bD{(q_kt*D;_Lw@IpZAW5C^i6i+%Ipesjb-iJ>S+q;!y%sbi}?FLWko0 z$XyJuF@C19pXRV2)#NO(1|~FkwvfpVA1Ek1emd}uTsjcYXwCB(U<3y8a1B!LJ7;~1 zJNf>gqnV^joWH`zrv)(3{_^m;d$6}mPM(-_h6%n@4*SLJRB=+Jj|dunZJegx0QbEq zXAp*J!Tfo!^b}1KQ?-OaY}8l&@wirj??8eVP4yz`ZjJc=vH%3$>wqP6QiP_}MYr3v zxcnH;&i-wgoa~oKzoWxuPJ6?3(pbLP1}Kmw!!Zq2MuRsJR}oz~a|q zKtL-KZ|nS5Zj1m8+aP$a=?K>_v7iHgf;kw$k{eeazqipF9}%K37_t@8bivU;#%Cfs zXjBwHY0Op~x!U9B-nRe^pwytBex(@vtr@;ay+-3bN3n3{-&-#Mo%TJ#{JLJVdxLtL zp~Idk5s?3hfwWuHP>0)1s21cz{bg^%49DtIa%6-FN%)I@q1xee=htmz$q#C!^LA-A zc^ZJy^XhIJ3BA1E{C>6|fcx!y{PWemu8bI4lJl0PnZt9Q63+@}A-qdLME_s01&2NNx_K;K9!N z*!@Mx!JFnfH-Js9KY+c*J&DRpG!T3@cc}~CqW_%^>5zC{{hsJ{yd%oCRizxEZ1wD(3_Pd; zK&&?w#kQ3ftt=G&c2IDPCSnr2@f@BjnEJM~2agCmO<)|YXc5R?j|5PjWU_cPk{a?i zQGN`H>!#H(I<%E%PyRIRsPTq?@YmN_gf ze3FF`64}rC7wFyb_lG6>;@jtmCe3yU3y`1@?|4U11l3+7FH3?W6Y+#~hQ3`*MPD!& z(`A@|4=WD~N`HWZxy~Z=TTtG}_=l*?-qDo=r!*)Q3j!lT`Bh%-4W0Ao>`rFD;c+b9 zl72+khye~fI3#JmWU%7Vv0O1uy>LdL0i$ zWjR||L=(H*E@E6EgE0PA%0b8L%$gr_`3MoPn*lO=$rSxG+m=%Pj)WG}Yh6IjK>lJQw=@Cc}K?=AYI`u&S5U9b@O8p^53hstfGV|f^F8cC(+qnhOa-1UxkTvk(gPuP404D<7$bIVJoYX}kH?FBJ z<%5wCGL9%0(s2Ph`tS7$>#(IvV44cq@@AEMZP;I{h%kK$`OS;xpEJ+K5)hNbywg5z z!8Gq|FWgaYeuWV|B25xM|2wVG3$t#*c<%zS`vK*Nt%|Ih)!FldxtE|yzo-rC?S^Xm zM(DBYsmJmKAykDmLS~fuJ|O*v=({_K#OWbh@r-y-=YM4td;iHQysI$)r~y0 ztQ->Cz<}WmTfIgy91}lD9W=()efeRdiWJz4OQ5B0E2RDg=`2`p$3VH2#3W}wT>2dwpBCe>tFkHLQ>zse!&mL~?~H9tVNU_Lz%CrSx?`1aN33f+|G zaRY7Z4+`KkN`B0Sq59Zw!gkI9#>>0u-~O)vUV(ywFXTeSALv86jWLaI_8O3*l#OHD zu9O?uyavfL)NmWot2|-&0Ta0zBXEzr6lP9c90%fu(Gr8LzSD#=n&U}a=)7?a zHlu|s$F< zpCT#(;K8`hDM2|ZDIE$?3qT_kC9b1TA9xtKg;W>NFosOU8>&5bSG6&#V(E9yVbn1fc_q~iAWBBlajPu?zry=7@(h(_W3Y7*TcUeiA$i$(8$&Jl7t z$O5s~y$h;HZt(GEcTU>{&m;RoFo}~;gx0BAsvGTk78`DVhB+K58vOUAV!>?b51X&4 z89V|S>w9(e&^*VeUNXUu75dqyy?aQFK9nSdew`S+Y5o5%tm2|Sk8hX5(L`^)I4@Hn z`^%eg>ml0pR?NSGbxdOycJn1ug2uHm_XUev8mL{9Ebt3{*PH3Mr$KYMLjj{37>l{z zZ}4OPl?x|OjB__%Zw{+lUi=Lk1$;a!bA_482P5=1>pv1TY%7%2I~%cYpHvDbN5)Ij z*uvDZYHuQ)!iFu~ikq_pRfKHS>c{&zV-16BdVuZnpw-_jf+m-pNfv8JA!PTpJ^##) zGF{&fvT}XWFd_^l@1gq{aX4F0l@63H=okD)NM|e#Q!S`UPx32ro$PvJ_r_p;HXIv} zNciKr!@*}KsCMzex^H31T>qjaaNBm4mxT1p*ADkZi`Ryj-eT>qr!{8vX0(E3lZa5& zAL*`yb+U?$ZcHJB3Tr#VBISG8dbcC9FRvy0R|5Q}uxa-0(d2;$(o)pFnu5bhE(5;J z!>_xRc>n^bWnW3`7T1zGR#X%|>Od89uO{P?=l4OftZF`j$5$;udTyt^OmBW{WgNt6 zT{H>+jM)F<^ln#b{Pp$NNe~*)-CFsZ%j)It0M5?Y)QFf0|>DOOM-CDBJ*1;2-lTg=F!BrV) z-)DmfX&gW{SnIzNr|@OHTvm%X%GCFkZs(6(%J%c0HK`B8<$}`8imHlr>7;n)SgR>j z%Wo8J8MznMTWG8j`dNF!xUSb_{4u~dJHHsm#KyR3CP++Qd(h=S0D#nA0p}@;$k@oH zsDo4ITsIpB&IcX+3K(=L7l8}nsv27E8p>Wlew&-FD#)&XRW3*^{LvW1en{~xFFu( z7tg!e!DyfpLBd6@0#IzelS6B!XJA@ZjYehP7&!#(+xS4f9c$&4*S90#0mc!yTJ5#9iNw}*mCXED zs8B`ux;;)W?)|l@Yup7=jZ_DrO>FkcUy08a$DVkXaMEn#1(Fg02rJk-3~b#(ur! zz7F9L2$=dPb6I;lihi!yno;zrPDmob2&+4{s0?!Vxw#nr4W(*Et5ZZGg4)tPkp_UL z5)6Vnwtx36d~b3)?i~`~)|;*1n|_jS1TZU^A$T~mH^wizIV=Iq*G7*^y;1Fjdje8j zs^q=_55p0ET3t9f2~bZmP7+sr>Uqg=6juhIF#w#Azlev~esLF4h3q-44Wgh6jQna; zs)S#T@1+7G5t}f3B~vzRO^L!$ZRnIW`arRfrA9OCfI`T;72?V8xBFXU0_V=Nvpv3S>W?^v<1VcU=>d0)xWSUQZhuS5Xb2#T2oaKoYx!q|C~rpg7DA zm4)c<DQ#frJMHRR+0? zAmiTWR%Ql_Pw!GPuF=+TMqnlUCK=-oGneQ$leYtsb%ZEXj^Aln2+;top`mWl#U9vU z)SkQDJ-X25=cJghy0`}x;oneZqclV58{d3b=yJzj5FoE^zEX1%zHN+~A~$F=5~o-Y z7s;oHxU}%M!MauJ##eP8d+=NX>%aYX+ipfsy>6NmNQ*?qq8ar(!xs;j`rOzEeKZ*) zUI^d-A407i-%PLI%y2JS7$&N_gf{81*eOk7u+>db2zy4mF#*r%gLj&Y%4&lcdUw-hlGAodtPsza?to%R0uUUzCm03J=l&x$CViJ1UR=!QrF_=}kGf z$Um?D+CGFnap3|1U%}~xmvG|FkT;PY;tcZ!GHW+0C+UyY8Yy|?;558_NOjQC=}#8n zuU>ZmE{YYwWkDj~7Lbd^A28@Uf-sdR1(?=xK*D{=zSjr|0^ntS49Mic07$_3G5~D7 zVRFwj63HScs}+4n(CF3##dq%9y6`&XFE%7-4Dlv7VT72|0n;C4@oNmtgw)=-F?qGK zf5T^fm8iG)7(co0-7>!n(?iFl5&$8~_|l%K=s-0ny@D+0$#XUmEcNCe-D*TQ{2d7p zSing>VEEwN7y%G;P?d$D{C0EGGNt$3;VBxxPeAGm@eJjR)RR{JVXdt~T@jPZITcfl z=D>9_rnUC5wP~^WqR-FEB*zjcWYSUG5K%XR(!l(gzB~VJYtpRVUc-1GL{eqgP?UdwOv1AVaWDgqx@@Wg5bzEejU%$*X*zn z-uEio?X)MvmvmNXyiQ^W(U|?xkh|-&XToeq0VsvR0emaa3F#3*9Pg`+wUGcJF|v7$ z@`KXYfaS}~;H8;*Qxh4SN63r|I%kCdJeeDc91wnISppm2c4Mow^4+X{K>TORYNCB1 zRmTKd#~(5Gm+vkPrv41U*+@J|Hiuy^KQYd}(VtJ#NoQ?)xn3##k@se6oz1m1Xy z?`xwOoHMkB4T}v4!+4v(U;w#lu^RF1g)u(bK)BDH#_q;WZ%GgzSgHlbrJ47AXHl*R zmg~z_F>GWWJIE&>J*~@jM%2|Td6jQz2p{Wk2bvi~Rrx1%{!=v~%;uPvLJ9W4AWAv6)J8B?Li_(uA{v>r+oI~oWXa)ySS_(W+R=7mi zqnNZAn%7q`W`rH(F7A?mFC_ED%D$v*7Re#&OJ{x+$g{nMD+WefgH!F} zP>2>oM@LaQ2*xS8pVBTk>G*J_r}*2mr>w|0Zd$d>^j);yH(`9#UmS(-DsZqGoNJ4> z@4SFG_k8s)qhgWw3fR*M52a&);!1H15z}5Na$a{FyIWZ~e#HPB;4Nk*FrAtR z$Ny5M0ly2v$5e8csNa{}NQnlxiT35~O}kime>~zJ=Shd#^la=y(PXl_xXkH#+c)); zbg<6<+FI)=!{&DMIF@jUfKX$eiwqe_l{wt`sgIN$4m1 zhMifD#XVgAKEOzCk^vIHA!uTKwXuW<(H2nR10JEKe`EQnqCqos02L5^BT20HLeV8Q z-0#Za^UAAI+$Ph-a=G3ULS{zkd@FB751*k+^ngOn6e4@|bSNF~o3&og%N!LT(iC#j zAWs8039_)6I1C*{y@)`xq#bEiBmn#z37>z{dfO;puhm!@1(D_2hZtjLQjbC05$t62 zWB&M?*@gTqcs0dL$J*H!`m(#}{9fZqL`BU-_BDp5coy{;c}xl^XnB@l7j?G-a-nQx zOZGPyqg5}p(*Vp`izQMl00xk3UDO>elDt{k4y%xGj?Y`n z1G{UzCBbF`x_xE!LAy%az*N{H{3Fzm@7o?F zRB?O{_cq7Z1ZLA75w0I*{CjI=HdAW^o)V^{ljWoJH2!-qRX5cK?6Eint~zCwMmp^Q zQ<|Rg3|uBe?aESP^Qim%eqx^7VsYP3ZShiUetV0>h6dv@V4Nfyo^GfV_^VbMrAbu*aT|coEmetIB6$AXkw0JFk18;*dl5%m^ivIY; zvLun(Dcue{aB`c?57^!gg1Jq0=|+rpZco15xWvsqKSUS)S?7wB*C*qSXyggwHkpO< z6ie_SIiD)~^FMtrbgfN@0CY;%6uUz6J^DQvS~C z(ly%qoF%ysN}kShe{^_|GX>?Q@*bjjyq{M?!oa-y$362h!DJ)65^3+d1@gNMW<@MJX{~&nf%PPAi7u*Pkl%UqT;L{ID!`Y2nzMas zQK@;R&br;-)D`cXp1=i37riX3QxJK%xqc}Q?c2s>_$hy{v1a~NcCd=esyPW3lNn}H zC@iyM^DFzRddqOp|3cQdb(l8temy9W++6eH7YCn7wsx1+zW*TxViu4={S(Wg?oZ)D z6pcui{hz;rPnRw}w#B-1>kWBY_SA#jw5D5o7uc`zEd;D-nX+rHhATW$k*BHJu}C@# zWYL{h`2EMOF-ROg$H^=U`cGA0-@;Yo;%~e@oZHisYarD`A_0)jbNe)y7C|lIwM&f| zx-{5NO)GOMt50^Ii++)Yi|~=F+9buzbMju6;>{ruo=Jv0B5`3;N>p|~om9cs$QY7) z^iB*z!CU&$KsKEg&H4BKD*#x1!uXIoX%b(BnOK3=C5c8i_!&0eflMN$h7jo7T)6~$dNxp? zJns(4FvO=Wn>VXZ^lDW_IlXU?a1>01UM1fd;+T(*)@9F;k2Tz<^&y7pU(8ioCE&?5 z%Mx*%E^7GZvrxdu*$k21X{F|jSmO%yFn)0|JbUHW2QZglFMl@rP0(t0yQTK+voV;A z`H5{5;YW+wWkBFNe0}KY>A=WUJpl@1Baje2Y-_?|d5ghsS^FF_nqB61Hs5%ZrT*G* z7S%8y1tygE$>Rerf?bweLe=wQ-xmw{RR^zF7i&L^{PD0Sx#O{Q8;$|xMot7BwHl2E z;1X^Zi%K+`y;z8q#O_#pd)*HYD`F6Pl*h)fp_8&GmgrtojSCZY$6P7E#uz4TTfIB8 zqq6Nf%~6)6D-#)bmo~v(`^&I)HnxMJ+Cn473RKSRa%wqyjP=d|! z)ZgbqpulLc3t7h6mSb4@^}wA&8x{wepJTM93_ap*?4q#4T*A_b9oFKD45`2?hh0Q) zgD}u;Ue=}J^$tlRiF`P;*5>u`x283P4BZ>Fx?XW}1;i>go!Ibv>f|XS8k4Boj}=Jg z7q6`aJ0r`8n>JTQ8#w1r(3U#nms!dTjZl+KTdsr1!=#X0o$ zO^dwR{sh-YYIDEBm=zR@H|?Y1AY8yaO5SGfvUu_b6F?({&=}04cvTV>*Kfg?P~*yQ zq&_!yKAzvUWR}@*L4l7u6?an_)WbeuV`pZtfV^W^d~!B;O)-9m}+kkuz9(y<9Yk) zr@qr6GL{^p_rWqs)FQZzWb1UY$^yrngdrAceyN~I0IvDawY5zv@XP>J>!rNQUZ zuD3vPd!j_p^sMSDu`t#Y`0Ow#FH4qyB4+AS;}PmsNps8LQ6C>zKoNqyac;C%uk2CW2-!02{C{W)Lx5wl|(i z4i&{C@uM!o*zIQrP27gOn3+Q=EU#>Vi&}TX9@Wy$du-{^WEh9MljRXmK6};lso%b^ z-vPcMvIv?A(!L{ZkQ>e^Infy{di9D0U3`JJ@Y9DS(a!9`at*;(#Wk6Pnw$@uF;LAjgZcHb zd_A5VUW2_pPbOFR6$hyVsW6a6G9c=Zl!lT?9YH{`A?O4Njy)(zsBmj=SX>bxvB9K& zb7=?0KmTg*hHKOeZ%n~pUuSI*{>FkS`^sIV+mB23Sag1SsOrq~8+F2)4&d_A5dGC` zxN_7kn5?bP@y4j?h>_mWM_Q7z?w3l`J3SM6C@`Z&Xo&lv)Pq?$PdhHdZ>~#p-hN0? zT{$fLb7A_U)T@<;+#N=5)@u5>)v(oiuUglLVHTPOi@_$6s2J?j2prh@;{-cB&F)XI zpW2f9C!pSLjku^N3JpE!BH*Z77~iS;5J`&aK#*6+WVGaL%}F#E|K({HwL2eN6vpGx zQ0Gqr3_lX{oqw|?M*NKWbvupcN!#OVAX*x9`o;6xY4HWsg~aq_>$R{y>6B@Rp^jbT z%HJtuG9`*XtZsyouD7~8$*+$yzst7DaJ4G|wX^g|B`}0Pl5q{$P5YuJF5jm-^{!) zbQnlj2RvH`glDs_LKiu%t97RR1 zSR1*hZx!@7n$FDCc9Gf>{;M9$;(}snjWc zloRFpz=^yxOt6Q4)tMi4;KX8O&KG4A%!_SQMFQBVEf$8y=k0&A?s8K(IT~(!CtLhD zQP$^E_}=Oa;MDeb62ABv566P5N&s2FE+rD6k}e>W>_!P;6`p~b&vq;O`|lV92>lYm z4*mr0R#{<`9e#he>UgMX;p*zkmxBMIcTyW4ra1HF-VdFXkIf}eWz>gX`Qn$_YX0p;~>xp9L) z#9QSk-!+-p`JU}zoDs9>{sM0$SjJIrR<`^%zh;BgpWB|q_e%)4uUl`spUBS0WMCt$ zZW@)Q2&IW6LF@+#j(%RDTb=m^mot~x)>hu8yl-1)`1M|5%wC*iA^>__cH7%90fBeb z^8G*6(~*zxMDPAbgkLX$RQWW3Pgp{J234&#kF@u`|4csz%3a7$Tsj=>v-4|=aja50HPZh>{~Aya++0Tanz`ZYI7qDdsz8T(R)GS?1j0CQ z{3Eg==uJT%K)G`^Ne56atJN^~6(XY@VGIDMsh4lI6O7c5+I9@67a=EiUp&r5UGzGwy|1^^%22;Wi297e}l5iTd@dMXJuebG|r@+Aq828mzoKHvM!~e z_l7s3o~MrDWiW4es!6rk)J~By#?y>@z!za0O>do+^~PQ;Mb=cP@9fL^83ZtPFt5j8 zhRG#;eI4nQIBklG5d+1@SR zl)hDI5gl1w*nUUOw=QrKjmr}xE0uUDkYP;!T^rb_l+y}moS>aWIc{jJjR12THlorf zKL6c4tYbjdRngYOIR|r4p#dZPhtk|8k6b=wGX6cl19OY_~-Z%Ak3=AyP$T9A3!@7A*00 zH}8?(M+T1V+!MdJw5Bwcau{PV6Uf~>w9R~DaoYFDbB<-vXK+jGg?IPJ*p% z=gar+L;i5#LklsO>!0#}pa;K|*P7cpF}uBXp*wDDy{I*PSWRb7j1L*ll2DT6%OXbm z8tNVK-qrh<79bW^g0b4J@^ZV4FM}nG1uL0hhre_O*vDwfq z^DqwN0!DKcciRjynoKx6Q0wegpv;vk_OQKecv~-*yhIV&>ZSN)cEO3EQ}JJrW@lad zJs9$Tkwrx8#B0-uc9V+CffIoE>bX7QCR0d!$T_#-yp<4@eB0vK!o(p^mM0a9l=%ki z>RtK*Bm`d$ zT&V?@ugF-wUO%rG)E4Iar;$Jn{ZAv&l{v;Yc$yyV^|>RN20+!}53j=;CZgR>ok*KZ zeD=*8k19H2s_Gv9B=as zL}Vi|dZYY~K^JQISbQI!C*FKQObU;0Nvf$DHW540?_dLnzu}w_F=4hoPjp7ls?{;~?;F zVOnQf3;yxoAuKjA>OA_aU#&lN+Vkmpf%li*?^4# zpbQMy>KG~+J$9QN^$xRZ%mF+uB8B|&+1`5=<{OL~kSnr^ zk=kYKgNO~wGf@tk% zOCf#FIU&uG9eq2g2{GHuXGMD!{y+@RebOv?8EnmTLu+VBBN6F+Fkvqlf;N?9Yk}8f zW^&ZqI*RI z9>{AwG@|`jwQx+b>r!59iVVVPQ3m#F3l1L9=q76B7)KLT+Q87;hjAOc~y#yE6(M;Sh3lfrq?)%0C3wFO*J@5rpxgWeU zflD{&IWdKYbq176*GaZYAGDPp$`#qhz32Eoga9N=US<(*rpW!a=f!R+PmfzheCtw6xd0mJ9}spydClq4Ns zhAHkLX@=mamuQ6pZ}?ta=P1M zSEZQ<6LHkb>-8L~_phx%x!uQQ)HiGbc0w$a+3py*z0P7857eK&#kLFv zGD(%D&n9gej^-_~#py@9&slBwr@@a?QqyU1v3=1Ymit#&Zo`mRM-(0_&XMTa-w!-e zU!+8hJ4-#YA7w*+1(NFGZaB*w{wkJ}T((Xt`>P%>(r}I-a>(EIP)+*}9|+#ieHSlO z*M3_1B@ZB2%0A84&we;Ww=@Ij0T{Z{v9~TZTpeqqJJo!qZFWw|xjxf`K7-QAq+SZjR9GkBd)6neY${t5GE_)OAu21o&L*W#=Sf=gt|R`=-}&mSC}#9{;n`@ri0V$ z%>M^3&r84lLxBz5EA=ptCWI7!0&A{11_7gvY&c@7@+1cEk+%4;mJkl1cibXL7iM4H zh;$^GiqeDP!*zj2PTS<>@x;1UfOSUDgpUI4aBMecFaWZ~h)>hV#s}*V<&;d*TX-pG z3X}U<|Cx3Ky@M{qUf2?(pr`0{ykd~31~y`5>?~d|(9mKSMjm*`Q06gaw_;L~pVbQ1 z9zuXE?(5ZyzEhlj!*P_#j7i6RD8K-zy4h!X`PU3hCklO**Nz}%%e;12jpI*hb?01xF=id=?>9c_-0IKqDm@K+^=6=+Iq(_kIqdz|o#q|q4Zd%Mr;rtGi~;|? z%W)=orZCzrN@BiIK+*i3YQ1vUuE*jkc%~INdXTkIG*@!_$WtYy5$aF2{MgJY#l&q@ zmJ~o{1nd?va-FO}Y(2tDBJtqW9p}ej(Y?LqM6~39)#aH5llXwqFlVhXPQ=$WV!+Etp;zZqOHn4o^xAG~ACgRDJqdad9|QTO8^34M zK=N)&iXQe`%8%VCe5$tO@ZgHgzccG%MjpnU(+tkgTg=@wHLdO3e@ocaye2H0SagPdmO_dNDW_ z=J}XlV`nQmxAD%jntr3$J9phQx)!s5@?qe>!Mj4x?foxgC20z%`7a-hmcILWz~r)I zdFUjQBGbQg$j2NIb2P?i`mra?>I_;AVmk2)<@VN~(U-Ydf;0*~lL4MXLh*~%6$`d2 z#>e_&)Vp^+1y$8-+w6#^AfoO}LMg@g815|5K?D@8NMWCBv;Rm3JeuAO-MWZAv#c)S zjWR>kDxc2_1Ki{{{+n+cl+HX0E=0@*>1erQ=lP17oxJ1{P$c{Ph+!GQsS|06}A>>KJPA$;Qh<_OTHBUSG958=5N38dThK=+>CR z{iU7~k|_qZqE`*i$0Y8AF6&ZK(p|BE@T;EhwI$eO-^k8wDw;@7_3UG80s*e36MlYO z9(I#F7RyrlHmq+jL+)k%pAS<9u|JaZZyFp26<;rf82Hpc^(Xrp;^rrWiO**}x4Rcc z)Km2unYA!VIuT@T`ZaJ4*e@+{BPmR4t!BV(Fz?j6#Ts_i?^&<7+y&5vS_Yt=P^|(@ zM}R@zUh0yHO49;idPAARJhnM;49$QOC1VPT{_|yB`x;aj(QZnNDg4RHx+%SINW_$P z-tc|u8z#;7`tG{^M15$xHc#tPSLj`v9)Kd&hB4*eGzsqrIxCD(SQn)0RHi}vK70S4 zpv@Viyyp#-|LqS(#q?Z(7R1k{Xg?t$QyJ|Jf4}LgelyQ_suhdI2N=;@XVCTnac031 zLfw7PxqLIENIv*xdQB7ALIr>g36hBarwtlrj7n!FaZ5V4|Ruh|%>W{nRkI%IE)=n@SGY!Ji|>#J9KyM!bF z>0@HDmI_`4*VQJWO~u}=3cY3R$rs;k{@nxvPHf}5NP$2L7y{t1T?}Fq!;hf*|42#~ zh0wfA9V`q)M&Z8A(%qzaiA4IU$3H7i{RSU_1;T*A4W#RsHi3gI@tjMR$n2<;=_lyGnk^|h$I^bMQ9)~v)tj@7((I83ypvJ79K zO^gIUFDmj*IFiG3U9OQ?#d*V>F9!}x3lZN)(R3(reoJ-;Ki}FL_F@tf$_q2SM zTj_v>BbFXSGC(8gvq;Y;n+djkGD*EZ<})R)1B^p?uB{A&wh)@%-?S~MpO9E(BLb$Y z{hNmH9tG3aSzwIVTRZ-fpD4DS+kAykSU#bvMR7`~B~_Djknclhy5u3EM&!CKOpLoe z#ogR@T}>v41VG~Vkve;cM(Gnr&Q42IMax=%B2x37&;w14qJgBwm?I`x*b79L;s}yQ zCR7AvT;ji0{0-Qwraj-#{oW^UWvrWUx`*-3RvU#GwFs6|Um9q5Z9XrbHR8xVoGwva za_kQ-*ij>tTQ+J630J_xYspq5kjL7BjMk}Owl{D6;K%_XXXpmbEdDp5Kqt+yJoculomUY6 zccQ_h|3ltec(oO5Z=fLr2=4A~#odaxxI4w&-Cc^iJG8jFwODa2S}0PaXmNMQ3-|u+ zdw;}ZR#wg;Cpl+k_WribeCN*A-2b$#yXIMhIiX1rA9BLZH2xcoisUo0shHqc&hF|bQMEnvD&hdHwFPsT=w zp zEM?7c$V3A`<4$%7EjrfB@7-->!{Jq9J9uBKP4&f3F@tx_sbfp6|M|}T zYXFBJ)UFed-cF17l%{<5^dAn`(BwkSw%_(+Md>MzO?dBR(*Is()$tp%9%_;{P7odO zH?d--72#1C_5N?;RjD{2NuUCrZFvjQ!qsM1nI~pq+X=yPv*%qztQx>U(`!uv!x1~AIstw%mSP!BE z(gh%?xB>5hIvSOI$h>Lfb8BD_=={XvaKp?|y4vwDrZsvFcouXQ?oWJwKPZhEx$5e* zmOj<*6j_k8qUg_~0LZ$hboK^N$W*6SwVMy;pn{mC^;5{mK;OeCXJCK~FF3VX9`kCk z0;545DkiLd^lQJ(eHcJqIr^1G^O8I(!Sv%P{=@Cb2g*;n%j3E`5b=DG!82$?L-qTQ zu-u%h07~n}VB}Jo@Mg|J4>7uLJ`#|+Az+{0PKB@!W{|O!WFN+FxDao)V1pjtQ|di} z9tcYt>|(pk#Z#)Lo?|6>Vm)X4pz}#LEchWB}>H$23 zeN}qtZ-x^Any}_V%Gf&4X!$r=M}=51I$$}3!OsnBBb@m{c?>~i{nMf0NxVCen|srn z^6yMUwvu%H|RrTu!27!OYZKu9SnK}qJ5!8ucpP^R>OS`ETFkw=ndi%jEP>Q z&t$;H6Ppy14A$`K!MM;45a5H(_gl&H+mI!a&`dWKacAnVPA8RCt(H*nVccL)@SXf} zD2<^2oEjXQhJP0#0SGJ|He4UwQ3T5v*XII~`ji@(2!Rp7lu53j#WeDrZn@5jts2uD z*7Xi^VhBxxq#{7ZxV%NXl5l~klOpINJdf$;gowII<36QTJpx zLg1eo;K6Z1agW?l#-}nG{2@IIkerpFUmUU9LTl6h*;^&k&nz{{NkY4WTqZ?JtDDP} zC{TLRC^A<`YWGnCaZw5zd1x8BTNM#J%65uW8@9Bq3bc9H!i8h}w73$1FjIG7y>#E! z4+;*yb2wQ!&fjc}Z?B$uZ2ar~6OQl>p$R@N9soF*h<@1TTDg%)bGElO=^shgbZP;c zbI+Bh!9+oSQN=v7#yX^b_r&$39x40T_T;f91)wX-33UT#I=wX7kxwNC47}{1>?1+d z-607g7@ZxozKxsxdyKlUWmtwU0o4f0v9d<~>vssZrIhTfVC%l^(W{?b7evpXr}Wpo z$Dvl2e^oAyku0zZvS(WLg&X$V&1Vz1=lFGBNMZB8XQWh}=_y(pJ~bXm-+uYe>_qhS zVX!0j^%b3*#dp(g=6tXGzW#iBWE4b;&!FfmhzB}D3-9Q~2beM%-&G&0Lnodcgc1Tn z2@R)$gIiaL-X@Tp5FCyRN8dO$El0pD|9R3kM>BQoph=5a5s+1J+BW>3lV-d?bz>|K zT3Lu^AXtaAPaYqzfqqOp>y*xvT$k*6_$v;9SRCB^FMHJtMf4NOVe?nR}za6 zWUjMiY1U-y_?uql>Tn2Q9`A8cx&W;3{*L)?FM{7>pbe>rD-X-#*N4)MuRI}V;WwK> z_}jfDWip~Q92ot5#$Rl@;Qv1w>GLk^wfPE4s= zxN9kuj?>{<>!4u7lY3P@A-W)a9$K{C&Xd4S9T#Z_u(K`eK3vGlAwqM(_}(DsX#lZ9 z-VhT{&+xNvclq}ef-xvmhs6nw7BK)9aL;&HdzjaW@P&$X5B<437MbPR)TTRwZf z^n7_SZM>h4s4kp<|AGFCqzzd~(IzG`v(2vHqTe5X2~Dd|*x^?pthK#1K}pC(J73h} zZS%{?ozmq|Nju?IOKKxcSY~3-)+Y-r9S+ckV5rKyrPmu&@@Y-=VCuz3DzIDM>B%#YvD`eme0k+PYjfnq)0H@%zwCjD?Xc)d0jP1R}wr7aeFc50G zhQAWmV*W?*P*6g6c8|R4)olC^Vs3^%E3;yPtSwNWLTHR4=wgMPBVL<=eCb8gIAO6Q zOnvod;iuhk_kWZ-pAsYdvE5}WHHdwxm#a_BO*2TXvb3x-Rdsd-_jJPiuAm>Vj(gQB zN?6;b^&hM;2D^trC+AO5dWxOhlI7U~)9J|@=4$K;F;=!|&c9(8jHGeYTMkdEA@ZgI z3cTA+bw;1&uhMD;KAxf-&EAr{**Id5%r*9!TF!+~2kuCj?qU)>SO=vKo8kELe_=@zjal3>ym=tT#m^bo{1S@fj)ga&~xgmAlfhUE6^9JZ-|| zE&tk8iWX>@`G07p008a*3AUB!2xbgCw5`9+!KUK$0eyx$dTVX|GwS~vhrf2j%f6Ku zJFI*I=WSSih3bZ9%`2fxykT-Kg?hhGLtd#dw1AnNWs{<`o#^#R5A~4g1|d4QH|Jvx z8@BGFgV1ve`)=TZ`__NxqbDJ`zB_BdBUOBLX5&JEvxS>3zNb8}$BO?K{;8 zSO>#+#c$@&>22iR(E9pK$3%iHMgLz=o=XTG0+e(k_*L}YUb9AidG^!8ulNH@JTR{- zB6DsjBzTKyr8SD)={4*%Ww4pYJ$h`EWx*L6c@LjYFjQrhi1p5dLu6QL5=@wDWuX_D zVFa$QNim1v;bLDS+W^Ub8JHE%7p{2x`_RYT>wag%){5TqG|ab`+d4e^h8*9{ojg*T zyVpho&7gN_7SgA8(BGaLf4o|UQTNWNvlJQy>HSPI8t|&~Z>Wl> zeWR_h8>`QL8g5LjRg4fT2ajSgz>29ZqRz`?p)Qo|2)Yzk_f}tVRoBb?m5dHdU@oHr;v(vJw zM?`JR0pP&G_FiB2EM5NU_nq(?7Z$LG3d~h2`3^;dhjeBKwWS~%>T+~s70hx$5?P;2FxblghG-UAl4=jMdib*eoj zewMr0^MhtDsURcm^)m?^IR6N<s|?u*ODX*T%Q$8?I+Cz@15h!D@?^KZU2B5SY$0WjufS>s>>VRiS>2yW_F^!3CE zLXHifvqx#+TY`3%o9>=RBG?qj)EjiXE5TX_G5d@_o*YqBROGCs1v5b)@WX5%=RF$K z5yCgen|(~bIU7)LJ0XYcJ<`?!8aT(mS;)pIenFXSY~TORWwU$BKfvq{-EBB$Z?btT zud!yXe1ytk5*etjGs5p}qXhBP@yQBQ_kX^q``SA3kb>V*MWDs&^_FzlXC#*UpP4;$ zul4Z~=4cIXSq{bz6ks_I{7->*heNrHj-NHVr{CgdE3uJ(o^RQij%OAJqOLbjvJ==M z*!Si&mB7M~UnGthUGb~LO>0q;-n8kVy%kU+KD#3oszVp;ESuir*AaFdbDkpD_7gMO zM`$i%WT}8cry3Z&3=ir$>{a@^`M!whG~bE!g?_&U48ISI3HC(wr_FSDEz}dd78QP3 zFofcnSPCY^kXJL=b0YMS$wQF59bdga(6B=n@F6n5w&2r$sd`EYTi{^BS*yMFX~cU{ zaw2r3Q9~M~DQXygOt-RwSKF`tSeqZ6oQ<^IEHDy;jv#Dr#8kItGCVQ2f398!lwDI$q;85&a*q z{r~=+SpqF01U|iNfYuwRh(hbk*{FMuTgj` z@SNI2mbn>~Az*k@cwLs9%;KVL_5_U?PV0FI>shmTyV)`i2ZI*W(68XH1`x4&#ZmV< zGizzGjy&=Wk^MC{(co1qcaaTD08)+(O|ePf`|dt3kuXW}wR2OIBspJ(C~&2rKKKh zAM8rQHUGuC~6U(hLz$@&YP~8%JVViF(+BQnU0()66bxHtl9hb1mFbN$+M03ysdvJ z*&opOnH3e+U|4xWzC@Po2>{l1em#`35=a=h&TVlLZtkYpE5W`jiA|d_a$&Xv?I6MC zD`(sYBDp)jw#HZlkm+ijWaW^DR9X5hWqnTdqi97NtPk!E=&PQ~m4|pQ7~EBCNv`HZ zBpNxwdHuqtxG;du5x<3wtfitNfC+jG2Eatx06@?q80d=#`hren5%7Qi0RoC(|G(q6 z4;k1qdjSA3z+3p_4RhSR>}0T%f7W@MjgCGxpt>L?*YuU&QbTFy1M7+h<|ffU;XxQy zV_05iA#u1jIx<>(%DR^fkJ=Ysr@}bu1i<|Nziqaz zrxsJPW?kAM+xw(4XpzBA&$TtOC1|1pFMla8#QHb@j`ZB&ec$)~c%RPQ+E-f6p(=aQ z^Ml=CfCWy&()auR8-*%&+Xfv&=kEWq|5eGdJ{w;=DJ#(ae8(<4u{xH`4_}lzL$cVz z$}&yF_7q5UYDBik_{~R}1lSX87k)L&C9wU`zb1gZpf~Hh3;o5r_THW0=eu(pyi)@( z%m^Sn$+yVf5eReltue|lx3SAGke-q zDu+(f>UT3frS$>o%pxO?34+mJ-IKl%E1oIIwL-Kr`j!Ygth!o2^_h8xt!PPW%4k5< zh+r$j%fEZ|+=J=fHMgn{bC(}uuztr}CjI&S4IO&t?&QPC-C>$1BeoSt)4zyI7NQ@Q zWg$1lJ5X}XC~na0B(T70(E{~8osl7HuGI`3Ch}L}7@i7Nx<70Fr?vW1d`^BF)7M^n zFplAFPFQeQA4hOs20?IQRS!h9e^84oZK__h^L6aK)ekcO4BrqvhBHwxeG$PaUuBE# z_4c0R^xb~pv=2nD|3^@<+0w*D z@8kCouYA!y7u~?AdCV|M!(%mv$!g32w$|R30N?bf4W9q#01PtB5iCt}QBYeI_e4KF zwrJP=9)FG`LeVx1j1`cd?C99?A5`o&DV!-lJIKK{=Qs8rTwn@(HrX5@YoEB<(S(-+ z1T-+5QTkL^%5&qOqaGY4R*i8!&xzSX_xT)-3RYPCQ9%SM)0*sPn-2*v1bxzW+~ykI zm9hGrYPEUVXyoNT?Lh2z-^2PEBZ5bJozf0hr?Cme24@=KM>ul2%m5M2jj6G#S7TW| zLZ|e5+}-6a5J`S*KHC4@KSIdu+dSNE;{B_}YFr6D^AW`}3erk`EoO}jD#@Hc{VCoD zZAEMt&Z>X_7(XwkL+$R4l-D@<{Cx$$AGp>dsA&JDz{uQmzC?)K5WQP3J;N5?nHxf1 zMLNq(Gy~ki40L;7I71u%I>z}(R~DpOs_S+mTj#{jDKBW?0T$&V!kI3Z((n`Ce}^;# z51RaJ-V(xk(qtQbcIC~u@2q2M`5h?)U7-!VQyATf4+CrRPeS@t*)5-ZRsRT_K|Vkq z>j_mturLA)Az+7(=5OLv8M`lo;{vkZe@efwfOAaYVzc2KN!xwDPWqWAJ0 zwhN>Qf8o_r^EJZ4;g2v0=n)7L#6ed7GToTt<;7|6ASQX=#Wvu~cR~arft}%*xoz8q zLKRNGpX%|GMK{$;xvvn=i|-9Mw?c#Yn4l(84Solk?!DkAH@9XOAau6Q1I|xBpY6Tj zsVx(-%eFECqDWSn+dAoasmFj9#sM2BO$z02JxF|83h%~?{q*!taIhKR8_X}V+w3vA z_1msXA;fJ(`AZ}B@ZQKiuXfk}j3j|E6mg7$@e{xJ^$5_LKvrX(@XJq2USW)s`27Ei z%?096Bo%>e{hs_End%dh5E}~Znh3fW&!r=~TO`MMv16q&rdYc8EG`7U376Et_NE4J ztw5r$P{Xz8uEg=vl2>73nO8Kp19I(k=cqyn9e!~G0Y1n7yM$Pu{6y~oCy%sklK`C^ zHLH-Z^5*(WZp$QK)1yG19>2Qh-#wl4Vd);;^Hi);+5X(RY3t#B`t^QSiYGt%pFOet zpa1R80TRfbvrU^9-`0g|yNZShMC)ic@SHHeSkL#UubUAnl1;xcCsYYbDIQ<;2v zm#5+8>#`0(726B+{Lj!IFoEP+IoM7gu=|ItJg5;ZyY0S?!LO_xlIEHM3RDFqh&7@q z^?Fp*VbvM*`|s-~R7gQO^mr(;j366>E37C>ORo} z|Ic;yGAx%HN9`F4R0ub_J#PQGNoQybmB71hE3EZWxp{FGiAeWkV^Do{sW8c9$ih}? zPp;7PT0_ONp6P6uCedM|?yHU>cBb*uaK(M0z0c@Q!JlYk$P%9mSN^f|sCX61ub041 zIkn!NeYL6d(QY@6#AT#)?D2;MFPDN>0(6}FW+aT!Kl)iJNRRBjbDYwu(yj~qR?BFX z7^mTPH%DA-$u}!pr%*y?7kCm!HyaVHKY#aRk&xaaQ~|Wp<0$1D0!Z0P>l4H+aQy4o z?@pbf>G^eR@po(SW$2_Z*N#rDiX{r7(BDOtNdNi?S){yn(T9H0GGyoHTW9$fF#zr3 z%O@UNi@h<~gDf0C(Zrle+`MeASD{vgtHHHYR0#jp;ulLmO?@c-Q-NkI_d`cai2kJl zVybuvK``SLzr$bb`Uk^fgq5Pyxit3)lzEzxH5)V_8gK+3cpoyv$}BJ=KYaCGeu$|T zTmrH( zT_eh%f*`FJ-psq+WjK%hH*XW_%;2>vRcuFVY5e?1C}RzDXiHR^+S%^e$PqNEir>c3 z+HYu4Y*z8co&C6>~FyPd3AL-?=W!F=uu#I~+|pm8TuT*{U^s_8TX7=n}xZHv50 z;H_5>RfM$n)3~V%YDM(QFQ2dr9>bSRfK$kPd{cmqo60x0WFb;ny%!1d9Zkw>;&!x@ z0jk(L%f+gC`#}31cD~$09r~ekeZlO@^%!kzHwoi7gF|1?3_$C^=d1@pn50gf=xAK@R(AnRtKW{&+sO5HAO2Qh$GAbl)_)-IjXK z|Ibylp!0n_Yt+iaEC=93?4;8!TzKy#=b_Q?=qqf#n-DG^q+-J9{nF4Ea*x2@d_RNC zjdz@<-i#eCSO*x?;is(-p!>%tHQ=&H=r1{dc`yjLsi%N7ZvXDW?qv=Kmc2ke?kL5p zMR=nQ**Aal+{ggjdQ)r$SOKoO;V+j6zbEb#zoOSvzM4eG>kT?B!dB z#V>PXd};ibi+Xk5h1s{dk`kL%)(fq45_q(G$jpYmFy3mvyE+B!M+sWU{=ZWx-cuK>mP z4SI+g=c#paywq=SPdA+!EQ%4xYr=v@G$8%>L8wmBNSVpzYYCLXu^VVQ3FrG(h691# z7G#k;B@o}<$c7qQi6K{thohkis(lj!-j@LWcQ#-}wV?ZV)4sKZoAlnUvBevu|F&8J z|Gs~w=l@x%R@vO|LOkWJ!SmYn_q2>hynN9K-k9|L2nT=^-umTKX6c~2@Z2^s3#n^* zs&p59oyW;O+cu<1?F`JEk4Z!jl@%0g{<-H}$OF=qWza$@3Ey$@HqyH%W<{tfH!Uv97lD#EEUuuUsi6 zH60B&?sh-pdT0^gO6EmWHRXu)G~8nNr{B)WLu&UO_bL)Ws7z%xlDfrxj;q;BHdS$W za_CeWA;Z^RhwN+2FpRV6K9=9 z-f=eMg@xnR0rAUBi<4yuq5M^?61tNb69#v$KxIbf07$L(8YF}6R~mM!R`$YWEP`au zojSjxmph7>leTc_RG=#Qa|n85;Ocmel&zQc7=!Cx30aKx&7ZW0tiu!bL}xxlG$~{? zq+WC<4%K;;g)D8@PIjLugou6LO=3)$#3}eAH!v7LC%pyNM?a-_r41!R^WMuE< z5C%m(z_2QKunml+s&!1YX$fts>!k&I*_gA$(=;{Q1&dv`@;ft;rUFTLoqP(@s>Jh( z(TJntkAms3xs~<-?l2*1nDZAMI>}#;7`GhkNWK-^m^fICVCCG+BmRh@#fF-++7a=) znO!-!m`J_zqxA`>xV+Sr`8Z^l!k4jP*5`b;i4P*Mkew z6z28sw=??js4Z|(mIa+?qAbVz1DWCOPp?{Xj0%X;>~9Egd6f#H&QeRWZ|O}v^5ncG3S#Xm+!q4=1(k#`>CpN(jgwvFNC1pKozES>HWu z+EZV6=2v;K^C|sh+slD)%j&k{V}h<6^&@8#elp%(X@!+!?%-$Pa*xJMwA^4)izMzZ6SJVEh_t)DzTlh}m1fQ5%@uy=}_+%-Y8q+j} zsPO9Z6pmzc2dDTyvrTQ2%6?wetmf^$ZD0teLsZ?+uAgw*L-KvdrkiOvo+En=8(K3Fi731hFbh^ z$9dBPL9uI2wCc13ynd{+)+J2Lr#r<{>?0}GZ%GI^Av!)?mYRB=KPkU*+-_@I?cgu3 z8MjH0dwkER-Z!TDJ7$1*60Pb2wbn~+_y~ccl4ivw2d|8fAQAJApPHSZKqz_e9%xs? z?!$}IH1^DZ-SKC|=f*ZK7Sp90v>V#h3Anm6P+Zb#9>lj`@S<#;e9}8b@o9rs- zlhrYlvYIS`d}ZBX$AETQUiWvk=~LUaDcrKk+86)6d!C)vxnY3cf)j=lQ0Zg(_{Lss zo3*1@fx9zj3Q^l%UCe0Yd09*bc|BUj2TS*6x_>;5i?Nzl=g)thpmjOY4rP5vG>)=hrih!{oh02YdnpBJkU`vVKJmNR?;!T~v z0iTeO!Njw%YfH=RrrS}#oW9*uq>yIVo}=wc!_$UAeOBb94WNgXU}-aLQE=Uh_o}aj zGXr;)Tsfz6Hr$xbEz)qgo!wiP15xM_rf(lsh3ux_$?&sqy6Te&WwrmBIsJKnO7dH3rR6eq*JONdCpa?*}FCe!T9+czBkYlRJ|BSEXIL z(!zAfiKXe+_fGEcPg+TMzNbyAc^i^ubwphpLfd8DDT}YUeszkmA2m`PFgk1|+Ybx0 zZfVs-44xgWeB%eycb!w z>g`KtQ;6?V7iX29qF*{y&!@Uk1)jI!$^+mp+PlQD8^H9A;(g?##{;sJ4?c#@w!-+OHcfQAzGdQpfnv->VbL-R3Oxamo z6Q-&g_&Yl#dpTi%1bL3D%TGmtqO|?UFksRWf6AtgD2O-RIqaycpmdckc1rhcku~Y= zX)XQ`0Q|jemKPaUpchVUE`p{dO=^R&GS(=6TKD@!XY_CEr$$@h7MI9d))41JdDx;Y zL^2EJAFcE15>m!cPCVZ8ypkaM%P&&iIzi!3HaPxDxX{*KWuvqYJq#J=7d@)5UDg0P z=?045an1RbCiIPvG>siDKTtE}{QS>&chqK6+hbYcMoR4AUmxMVi(U-&-c*>5Q@tL! z+7D)yBC>a}V+|(=z;XTh8y%OOks)`#ke5%>FEQDuKw@*Ezlk4;B8s%hCuE63n8a(h zT;)>)j{QpYj$O55k75S#O-7DOJ)iT4Ux%2T`b+SHT-=sMoW&?+05moEyfXmM;i|J| zzY|@xLD)48zFKOZQwHvPk05OF;3`>TdZ%X0R0EC3>jv6*;Go&}G;S-p>P5;rPBQE{ z$3JLmd(H));5pH0__+bfJ&q5kgVZePq6kC)Fyc!3Hw^5&FPQm7*vi}h#e}@hgs2MK zi4!|OFlpS+ijts7wC-5|xH5Xi$xc*6<9;u!Hf9+UR!oO_C8RBPuiyW7W?w`Uyax11 zg!}&Q9ZLfjuYFJv=tw5XvkcGe#Cd{^00EuQ4l=%V(EZS|u5c>^5EWHIOL6!~4=Wyn zD2g1{S>zpV)wY0_QVL75g$3p@OQqjM-bPX(ph_o+m1#*!g$;x*0*vz4T?r=TfH#Zb zG|X&CpNqdr85OUJn@wnroq#DAPKbq)5uhW;_E5LP`taE1O~C!`b-|!ULGy4{2Z=4Y zkVSqrVixmvH0Bp2+W|bR+1ye~O;)w@SoM>S;8d|^R4#kaa;Q>AfT*Gu-$+Mo>9K;ux}a(#d9P^g_vx_BaxX=?PPJy zD1DhSQ3izbYj4mY~isCbk*Zc)XXKn*|q~#65W%Y~zct-P+Zn9%KK`(_HS^8av=J>)9S}yVoxX~D2HvflCs5~SO&RbH@ElZ#a_(b~b_69O zD}ExsRfRZ4dVx%0CVaRof6bdXMHWs!Dn;qUGhJg@4P9|vTI0j`)3n|+p*0=+va4B= z60{)9&n&rp9VV2f(4ktnU%z<_c;y2J>Y~Vs&%M@XhQ4@ezf#NF(H^CS=9AJba3U$P z+fCn1TMdESf1f}bLyF!;IW4+E2}C%%V{_! zsu?zAF#PC8D*+G?aJ^|}TKQSe{@<83sqgks+Lj8Y!QoFq53h>V1g~v^;DoU2d-tdu zEE`l7F$T@0RLfw6s4LSH`{-Rd)rm3-5}XmkjN;r!DS3>7B_wXiOWZl*Y>TbIpC<*u`az1@&JklUDVJhgcoih)1TX5levC}!h$L^ z9p&$3it7YfBfqf)qu`C50FjogRstPlI-k+fx_I4A=EeEE>4O2-XkE`22mTmWpPMy0}-mJlvUuYfY?n!&;lE z=%|foFpkK)6{12vpP((as-3gH=R-ne`9D;K+>q!fU;(Vr;S22QsBv8D5mc zo}^o2Dhhb|UmFjV6n^U`JR56sV7evX3<+`}=Iw;c8WIVj6NpB_cP+r75%&)W&;Kba5 zGAwBZ$CA@Xr+wnjXh~%f_RCVVsL-Nh%0K+h4>UgD=SIC+scc~^kdb>SoE3zpv~M2_ zcZmMI0)`a`>p#!Ka|;iGJ#<_ouPh`&FBa7KUR)!WwP5uzZY1*vBf!Y=OK9h7MMaX} z^6LLLPbu5ueVHTN(MD338P43BsM+mHa=l=KGTrW9u6nb&-DRG-ufZX9fg z)0&3m{#sLt&0wtHU0jC@6tO`A7lW6hu$Yppi+6(&>vnYIXC@^Q@PKrIxxl0=BO*-9 zps!3aE;W#DCxA0#wjWIK38ObH%3s#4j)9ejLxlUb|wEVH?FFY(ak? z^&L=<74a3Q4g*U3vo_&!ArjN!h9&@G`xTy8Qf@k9#4vZ;cTo)4YISf51pJ&URf)CA zyG5(l$3nG`6tddFqt?1UI`;KX8&%wzdL33_Fvm zu&(NykSDoYj6_NI-3H(R1nAcoQ%6AL9Md16x<0YvTxB9*?#@fO2r@|Zcc1&Y61KL zXK;}{1?vysIdaS%+dRrR!#51ZW=Ihky!fW3TwieuG70c%^^!RZ8!vQL5UR!7AL7SO z0VnlYxiY%B(3zFK#?EK`80@nyAjw;jg%?{DQ)nlFX-!tU^z5%UZ%LXlL^{N7;g84A z2=K%8Kefq!Z@Ux1CQxkc;c#QhQX*@BHqvBqEvbk#~o|z#7L;b5-h1O>iIQPid9uSA*5Qup9B3XX`0ngCo+^Tw}FrbJU5aS ze2t*Slj58#d^Pt@VVoP_vZBciL;(ygW$?`Jh##Er*0p9HDdRDf4+p5FB-|wuhT0IK zzo1>sGQtn8H%y6!R9Zk7^v}RH0xkKaure*{V2Z$cPd?0 z2+Bc6yFof1BZH=6mUrZR2R^9`6|a#0aubvJ$6tor9Z|-9t2mN-ii$l(#(1cxrGT68 z2e%C!Oud!&N(SiT!X??!A`TCLMOcg=iMKLLdMA}UwdMdzTk~42Dz0Q z69%*0<)I}%>n{^OQA*#AGt%;vVcEl1r6V~giUh7U^?~h_Jx7Y zTfcwP=@ev9*mDp@%5K?Z(Gi*u_gs}PF2OKG@uhZqlinCh%F(}BWIePMe;muWj(n+( z8Cc@t^a#-T0Z1F<_UO(c5w z?AfQymbcyG4TKTCQ{CU*@sf}B*D{~`F|xhVZE!@ZJVy%_1-gEh;Edbger4tKQDmN- zrdtT-s^JG)-W5uD6t($eE4b`^Nv5o_2Jyl;}Sng^I$>BS|2O=qnc{9Nzh3` z^wYdCd_&}wkJPuzoG3mN#5saWwJJ{3gI?)tna>#aAL8BkozYMj;SS9NS7bNMOW#|( z6RV9A2=&{Zyem2Jd)oPKxk0kKVtK|dZ|Ca?0-IfgfHiX zL(CW?dmLb{j8;8qo<4?=tayP}2RDxv9D9UeZay?aw?j*(YRtm7&C;+;wk~Z4?gjP- z#n_WTwubmd8?dS2l#eF1{#~roco8~eYi$a>ZIY)qn>KvrVN|m9{(&g2WiaYZ2w=8 z1i@qtlWhANK~>^S)EbU&S1YyN{G<*k>r?|WM&ZB+Sjiek?&U5{Vxa7s%yc#Zjc>+nwp#5n*JAm7;f| zDKg0QA^7O>dxe>?RF6_#4BQ&Ml*n5Ia>%bM?TRn6TsE=yo3oxr#XD*m!zAH!7(eAh?#y5=GSYm)9XCkA zT|Rop5pzZcXuQ)3vS~^`OeZd6y3yT+mWEZX#-&SdKFvweq3BF}>|Rkd!?-?;^P2kJ zn72&EQW{TY6r^!bIl}2~=LR<&vQzSJO@0BZLOfaQ*4fyO)bsp!W{=3*&@PvIGV6e-eR?6v!@#df;E>WAe4-!65?91=NYQD+f74p_ zZaY!hoSaQHAnR`(AY;I zCe;2|qJr~I`SPYkViJ!7?Q(T3=5u8)WG&|4T5m-xs=<l6RcW6k#0$#K!KUIc6 zxoDQ(W9v>|pur&7-`8E=U;dq#8qr;)_kmx;xVg5K42ZgX>UB z-_;YN0LvojM2NkuUI&M1-o1#m$ST8VW=94bhW_l}WJs5+fw zdR$wqu+s}C$$?+A8U{lpX?@^qMVGxU;$HkYaZz2!3%#x}r56u?7^Ds=d>3ebLw$`6 zAKYrQxOMee^|uck5jOLM{I2rBKB9ETj)k7YxDxi`m#eQW`*+i@d#TrBS#^U5zpbDd zeBX8b5LYFm$bjj?>hU<@O)s4e1%iTjDEOgIxNq)5r~Px0{Ou-PfH*de!RF z9Yn3|WqYlRZ{wj;5oE z0r$`TPGjhWg2=C7rp4j6sh*PQC9>Uj@#`o7<$njbFeposN-saYMf(h_D`#!w^oxxB z1wUUrMlxEr!cb-DDbO4{NhqimZ>xtIkbYEd5u)h?{`g#Vt93SCeKi~0_(8aELEZSd ztwU8jPPHE1rRAy5tU%*o%?;@1@?`7i6HE>4x?}B4uTQVu?!UPL#!97Fw?p;eKyk!R zh^#(V7l9!$2aIzaJ_VH3v;4Z~qcA%Td>8j{`SUC;6kA-jRoBje;i! z^cu}gscQ7^#`lJ|4RZ4iy3`P{bNK5?5Up^Eq6jT7B^p8d`Q*q~;?vI(a&ejAM8;GGN$z3`3UXSdyGN9KE_$l55kd`p|Hb=N z_QVRjXJ^&K+vOxz^~%TrgP~#n3Vscn;asuGDogQYf*hNF7>iEftu$y{u>*;Q3jvU!M zkYAX6k}_urM6MiKaA#=?*?uBYeFz}|0}9SnGb8#5i%R+|k!vc)64W<*VOWB#@*fsU z1>t|_2LY7qLSVsB8qVV4WJ@L4q|;U7MT0xDEl#uz%W@6lfr*86Gk3uq&NSlI<_GTx z`^(a`S$gwGOc;E3V2eDExSqB~E};9dBx$X`)rP+J{~!d|(buWNFPm^R<08lY@zEnt zE1N9rTxm+(FQS`EW=ha+ML^Yxl2S4LP~Q5_Lm+!jdHHbf?=p)YsMvVOk+ioS zSE2;!S-9CddPW!yRc1QLsemx&P-sb*`cB-abq;rk|XBI z5h|hFtF5$=3gW7}ffou!nq)8~GWJb`NBN}Q)}o?ijsX$Q#aMJ2>i)r`2!rZKi4jl+ zcBN=vF)@bCFgIGgxTMa5;jFQxzWbTcqQB_JFKLIgW#n%1+b-nXtcpW9tXbIXl)2P? zgqorXEG7Yy@!dZ((rBwns|wF(J(NXLm;tT% zd}=t{ezKFkGCCcu)qBvCrkw<5>?masiq}q3#?0?VNIl)C+X(ggU7~2S80K=+XET7K zM&;FQ^!H7aRRLy7zsxHNXIk`}GA{vnUq?bAznIU^)U#71wfaNp!8AQxJISiuw2mNzeY)XX)vQ!rJzMMMW)r}Y!9JH=2p*{ z@8AZsS)Q4|0#nj0lhj@bgXvcAD7 zbEE%mF2!s+^lQQ7)=B)Z4q#Wf4^$ZYkdOfq5^z4kTMZp2|2wT$bIOprp|?!e8dAwL z?t*E-dIGPqEC5t^cirE7cMy{&?O+rqKUNwb2ltszbv@Bk;vrFqTFd=bK`S zFCxJ#2$QF>Lz-Zp1~HUBwMn#0>dP3um@AJvqqDquDpfi}suUgoqg1InenJ-yN*uUW|%eU7_ci{&@;D;7+>#+O{>VM#EZ zM`?<0TA?c&TgcQcm*`%ihfIU&^y6aRsoa;#dmVjhr%0?ZyBesrNZS{oId z$M)V>k>ycFJlI=hi`V(u@%8>Po#k_O^nFlZImMZq&vYzCEuLJ4F^`)USWELK=$k^l z=2fnr=Ft~aO4O$Dp{aH}PPq*v?4th%>Od90dIpMAfZ^)&u0R@u$$+T;`T4A6W_Cna z@2v-+b1*nKLgM#8V+@Rs?1@=1LqS3ut-Ja;uwr3wS<8PR>f~gA`B)KrKUb0_)YP|R zJ|U(bxP?+buxyC~(CNgJF?ZDZmrjjJ3nR7vNf_Bci!mk+h`BN^&KtHCnwMC|Z=TFr zrfTU?$!rM57M_}L_!`l`J82}X=hxkCmU6t*w`~4@q0r!e)5{0ag|Wb!J+2bNclR9LAWmhQ zwNRP}Ob}3EwT^~bs!J>B>JKIld^(cW2_Q&+i~Zf+Q}c)T6Yhrws8eHrq;m_@`eaN* zqw;W5seEMzAc4}_ZpAua!jQDv$WOq&#p8W)Ph*9~Wp<1@4fwAFFtu<9K-})F2Ie{* zS#n`i1si-_CS?w=5f*z|mZ(oe+kvOyJO$I3nA|6P=NalF$gD}ZF_xt-ur&aU2 zFE?$JKuD^>*G6}Pwvmq?r?%A{V-wq;5kO7*iW0Y=dcQQ6)~lQZ1@N>0&X_vYAdWP& z8q~9=F~?B)w_oTF7(K%F#bKTwZU*{GV5=@t;;x{_5&ZV!7U#2mRJI1E9|Q zpMC!EnqJo=b)VP6Wo3(lZql3YJSjPSRPI!7yNL?EH}`$^F7KUxBeNY#q@_t7m$cZI zF+4k>`kz3G5P8)8NK6n3-iH!t{i}!PSEOFZBc+B}Hl$-^`Ij?fRT44Y^yCc)ywXb| zSkNpy`XTW38b5PRNaIS17O+h)U)!aQ0P*fsE2#o=)VHh$M<*OFVd7}Krb5=Di@TD! z0vF~BoRIv9=U*2ywW$M7f08HhJCeU%nre0$;aqeD5Dzd5xzoZskg~ za$Z|nn&@V)JoGqW`e$le@&)tv0033bvL)HVH|H}OGdd@em>oJ?tGuB6q zNMqpIeX2hYxJe<<^EOOsaAW=(&$#g!zy#ugy?!j?oAZ-+(2F68jaUhGQ^f4%s_M^+ zuod)vr%l^6CV{)_MOAT=Ux2g&L?RHP_LZ5G%~S_r%c)cp$fOgDK;xMo{S1gdW)oX? zLG!z{TCs$GS!(}>a{2>iJ2)TeJkD*Y2@a&ZO(~}V=Bm?^l5hp1)5=wGLf)K2bj*n7 z$Bd)pvv6yv{~-)vx&%WAqK-@{xwt(qKI`qcp8)5- z4inIkj(gCFV*ok`KP_ZI{5tu?`Tn>z zTU1B@h>Mua=RK*b<5Ht4uf7P_^0q?Oq(euYEixv8)*h5da6|c4)YNNAcZ;|EEFo)> z*2Xfdi*FM!g<+WO-KBR|K}@ju10#y};MDhr2SwTZ%VGkmHncJbK@8OXjI0#`#C}YQ zQ_Uz-6}bs6C|MD?3LtQ^WAgGB{BZn3%B3CW{Tt4os0hM9Cr1=oDXIkQ#BWMft2K}& zprr+{P<4L}f`C}~Q@)pcN4svp^J;m)RSdvj>_Eo=9JHcseuvj;-18^2^k=mR1|si2 zYG>-6lOG-FDJX<87@N1vWomd?sKP^%%!;5Ou~w)sC<<3r>>Rb?jkvsWIcByKL6*8_ z@&z=3TM5A{=#S{Xsa52ytu7N<2h`+9{A6FuspK&0qh$%uN%-1u2E94K5^(0K16x0~ zd7yxS2qw>cDuq`bIaBQ||smfTQ?b^b~G51j?MMimLfsty28i%}-V5Fj_6< zC)3iZpzRgj4|i^~#(3Ch90PC|WRAi2sJc&&r>rWKqCX_5!GS7t20I2IXljZeQsAQM zx@J~3=2uUq72@YBmc42oj#aHQ+mfmalEWS;*CN*@i5;hLjr`@TSNzrcyEYboS_z7% zz(^&=`FzSEZesh<&O}AHAi4o(NeKL1X)`cuka~7m>V6XZJe0PC-%8SUGzkv79-vST z{*c7yWL}mv!QZCv714)DU6@qyCBX*M3Gwf&k!vqP;Hf!F=A~(AP2|(^Kx_0+>xEWe z0NT7lSbv<%CLS0s@tMr5|KOs#I=5<$0q7ho2d*d46WLJ7`%cEVl&y}2#OVa7XO|M% zVhOKavoR#jj3wHSRI>K|rkDT`Je=G-NxcQ-1#U&U0tJ^*p6g9n*Ka(aQlZKjivfTM zm{Vj1+4+c27?)`vEj4ZwXk94vZ;R=9q(n2ne^|0+5zHD7HcF-{#sKC3vp`GKpYzqw zg0K&BisL&!m9_p6m}BNANN_~Rro8<18lD$i<^Dbofh3%f{^#Yy`jQxcY3)U+F+RkpV1Vn!b zJHvU(ss}AH1@X4iwRwNce-3=qqjF1(|VZzHc zOe?OG#0AU?(lX#=NJ1g}64FX7Ro0C|mAD;KkJpQ_hVv>ao*zvJ2de+=eGY(VHCk=V z2ZGLPN`LT+0Ioq@3c*;?enwoYHH%0i!2Wfu0R;9yB)-+ct}KjCjsUcLG5Ag`Q|l|$ z;GUiQnUEagE0e178p(~JlU=*MhBOL58+sv;l-ekncu;s{^M5yAn48^P?D#923(1uC zR=g@NP|y6i9;(Q0RPX_a(-U&V?tf0+)Kp3%4jrQAP-^|15=fi@{6uTkpAc7tof>ujtTZ6l`p-?G_E$)zG*y@a&k$#~a8te$f-`$_vsh`0Np1d4?#w}gz))%cMBnE9TA(&c#rp{;*)K-cxcJjhCnfg#IwZtT{+NdlqxVvmbNE#o3g(cp`1z zPl@nbiB)?R;%{5{`fL~O(;*N@X}`>A!?GWj#8~C^%*TtKn72wx&Y6dF@4g;T2n;0y zAR_!kZRA%;=Gv9!DHCG8R4nE71fB6?z9Po){Ev16Zz5q~SI!Bsl6j60Di{L&cdZ2o zSYosXw~V3$a91Xbl7uv<@h73ulHOqqO0o|?*ddm@)@%F>Aw>m%Q!y&{ir#DyPDc_Q zbwUy$(iRgbAnw4foz45+!8K$E)Tz$M_mXEJ9ps1ROEejsSnD4EnVw-I*;BYbkJ=o0eUV0;Es)e_dZR@?D7DDu6 z{s9X};Ea-|oR>oo`QOJyq(BI01zc+n0%%Uc>U-y=zeg|uZo!I^Qt8G%w~{Jpk-pVhnpd? zINgD)iQbUL-8#da7!x5DQ3jzSiFdNmA2xqV39l%g|B=ETNr$|mB0kIyudI;xw{z=2 zA|<9Dd%slwvQHCc34?=&Kl600a}aFP6M|y;!P#PHu!N=5O0h!`~4Gpyri}2`{-MWFS$}WMw4rDxF$g(GMYt1|J zgT?QkOQloms!2m0e70{d+Y=LXGH6=>06+jqL_t)rvUXB~rdy`w1Lh>1v+r$Px$$>x z<^SK`VMiE%Qqf#Xrp-@eot&0;`8#@Ul@`$)V-9UUh@{f6$omDo`R$cBFYfR zYjVQ7y;87t^z$=vn$x|IsJ|xD07!mJ+MY&|wCztsAC*5&et%Lff(;S;4S9%PTi%j` zALWp%mN9?{(Z{A+2oGNIL_aTc1vL*K{;#MCB24IvoYDyI!_kkdl#cK>4c?Ydgh7Sb zvO<7fzkV`nO#vha;uwtNKvaJ9-cNY7b(vv*CUfjZs!qGrGBA#C!JwLepPzC^7=SA` zY$c-4NY|JhN&GAAv7?muetwMZa|a**QpL*}35!Z;q_gEc2*I`PKmd57xD-v6jaw3z z)alZmn~{P-`$X)LD@CdGb#K<71)|ESVVpgc^*FGbC#2pP&tiTsvZZ4xkZjWA6AoeL zx}v zBpdejNvkS~nd0`<-11SA0#WgAYQ)T%k~iu5RplldjD^R`AC)u*glSO5JxKel(OB6j zmI>2SN10Ys->eG>f2_}d@W?YY1sZj@?{`oTec*hEPXNw`^d$jX1u6qZ&t}fkdEt)b znv%{(qNmE?hC=&xG!~oCXV2e&bJ}U#1A=eW{d#5ISq%m|za{$Ghx#fQOE{o*Zse|M z8v+n~Gy!Oeh_v7{hh6h_7ryP$xC{FMfuUvqgk5s7aR;g*<9%)}Eq`FHn)^oqw7gFj zleNVAwRr7}_=|<3^wrC2$E9+;ypXl(;rWS#3WK0>b(psoYk-3woG6(C&nrp*`}vMi zvYpa85Kn(iRrB!3ChOlldHO@hTWt{gdrHcKkH=l<(wCNH77$YZug;BH{{t%MQ93tZ z{wP8uTfVNjv4Us6O7}i4=?Kak6KaUspFZ1F45Xhe(v z66lzi0JflYplo%*?)$)|&V>(B-&e7T0r0TT$kQ5?A2z@s?thSG(8MI8dI}7H z#)ia;1Wd!>Eh*JE48TKq*NZ2xtzDiBEj?j*w3tV}fS~f*+3AWUu=Fo_Zto+dfXy?2 zXn#I^oIfc-cw zEfks|(k%1Y?mw2Nbsn_;6LKSH83M!20JIE_;kp2IUPjU&&Q&?ZRHJ$&OwBs}@uO>f zg8<-{1Ge?UAmuIZk%&v>lmSFgd?2}e7T3skQQN=|c12j15RVC_np4Q}avZW00#{#8{_X?n^nDVcwfN}iekJ1ypG7h*D1QE@T`{`Siq%K(!5VeVnlItGSF z3rE5`lKL?@;ONI^u7w9^r9u2h#91KOe`Pvlz9LV5G#vBF;ZN@QwCob3oemg; z7GnfYIW^V=n>inmn6*@vQEO+ttRSyHVKE}q{h3{98iHHd`$^Ft>Ax!CZ$GyEhw(8N z#*0%K38r8GChRMYfPt;Q?HjlYy9NQ)%{ppo@zC6qr4_7LhZRQF|o;B*LFjt>Li`%*~yum9-M_ZBL(*q!pV+)}d<0eJq;rM*SfIM2(O z>#{an*EiZB>($cN;Cfr>Pik0RLC~&67Xnt2mKh)>&(#xSafJ*f6@M?4>`u(u<_q#3 zq(G2pc_5{?AgW{kCy9@02|a06<^SYUlW(+#*hUZzV)oH25KekRMSRFGHzzf+jWdUV z(MdQzx)yB+utI2W#-trYbClEC!GK}~DD7#5qCJCSFgkLI`DRILbw^IKcT4fgk&^%c zwd2D87_+EcO&3pL!Q>|I}PJ8_jH;DYH9kyzKj)od2`{#GuXwXt0^9`*#ku z|Ci@d=B(navCSf#?Zf~58<@NEGY|;ZWJK$;ptV8`e>xvGmrti{mcKtP%S&74fm^Eu zdFt;zi4tgm{@ZIF@06a={&0P(re25z2U6lm*)Pt@WI>k0KRX%hu@U*2z!X6DNj~N1 z|1(P+$qz7URAC%Z5p%*v|2dx);rA@V_-MP-vPmeClN|IxDLPkd|Ie${_)n`Te|2>y zvD}F%b({gvUMl#$2X~^U-&X;LUZzN_2NEwW%sQ`8jZwU(R8w*6CYzrei7RO<=^oDo z?pRG<+TKgGqW`Y~sC+tVk$)bfhx?uZ|RF@BdB%{=Hs%nx3&UlNkJ7c$i7L5=#9RDGO;oBmNEk zG>3Wy0kMUklDbtDP;|_wP|n`6&X5^yGwgXX|t=~JPqZ$CX zuJB{=M>$El5rHp(aSoylXv#0A*GerZU!{Y;HVl>G~&| zdVe7HeAm1iHy2h%^<0eW49Q~AZXxnTDzx#~;)#=5VGy`$g9QP*mihx?#zrf%S`enE zjVLXxEvQ4%p6#+E^9sKy^iQ6Cm<4DDZs_2rhJV9*vu!XvV2a3z_>V~X$59N2Qi}MD z>od6}TpJDuu##wT&>s4FrMe_$#EKk6YBB>v+Y%rTt)MC&W4&V%Ba<=*Y?>RBTg^Iq z*I7l+7XMNHf8VQ(3QocQIu{JePn~7}B0q0!VoY7HXERoEd7w@5zaEx6BDuIdpNb{^ zTWzd4Ayh&?BHMU)?V&%UT)i-rvPoEQ$Z~BsAb^xTF5du(=e%-KIsc0ZbAKygmX+*h zS2_G|D{lbKf-nJ8b!&$SU=IDrrmtPNg&)8*ASz zSW^5tvPl)LQo8Cn0UF5ajJ_*8Cs(d|*h0>b5V46aGu#(g{&l92z6t z;NDTk5`%qS-sF?A(c;XbuUs2&2tbe_{ABVY2o>oYsqEfHRSbX%`N(^FbEjs?C6#p5 zT&sSYMgiR?u7`uz@bPrgd~I&TO8YO*Dyv^c`%4=vtwjHf$L*^D-&6+-AN)b3P*%54 zj++xQ1#HUXw4;0xMao4ELQ^n}9*rMsldcJe|58J~b(CR?M&zY{dq;cz+v*ohaPBDm zMd{k($N)gcGx{S&z#p&F4%cD&RWI%(d?lK&CV(id+Y4g>Arp3mx}U6TDG`38H0SyM z0;mS}3$1a0nu9dLd?H>Oa}R}kU=CPwPbvUq_if7#VEfk}2myO3E2aaD5+S74&aaKO zm$zte;pj$Q7Xo2v=7iRq^_L>R?gelR$TQ+{5CasEwo(+XF?D_r!UHaKpEZI>ez%c-=E=WYr2VtL5 zsnwa$q{6f0tR;J`RsV-ib417OhSeSfo-zP9d@ARDIc8p(O`C~a%{#8iTxUTW9Qv2%c{B?6;XHpiQ_r)0erFPGEgO03KE+utjstIyovT_?3i|H{_`GpZ~ONet*AU?r)UM zrku7Q;_bAWE-b510O5z@>6E;{#lb854?^JD@qqwHkF1X=IeoCtCWT{gFs8&b)gvR{ zY$^@!Yj)&VF@5eY~ytp6~gbJ#(w(dmsPq(H{?VR6pu? zx<=SOx&BFM+w5E~7OTJ0R=KYQh$7RN5|{XO$xp8ekSC4eJhLW|lBMgSP~Bx-B}#RT zNjmD{alPPb5jCkA++H91B22Lso6j=fX2Db=z@5klf_T#mJjc40U#h$OsfLn^8 zgn)L`aiQ_FnmvOp?vDp5Pk%0zN}ZL<<#^oq)55EJ9-qzj)t~cF(Tx(Htpf=SM!dD6c06ADmel?UagB@Ym_casa{POFHlrBrn4JGql9eY@ zZ7@bZ2oR3;7|8)}cfD#owb!HpC{@M6g77+km^VfIf3vh{Gyk0$1rAAD>?bc(Fg_-( z9S;Z~RLoDrUni{E{0vK^`XcMw1w0{~Q{DiS_Br+4S5tTssGla#C{p44D>p4u$uacYIKZ`KOF zS=Uik1|X#WPBrYjD?4RLc{QaRu31fk?R&5ukxqf**!F|Ue^jBMpvJshqpAA1tMt>N z|3ls4)kNMTd?o)O7fkOsUTIybg7r$1($-NE)1lWrBV@WG# z?Q>xXR@8N_9S;bE>Q@{9cNMa-D*{bsz-AiTBs?0OPmf?DObn!i<+a)SH0s;^K6nry z6x1f4Qivd$fdOjiy@;=~GD~CL9jL)~3(igh&@ISzv0rR*c@^y@>)R>i>Ry=Ki`9lJ zaBb)z0P)`v!6)4BPpa1T`JG*}qtB@98?}Q7|6y!H_wQn@2J?Pzrc@gfLSA zd#D-U_FN;F55w<)Uy&!g6F1*HowZRXS0C(}hnpmx9)#vEs=B7C)0S5<*~CXG?(-2o zYJ)KHZjRA00NsRcm- zb(IF<0AK=eG+dV-lH3byT)2w}XaUeea%#xvrR8Hp3Fu^^W^$_oq(Jt)yzKa|Yu~TS zr}bB+kcf12SFg5B_ZfgJS;`Z)Bq#h*n@G+SwMFGN9taQnUM)ha_dyLek&UZr7xDfI z%aKaJNn@=-ad6Mq17)55wq^g{-mCssmym0!Fo$IK<25JS5eNM|*i!MJ27UuD0hk$R zTLn*{fi>$HPR$7zPuGqQ1VR&lV$&_|85bUcK`e+H9e{`c{1`A?oKL6Y-+piL&6Njb z^J|5yKgq6#=l@*VTU2T7ym0De+5d-{QRq4YAT`UjY%V{~X0v~E{J0PVYy`POZ|FxBS^}^_Z){cYDG*a zsSkVS{8Um$%G&ck`C`qM5I*cWzK4aszge=(L#389w;pE{8DPw;YNDOM5yiD*0|81v z&&do#=;x_yZSI{)j%%>x`s!a!16aL1>0=q;GNp&`1T#J#9+Z2ATtV zf%`L55MUpHbJ%kT9x#-}fxf?+7dpmMx^W1TT6oz5qe6Ch@8YaiZNE}DwyRaH47U=Ew&N{<)VnwYJ3O_r6P z#7*)}VRv`^%8gIAo4Dvmr#J@SNZ{+u#XN8jdDLwb<3RG~{eZ>c_6Ar(dKVH@p#j*H z+Mc5z$sapxy~e%?oI_FDN^>Nl4dEuOE8g7H4;a<^vZ`O;+=n$Et$w{;LGC-M3-9R_ zGX!HIHL#4O!>%pW1YHXuz}`Zu#C`%N;S8E8lN?A{Y+wKeqWRbZ#`p39*b(zt55O~K zfgVn!=-0fZ|8VX9yxpsNItHLukZ$)rJZWmE+;G4FiH}MBFK5c&2lsdAApr3w`OdDK z|JJ1eAU}U-ldn5@_KbB9r9c#ET!YfC`pPyW_q?k7fv(pJ75PT#O^Cb0*WlDAe^C&S zArN&hjL4=udSpdV|ACLelM~&Wp@#rM33~})g!};PjSW?ODT^@;?B`JjfhQiu|9U2s zoC-%OjzIQ*Ux}}e2Yz)7K)CV|ePtVR=ovGoWW#-RE@ipyF{R@?9$Pe`3)7=vLHt!x z+j>~vT`QS?S}KU>Qu(j32Ob1|ZY*VMxz9^odwMJg9YuW`m)M@w2KwfF)`k+Iy8Uv! zWIg_w+9CAcR5YH=a@iDXo>|&Rm}?IzGAjhy1s93ZqfHTk+aP~Xd<>zas;Ge1=10Ut z*32K5cg^*O)d5Kp?9WP)`q1Z$n~BlxtmhL~0fr zV&UjmouvjisQRtPt)#dSNpU3qamcm~(1z$I2r(+vva;`>a^EVEk~b*VTW^}|8w7fr zC~D7agcGTa8rjnxA;IOOQQ{-}3S?drVYiV5hjfmV2e!oeKpg@Y5i|g@1Xu}>`#R3_ z5a12j*Q_;r2U7rLf|cLJWTg@yQ>nMdpR!+~+aUHnmHwVKJ7BwupME#Q?|RArY;0FH zCdLvU37`F=KzvSn<88s#B?YRp!7?KHbE8RXXQSxPgetMYd1H5VZTKNjQl{01TS3Sl zsd&lA2P04~dCwkww}|-6M8Xz}!ugK~66+JN2R6>jYA<2^M^kWNx@rmf-SwgkF{}q& zJ;QQFte6{*b`^<`R7FbJ0Mt)Pbinzh)Pvmc{bq9mjLIKCTFLtxiZDqfq_L!KgiKYD zW&nn7En1yXPZ@xZZ+^N?4ra5Ph?9v)oZ@#hV8;N|SvBlyr}Jr>^$#RHAzND@#nrjU z{WLTXAP@ijO-b6S_P4yHvcCnX->r?c{uGg6U=mL&QsnGp()s`-A@(76px-%XMBhpH zSC0Rrd1*$fIr$ho-mNsj0Qh16$}%5RBt$7Bv79w=I#U1Gh4xvBdwR1jdbF-ayR z(FOZ0s8bOu@ymg`XQ<|Xw8`+4dE0spd7QQ|lOL_W)~@a~1JK&&j_KJvHaKv3dZE#2?6nW}{Kr{-<-=JJK4}%NN03 z8_#&!XMq}bER(RN0GN#u6@U&wN!CG8_ah_W&DFA5l@r)}K5qRERC&#@0mHvd?F`W> zv4<$HGb2sX#aZoJ?S-v-6{{6ECSYiHniMDcSZu&e;r3fQyJo%Jj@r4-F#zpAt=rd# z$n#Jk{S&i&N_JdqxFB>MG}ne70-@vImQ?aLS4v9MBip|yGU0%Y+J3VUS^vhx0MHKG zIxv-aF#tBbbW(xPdcU%xJOScD#D5&v!cj0BN)g|9T(V}WY%;A9)j@VRw^I)U-B5l> zL9&E6#Ti8eD7xMztGd3jYaYvI#kIN+*iiDVkBY_WFUkDZi{wB1N8=cP{m_WWdk`lc z+emUF(y8KPgQqR3S=WXi0uWVfr`Y-nI(S9Z4pUH%{@d-LKS@z^Qbms`-+xp7BDzNS z+a%@1&0b^AaV=i{+luoKiT(4C55LDDaYtGJd=AJBfGL2nU{*Mc>3F^`_j&LkfY1V- zBBG?YXSM{7$rT{jyMsT)F3iC5^>6FSjlb)uO3R@Hwt(T@3f*ThVXMc>y5R2JpLef9lfM%La zEF}UC(|Jbw4i$coBDgF+gpkx9+!G;+kGJKVSdN*;lK$6rl_FOCOzbfr2VdpB9X1HC z(}+;QR0-RN`AOTtY%6iqmUR{#wiyrpd>jK1!8JrBJEI~SU!Bb;JPWVdAd8zbszz|J zx-cZv{Oj`izq=kp0PHB7s)QJ&b|@*hk|$O4*{Qfe{ZID4W}3ZrPkN(N@RY($ zzg#aX(a)|?Bx2o$#Q$isY_>%7ABh2Yyq%N=LdAkKj$~kcsC&KpaX26V^9kbz(@Cu^%rTc2wAQ0d% znJcw##-xeLrCc@bL4x`%B*#fKt(1lfTeU zv?0zZX!Lze^Ky5m8vWiu*kh?=;P@vs?D=WRw#IGvU-U=sMtD>RU`yYULmeT1e|lUn zpWoS$H@-^#*30^{cT;lyzcQDR+BIQjl`?uo2yQ++U%9Cyu#?#6^ zSToCt`Da}98c_pFiUuGg5c9*h7?EUL<^&M~_O@%o4*^!01Ht8MvniDemNX;n)$&GJ za-PgsVgXThPLO!J}^sz?B=n!0F+$A1r?Vp6re5jx`Ltw2`<#+#{0a zDEh-I(w%F=4*?KkSx(br|J#!EPkG*5GyqLZ9m#z%OV&Tx{$+zrK>XVvx`7%uK;vX~ zBl3iCJ?5(h4HYjM3lbJl$s7kpzVqc=XrJ#U`e<+q_w#^2Kxj<9070o}OhJ5RJ2s=u z8jvX-ZJ45YD!=vFUtjy1TSx2YXjk`*0XW*Qhx2M2u~6e?MfhO^xX|O-3);Mf(wi(`w?>zZCf1fVWuQ|g8S1`2sj3yr{J!Cvr&0X|Jmt`<(wBL zg8ctB`(ORb+^+);fsmkXsIbm&zbx3QYImhFB@~d~!ru>?W>yX(9OQ|3X^OPJ%EK;% zi!VUCjhJrQxHJlv7c%ndugU~aQaWN3xIqhF_dePeGzGg7{fkOpSXFJ|J8N?5(d&sZ zqk0xWUW@(byZ6Hj0T@%XN0@%jPiJJtirF&O*BF~lOYBO^TK!jEVP8siO zoAgJX|2WdLqsEQUl-y8SfIwN&@?#O(RUOv(Pm=UOgm! zdt$h!G$yT*+(Ae9R@70#H?9)3-GBXd^`0tC=XQS+5B=1GMF z!dNUW(5}i4DglA^=V~sV4yPre*`aQwEGXUo5?6SGE{XwPXsfLvQx(tRN3Mlja228K+58)?$ zCU*Zbikm$*8KiE-<_dG*+HgYv&v~2dM-nq0^fw^!t!xSYlr#y%h?CQz z$hFd!kHgbOzbl$ zMT(a8HFsgx&gwe@aK&7ynycnMGgO7Z^P+jjEO~TLM8j5Z6K9+hM_`?}oS4+LO&_I> zDX4?f9FjG8_lwd7kXWbLW*w}AO>ovbg4zGj+rgmXQ^0-55}1;MVxXC-KSoW-ngL>} z3(tJe7$Ef>Gm-C5xE_}ukYS!UsEYH$7m&{|z81yR-$ug*Cj5Nw|MeIB_59xt)V?zS z`v-Fz--BQ$rCud&npZx%c03>u5PxO;lgb}QJ6<7_jT)Mvv^ENRg%B%DMp+@(ZuyJA zSmfoPTC-Y-Ak$k}c>)OWJ5)=tNAQ^sc?2G9Rjj#UB$+&tgJL7txZfiN0qvd8Cxvps zlgd*;c<81aUe~1%uQ-mduM6fFfWCqsMDCeaW-{{LRstX)^Q>~Gb_56(1=YQ?~u31u4@V1a*Gtxidq9>%9C$wr_38PL+y^gJ&TI}6u_@i7@QWvxow`8XH zXH_TkJ^U1^rl9d3)Zk+(DkV%<pT+>oAdUBX31P#IchK-6D66e;P$kl?W4 z;vCaz=C;1=9Cza*K>z|7mi*n8{U3=4&-q6A(jl5iFqBxEL93nWyNHG8vQ{76L#P5Y4R0hQ?XrIhWbm)>?)8EyAE5_?Tr&{eGb8M_O zM8@I7{w_?9?vCnQiT-T0G*agx`PDm0760S|dvC`)R5iUY9Pl6rfIN}JdByJk`b#tu2(Z>LtY|yg$SW#$oe;v?Rdzu3!!c+|dGCGv+eg=LMP;s$(g1vN{S)FMm)^bb z-OcPsVqJR#L1U(zm^Wl@(+s`tOEAC&F(sW2WZbTa!HdOzp z%_;mdB1B3KfL`T`fccl0!Gx~aXW zHy-y}?;#LkI)tAKGb!!qsaBcV@5Uw&+PG1rOFfIn*w_i$=v?bpFO`kydVQNVJn$kb)?pFSnR4lnxy*{=b zrTImc0T99y;8Z5qCJ^;=LUZBXi4y!;8VfVP(GPWhN`I1){B5zH!Jk@7a5%On3%8*P z54`_-BP#3|~~rai;Pw|hs@H)?knMpW(Zw z?yG1cq1Eza3L+22(t5$B3GUapj@x}B$pGLC_}=+9KHH8Zew|Lozb(4?9WBh@GXUD~ zr}8N?BTwiV<;NaVb~O;W@TqIZ00LCXd$^^Fe>*kVJ*75R_)`g=fI4$$Z{UGX7B$rV z=cnT~0Z>29M%e5VD&9q%02MVcSxIoexw~V-8tq&TnGpQ^wnTsC^f*~D_XUHpU@|eH zq#u1^XzGC8{nSMW2&Y@zr+`p%W+Ej`KtkCf%jUk415qcywcbD=k_-S-|Jlt?i7+nw zaPhk^3a|cm%=n3C`5Y$prhVJW3~h56<W$K z`6VRImiyJ7ZiMO}{v+BiI89MWEhWr}83_d1&xXPuEdUH`R?>S`;Q>Wq69_uTK@(%H zcE0*k(m5Mq22#4FR82fFgYhZfbIBKK4_R?C(PzHT;@906GuUgf7mz?{$UOdYU~+^AO~T0)ePmNHz2Ohr4F$f%XsD0N1((0mlGz4YWbWAafl4 zrewbzmmN1Pm98uI+hw3fsCx(alyjYfIbYK;$JF)p(QI^g()85c|R7wG5DcA|)~=1I!v!8*IWYqI(l@J@*9yAwI;1 zWM)ieu2jv8t_x50Wi-d@rVhqkT5nJvj4d`UI9$}5AoM6oa9skyvF{ceKLnqoH<$r9 znjvtw!J$@%_!Ax%{EIL+VN5hU_BP3_Fm+{c>T3eKkQ|7b@c0B2^h&y5n-Jz;z9GUu za6>yP1jsRA@ukI?GI@z1;5lG#4MxL_(Oc8ga9eX(s(Ix|+Wq&#(rEzpL!*Q5L55?g zq`ah+zEvL5U!9doR~s5Nu4}^&0h0c#DA~`tq}w}6`TM8kLO|q{0=H3vaFQnaLLRg8{>_(4bhKSxhf5~J8!H8i=+_E*PNov3 zC{sXCD2t*)y`GJ`U%w!LkIS6)dm*cQ89P<;Sf+qgrOLjyUL25Wf!?-kdmqcc<)eg& zt(1!9TEAe~?0p>r&@7}{JP*WWC4Uk89BN!SNd+lfTkOc4K9CSVvZd}lS^u_#$ToK? z_H#3nVeeozBGVoPfKahFAxt;Zb=S^8jVlelA^}vWXw)}Ez979dYNG!#jRZ_lUS^IR z!7Rh!FjFJY4c+f-7aI;LW_MKfq%rONqV~d|XifFp68(C!Sgii?KStd7FWfwlf6V0l zpUvxDM^N6Kh$gg|Ji%D-pI1+K=TBH!C>%CCYkqJRb@$4 zuC`R}*376e-55Xkq1C_uHXuDr8*T{x1^wuspa(znFA)4PeklX?Q>zDP^k^^!Ec8gN zYL`n@D%CA7m3Q9nK{8^#ZylaYCXx=++K!?Aqx6n>D{)2wgO`kbSGVU=Vxzn6(GGDL^2#b1wkB*~^+2k4U(hcA| zD>xfO+f8%L)G{7A%UNpg*!)bxj&tw({k0vX19N6 zP3<56+y`h;9Z&$%c2DUaUG&P_JH5B9Ui;&Be=xhcx%J5hU;dX~7Qj*Fs8GtiffMLI z^i^}$xX*Rom%0`M_6$^C=xuhpx;{}zE{*j^kke@)tEv9~VbZPI=8iEk1Kmim41 z|KbbYyTFB69%3NDgeOu7FC(OU(1lISKm6KoiLd9%$-Vh6D&P|0GTA8J?>*SofLasLiVJ3SmU|!rX=}8*1;Vn z@*8;9Px$-88oxO4ue#m>kl*PaujH#%|GO27DqC464!YVMkZ5ZGn9+x;1%O4~O`1&Y z-go|6r!hO=`4J7SFd#8ii^^JPO285W3Z|bb#4`OxCflv>v~Mzjc_ROx8JZ2DaGWVQa4dz`%zGs>v|d$n33^Fpwu0lzBxyg7I^KH}%|W z0RbTqE-+wX>MSS}0#XQJ^_S7fK@kf8-MdW(Zez*3EAKkF&NTMqt``6r8%B3ruAb#hTqqpc4J z=hkC^&77Q5(>qsT{DI5#+v{ZhZgZS9m;G9~FIn!dgd1RSBh~t?c(|~h3V7qFx#F() zoYi_zSUAt6!d0M53)KZ?scA3(LE5?zR0phsM;Yu-_*`Tiy#Mdt`!_p%JIRC9Pe<=Z zQM(iF)c(i!1c3bzIl|vc^OF$0X$t>L!l|xL4p1Y#KNj*y5U?W*r7b@Vh7K{DU#}*! zYcj)1a@RWe5Kc{}j~2_j>2Yj{%c^!=o94cEeajrlt$_g;M2RUCf?&k?4R#PyLpD%u zYA6-DG#l!JmI0|vA9r&Mi;VU8Y9*M&ljU+UySfzw>oB5aFSEl=5h zfm78&qXqUu2r%zlE+iM(_o8}#hn@d+edjesqxENQtqh^hCHLp^n8?{Rb0kUbOs9;p z#!uV&RmQ$8-~4E4J1jV#Jl_D1w-I33$#G#DMxP3@@_O+#bMZLOd-2zfx%M-3jQ8;w zcnp^_-s7zqi-e_?pW9?XX!S8}$P6NXCw`o#=9nXG8u(nsCHBv*4YRIvscmqqClz4d z{jEBa>#P0+6Zj0%FYf$m-g_RhtvMylyk z6P63Pkx1xnLyDvHCkP-fp36{2HKJ8Cxs?qxeKdY6;Vr}bmFDL#kE<7eH4 zfGCz|#r8H!yKZ!J#b-VINe$>Ly6eXo0Biz66M?IFDEqRgJmjyy2P zGpWVmAm>!GXKS-CbMHVeHZgavaO0=cO(+7V5FGif0hMX20Jr4t4h{chf4l6R>%ck~ zDhOKl6qcPM1<77JIt02>0Ki-_oaCqe7<~V8)Vvv%+)RkaM;~uT?%<;IP>8>b8T$7x zVV+h9Kzlha3)bc6nq1n|meiU)dbB|V{8li-*dmq-GGeY$x5G;IceR$X%>VlDy^#zK zmy(Hz@nn2*EXhkyi3*f?F3!&-4;Pk_oz0D;^6-9AU0aQ9bKk!_7z}lKxDZT;$8@a8 z{5PT4R#-)$>Jw! z$ohlDBl~+6nwcBOYGJw^C96TksX5zm+YUnq;c3}qe;_W&e1&fxX7PSZ!R-``d{)dK z&(P|ib;|0ET5&8;q%}a?ZnTBl#<``FdG@yN=NK9tN`@5xO2uRh93CDSesR04En*C| z%E@+rKMW1aM}8p5VKZLAwYAJ{cqIg)$NLuG^0E)lGv3HRctL0s zzlTx$kC#&u|HGwn@(qE0YEn{OJ{38g3SKR+xV_KTg#owE+xnTUg5_ zUp~XyN7#K*VE==MEc(lV=OF$vT>D^~qLbzg!;8Lua&pAs~Y&?G%I>9piCd zr?}`?i<~bJT>b57m5EC7$YN=Yc*l|L>RZUodS?s_(A;Ed_$_?!WG& z{_Y6?ZGgNI>eX?idkFYNn9KxaEY;-B`T~_SN+3=3y1&T6MCl6SuQZZd|(KYimenp7c?@$V0etD>FBXt%evlDP*@lFhZX z!b@L@fn|_V!M!|JyeJkeA?>!oB&M6vyv4k53 zSJk)v`FqKgH*O{u5M(c0o(>!yC=6i1dMSkl?&1azk2i1u%!0dX2m-(T^*<$_eaPPk zv`e@{N_|+lsslk|j0?yUV%C04Zg`}}cA@J;tA}&0@KdQ2!-aI0ywU}*{?ihWG5&7v z`@th>?o&~Zd31n#QTVZn=%+MT~kqNA3zRcK&C)c`V-S2`o@M6@q zDUOa^Hvs?Zj@##}{hR-7(4Tmtb>ir~s@v^jy+AO_?=;;zMwypm&H*F>-VYTH1Gapv z5Mc1=023EDwF}#$Okdoa7hMur?1mXCfxDcY!)DC>PMY)Poc1$7@z9tR1zGV}93C7R zir~KjLhgPcHt(LuyPeY2<=Y~^$z$=VAWUwquO`S$xB}=e>&meY07v-Z`Dl)lL-$dn z0)r2}SD2T+C`1MLx)&Nnx`-v9G7ip-Tizbu&dvuP|9q7$pJ>8WJy$+P6y64n6v zqbROfS85VWh`*i3RvW{NEo`k{|LX^9$zx2&rieLy2~(|R#XkeRu2J&$+cU*viXcFv z=0kw2^}|#6U91)QEl$i)55kl{<7E~xvnxE+YOW*kP3CN2tqH6NTAd{Rt*)_b-j<0k z`1ONzaCj@ZH@6i5t5zeF`PZAjy?qw%pPTu~5f0kVT)*H!NzyEG>;mS-h zGCqduYA`f^1NrthHF@#dL+gOC0$RNModUt^ljj6c?r;@C6N0ueH3k`Lc~lxW3J&k@ zOSk@=j#9=itjU&G26uMXn1X$s<<>RB0%!aB2m0PE_Vr)AJ#_u+PZz$nMAnJ5u41lO z2d|UO_2=O9O=c8zF8n7a2ArA?jlz6tS^)>JQeC}$ zJ^B6r^?Sj*FW(03WCjRh>th%Q2%m^}9^}WEFX>KG5?j+V+_oQ#fnGmkC>pl@er&k^ zzjEh=w%xsj8+DZcP~FMl;H!=?j;^nvETPtPYXrB4RlU;uZNE9YElqh#%iT&ejqbN# zi>6c=VzW&GRw6B`I6~TobfMpv70wHnET4|0{Kfgha3IRrH`*$q}_@p>^fuAKKytwO`{b*vCt#tQf zf3pi>Yv5QQ3sfOsQg@kVU8&*W^jmm}S9xkZC=6Jb$8wRA>=~azv$>)9D`Pg&%#<|h zUk0KZOXlB<=AS)T_tPMFJA~O@hCe(?)(YnTfq`O}{j=*DIS0fZiJC! zyS$ZDaA&PhDX|Y&*k|`l80g2gEDrC&xRGa^)@xJ-bSG&gGizpSkh09=m+}!iFrKh2 zy&<5+Djx|PV+h+7B$^X$T_pgVFf5vSyvR68u%CI`MsZ8bOCY9%{VWr6vhK){miSbY zhl|@p{Ffu@T_WB}Gid4xk^JKX|6RIqHMIT#BB;aX-y$G$PzmoLJHGnHbp(RGWM^?P z`R0qyl73RI2Kok>I|K0205yydO*MzA2ybAT0cuYu7So6s(%}?f780=`TohBoZW*1L z{hR8*DZN;;z2jAz-y%(O469FtKtSue*UITm;hnIb04^u+&0t#t3rz_N3sHmcPwWd?=@lS^-2N9!MnfYtHoi4bBf{?k$eQ50gu;W4seZsSf^ zo}EbMzIu?%&XX~K;Qeq(YXzmS$%>#{075}aPdZgUiXj3UvjQypt?+2T=9Aq5yMEsy z89G&PXlG}80ziw*0jQW@)oXy34%JD>qc-Tja$J=#RH$>e)trZ)e1Q5 zR>e_sfakQ@bT?i9_U&Z+!bGCkf8yeWNcjtGzQvm=0DDZZCfD3UV&Bh2F|f<)W8 zdg20rk^jT*t1B=H3sTE#8vmF(Esm!RjmgRiqVX6<&(@9pIM_+#@coB|-Km zeLSh(Dh8NMA|)Pz1`p{&BY13+xpf_$l2&B1pzDA7ogeJXttHQX_W94KbaDLc#07xl zy=OB?uJjlE`Re<*YHpn6*wtl!C192}mFZtY3Vrudx_g&?sk7Q-{wpv!eYX$Mo_=+2 zHF9y65derYj2XFX^%8^7lm zD-zE*?z8V+Ek!2D68UY`+OO5b!DU=7>lAldwM6f;BIf&C1j98_9LQ9{tXR_nBK{xF z;<`c*(6VsU76E&=ZYGmx{$o>95y^klduG2MAO-dU!GI;=07fRpLa=aytuLOgCHG~1 z1Hw*C6NK9cSKrj(!R*Czpr#-1sQ2xbApaHlc@%49SR@Q%hF(4|+& zIC0g6@82zMjd<4&e$=L>BjZ=gF$y}JFDEq6>1B+RJMCgCzuBw|Le09Xe=+&NDzn_qOD4n)?FjRoh^5f2wo~>J9Fkm~Hf~5hhBV?gi#j>3yooq9#3IVOI57EW3 zED^hqLuXWQGA>8PUp;YZ-VSIsc8?5a+<0vQVW5vf38$)vR;uiNpQ*f(-|0WGp!X9) znIGKwL2+s*nSqO3XUZ*?cq*Di+(_m$6)82}1_?jIbXrm&YIcyf3ya?1X(Zy zs9Hqu!=T$P0CLZ`x6knY{8#C7Ope1b$p~^pmTLj92eq2NvDB|eBkm9Hr!`p3SE7|= zi!}1ATKzcf-#HgDE#u^@hFB`3TSAv%boJy)zqg))bFj_axm~dGo6~z(Q`6T~Bjaym z-VVFZfuHl>Py(3fOu#wtx>i2q-rh3~xxbc1nLRMD#r_k(!rb^B1R}}|rC*$rSBxGJ z)3e3C33%25Ji#RhwG91{}^{jy(Z%y zBV}ov!{D`>ll{r{iQRhc67+N0jGwuTE5!XX-nry%i2Y%{{fc@D^)z#10e*+M_nT$o zDUxJnlrx0HxPtv4&E{>9Xz_n~xIxVda2N|#J52xC)L8^*kW7G*1+6Su-9~Dl^-9g( z7?yta%IG5k&SMAjmF0tk4nD!eMWNYG_g;$xM@t6QS=AII}avYwPmBFEqG(zzr^#% ziwoW-u@3DRqNN!%cKK^3PxStV2-Dn?-Dk<)bzPXXU?ATDrsOKx{}dav)fCRg-^U6$!JmYr<)+`o_O+kCD0SKI!0MJ0+y5fVL~6%Lr7h-<_xLTw9~8 zDPgJRro3j|d!{4~Py3snWkHt~p?Xe5%3)mZGo<70%2qFa;(eWGU04QiYF%ij_MbgS zA;Tl>c=qYh&ocH(McnmBixtV|<58R~jR50F>#z)41+#HoK4HN zD3@^&8%UHp%=am1?0J)W|Igm}0l1%Ae6m^n*ioG!r|$PT4XuhCqARX z2LM9mp9ugn6fJq@B0I!^Gb3&bDnj*Iz(;}TGG(;KsLOzdCMiAYhgoM@{lNrWuv@cV z=Kf@9n~3;wWO7(lvAD+s?scZBYUz8%E(nw7J;lh(B`HL_h@XvZ)*br098R-+0+_MHpv zsnJiJhwbD!sR7ce?r+se(gA-=b<0Ki`r$}%-Hd?8$JOti0MG!WT}m>4bGL^j;uND+ zt81sfx`A#S|0NP1i5moSg_4_E0C*e6Q9HwJQw@(B?nvMu`l-3Ty^Ge;zuwzt#MZ%k z%%ovT#-gE1U>yQ$q;)l{00srVB%k&ui~Ki=T(hgegY}wsFm2R;(F+Ixp3j5Ts2*JQ zejgSR;9_3)!aDx$An4$j!1Fi&%zh+J+LjT@v;a6AW_Ijv3JJOw2$~N;Kw+R0?WF~v zy?2lM9$*1L4v3}&U>hO2pATes;&iCQe*Y4M+uNxwx|{3NrAp1DaLX!C>ZVgLI2|ol zL>x5>4xA^5ldQPo?Dw$>07m{_D(2qBG&8Q*gVlYkgKZVCB9j4JS^+$t9^`6u#Od!8 zpk;g>@XuiU!MKlh+gE-qf!kc)NY>d4T?U*M%6{dN*8kYOxA*t(S$ms*Y0dDEcp?kL z+(xXx?u8Om)6WbZ(|_!_5fgG|+O}r776yy|XffI&SM2S|xqfdpfX&((7l^M>Xo@{1 z&~CNj)M~~7SPvdAd{}5U+2cVN8+YM+6Z^;K>A5Ygs{=Z-gPUn%bv@ZwS&I_D_PJg9 zw`-!jz8S|3maM7^(S^AS7g1WC??>(`tPmto_lk4C|6k08V>JfAbY5Mw#+L{SEk%v2 z*B3WBXK#*G0GLYFqv%hL;6Elz$)~G}{$#iy;eKa&kO=NVqyU!4T{;gwHnpY4OBI-& z)ze-^{!3ii)zr@Co;^=W_lJ^E>Yh(roQ@K{?YO_p+j}q1FUHwt?QIfIYr$9Xo0`ur zb1#FHQ%C@6q%w>R#w|1Y=t;V5tiFFYKC0K$L~c{0#G*g9F-=|^F$)1Ub!s$|dLwMl z_XNhFH&!7sw27FYsPF5CX?408|S@ zdBRjI_j@aq?7Le=Rg=)aRDfz5^k>lt7grjod>}l})Q7S;&1oKzoK7qwckJ6(+f3G$ z*C3vQLCn*V=SO!y5eBHX zueD0fm(mx_|Easi^I`XhhacfZ3&8r?T2fpsCS_t-)Y|*nfWvl4=DxAM&i$!4i7*hz zw|5}C_s`T-m*Q(4_?-s&dIXTa_ES+vq1!d#@o-u$ESmA=BpaRdXlM@;Po;B}x65^Rh9m}lzFaT2H~7n@P}4m`7)Zs}rD1Jjh| z`%W~8<;v1hvM@WBEVE+r@%(|Ip%fP+IHi3WM(|h}jL+{Dh)DB~;j5lNO zD*7u{TPy2BR)b8B!}{_9EqLSBx8}HO{#R&x@!erR?tLB^6DaP)N^W4q)F$Y$p9BI zpDl4TVD)YZB%7E|KmG3?CtrQ`MRN1b8*F|0Rs`!=7|5d)r@1MA>&vSVSMZzv_K(TE z&%a7GSBL}PSqC*41@(QBS1p+JlR#3CGVmKcFWq`L@^YqT>>T(<;+{?$MHDj8xkAoCcfFJGi~{}8qN$JxLK ziKd070K0==G5d5j`S09&{@GkId-pNf25|QSnnLU1dNp}YHNbITacT5`i_Z8*7G$zb zk_qtL%cUs!{or{y+~414nI0dD0ATRn zNM&nK^9Izj<5JC0L6z}$Xn1IGS^f#!)LL{{1sR?SP#qi z|2;N0UJqo=Fh&^Y3USG(ege7R z#s##fdIZ$#)|OTx5_|T^^W?Yx_;GUoi@V9^|NS?~^0S3xhaB)7?V|@QBmMPL!v*HM zU@?xU@gNa-iq`+Dd+gOoPVpQj0*Py_=5H==kE`PY$z_grFBc;9X!OXfP=-sBF~^= zCRTycNC`nUo%nu>9MmBk3d05znz8cu{=?+%r(Yy@fBQx9#jih2R&X(FE)xfUOW+_J z7RRoP7ZI8)uboRSk#>5jHpi(yxlLUm-dG{<`6~1SWkPGNH6iLO;ijI^$%|bE{r!Dc zin;zvZ;#&o>NoRW9&ElmVkbIo0hmhWib;Or530Goe+T)TM8fI%$p6fYYg*C`ij)>8|HYQP~)!XT5;+Of_b1#Hen|9>-2fFfUP zHo$=t8pkj{UY!_Ze}TT(1Hk>t9b2z827w^l@Jxm8n*`I#>^_FMB@x_r_&uE3B?!E8 zP};~*u9?!Xn8P=W1%V-FdjcGOht|Id%M${on)kDB9w$}Qs<8_bxB_O ziG){oHuom2Y9*h5?tW$VT&MckaRH!H9q-hAl^!*vNqnx27m^Wdw}TLJm5_7STqJNr zkKZh+;b z<>dL@M-c}QsZ-g-hnyt@5d&cGV6H-W;0orq9A#!HCyH6tT8y6I%=x3g|7CK2`io@h(hSFR#I%e~j^WZ`q;J=+7DX{Bbx_g_N+zZKZ-}PtuPZo&jRjij|5dielFQfIS0WLj!o_viM zKYC$2x$*dI{Ha69IKsgA;6Cf4vlFk;s&fI9~$4Tb)nuo z$>g`t;-m?4FdF|hr7X;;d{~QCsBH}4V>IQ@y8pV3tN~y#pPXE(!&mzl$@=2-hz&G+-QU&zdHH*KzMBrDL2Rbp9+Y~y?B z*0to~t*c3CXeizfjgT#{+YDG;(NabIfW_yyz<&Kt5fr<&MDG96M$`dtBcNVu9s=qK zGZY7!VqUf@X(?{AMXKOJW-V&|u4n5P9V1cZFb==BI)e#r27|@~#Ml+wy^Y@4K{b8N zju!nf`d=hEm(1Up5+EM7?4179k=M}BWZc}HP^V~p?18?rKombw(L~0EjXvAr*9(@& zk2XTuQmm^80qdMwX_|@4aEoo8p$5tS7pDJuj3cxQcZlTBZ8U&Hpdi_YA+Oh3gMe#J zL9l=jFh+48h0tZJ0M=I!tO40Wz{^xdFdzltUbL{{9CH1Oi;nmvZf{5Z56|An;eJ8@ zH4CK_ru;Icf``Idl|3rHU%dBZ=}~DMvL_0uBAW$W|M&0x@72CSe(A41{5xX-+Sc`s2>@HSpW*x( z{5M$PzDU2{ogh=dlJ9FyE~Z z%|ADU3t-QjgbM(l=@t?G5h2||KNUREC~?xr80sPx08Rg!1fDhGH!h-`Ud3HB27#Hx zY+WGuNI|mKT8BUeJ}m*)$m_S3f(3q_EV*T~X?>}+=Ab876|WpwB`?2~FSm_qzPxSC zcLuT=&!QjSAOvdyEYB{5Dbr-5x3GrhlQ7xD8Lox41U>j&gT<9~$5HAYET&rqS9EQ5c>|TNFoqwJ*!l!5=of!@`wxHd^RIut(XMWHOaK@g z?jNJ`KZKzED^{M&ziR~mwOe_dnw)va7e|f$PXqr>koUD~j$6Nva6y9eI1UTIK^-k` zl#|)}Pg2c>`Pu9L_j;K@8VIPXqBT>gO4d3lkMl$dbGu}Ybg@l{x9>gbHJOwJeEXiQH4s0XwLzqdHh?a6@%#(Yj%=9ffr?GUHoZh?o*jh`Fz#U(G=Vb{L6pv`aM zd65%iTv;G=6W=b)}j$ZXmLeE=`@0yZ}u(L?jA{dd*{+IBO=Ub?Y(uw zcaypAR64y>Q=gzw|I%Db$JX-^iWXXj)VeJ7Yo>@UBk|}QqfEo|+USMC*o=T3Tr&y- z2IuMqSb>lqW&_BWeKY*C(f%}ZozI7O(|AD;NLy!cIq(ssENzWcOuf7)G)Bws{a ziPK=PuIp66-{M~BlXi&Gl-x!{i{g2DDjF!}n*kx%|}(3i@5%6XNLBI?E z-$#7H*#%X@;Az)|uFWW=%-J{q*JuG1R|{RQy@Y_!P-oEv;JF8#m$31jN}e>{?V_`_ zs^EX#1*LPX=4OjVpP9s5Q?BMlaHZFPfQv(75(K3OlUHy;aL9xtDry%!oOuO2ZT~}f z8>18J6u7%)#Y^FSu2IwRbEvRr{?}cnY_vB}w(XN~if<^cxNfzQ7`qd&;xj+*=7zA6 zQ>h*p7`XYT-}%9HOYFC!zwNaEw4+DIcn^JLQ$quR4A*f1yfrfrNTIK>*HX>PS_p1Z ztrpg6FCieYy-L3SzqmOVRsXCt-m@CLgipKQ=~jsh3ne0al6j*L{=u z{oDQAZoi*Gk!7-rWG_wPf^xm4DX87v^W*PdpO&NkYI1F|5HMO`m(MTfNV%jgK-ONq z%RcFnGr9(w8~sT>U-@2NCHKu_ar-Cq?8Bq>?tBXXK+hB|cWg7bNb|pefO*VBy_QC@ zyQ7_ll5(%Tgn$f5En;T0KP*S*u~hU+XmtLa=!d5z$x&;eLJEL;ENHRY+&SNf8QMP} zaD8gM3~Lltfb$KN!|^d&w-+ebr2?q1Bn-P=fJ`%sZ!xl4q`BVB@AS7NxV|j{z>nVi zqw(Ql;oa?|asfcv$y1>(spFRZ z%&+;91*W#xZh7mJ2$I!FsssL*sDMQ#`md7rp8ZYoakA3NoU}y%&>T_8SHDjOZUy3< z5@Fo6GKD5Fi4`CsL>T}yrq^~MAX8IP)=d%tR{}>u>m;9&Io=&g+fJGcC%~66wEqz^ zMu3kkeQn!gdN(=%0$Knh;Krl4W`(`$_B^lI0W1It0hYNf@V*y^ascA&`$$@*6=1v4 zhk}C+&FWnw9zfhW9W7TR#r}P1Fy#2>X5Y2i@0JCCsP+HO@(sXtOLGJqp)FB~tq!Eo z-vt3N7z9E-j49W0zwSKd-=_!z8XfM@t^-(VTrL)g%tVPA+L&Dpo;d|oG>|Q%P!LFAFZ06{LoJ4WOt>2a1QHK;E?Qt7FUCSl0)ug^BCgY3 zYa9ZSd;=$4#d8&2|5e~dxyKL9@^l9|(>2g%ST zAQ+kEpVe>=A9rv4yn-gu6AL1ZAlls`a#oFNfgSQztySJk&ipHPJ)M6TA0j+P5gOmR zSPTtxjDWNr${hcEs=*n=C6T_N33s!aEK?cq{v5mTodfrjIF}ul*tg{OrqVhTlt}2c zCLmzYqh*%rR}>##Wa?z2KlkX-5CB})Y07s>-v+S+?~q}# zagM;)vH;K!guCgY-AT2McoE`l%Ae8yJ*!#$Nphh?)H`;bjV-F(DMj(wi)~r!-{MqX zA&v|gV1=+~pcVgv+4OMd_;29O%5b@|HO?Bt3wk=5{dD0Bgvm@z&O$C} zklX1P!O8Vfjf34ZBf?mdnWnNLxz`q9Im-fo+N90;2i6Za@?Y0cnvRx!*Lyu#2|P*;+TyA?=k<@@X$5xp(V+{UPGJY6UKxo zL&jFkt=;-qekBj)LF0dV=LgmD=Oe4l)&po-04Th>dL8T2pX96kmw=C{f2X2Z;qTH& zAr{WX(KLVCNzaJwa89R*#sVTjkL&(Mc|Y6b1>!Qw^;1*d5&wfY)skTDJhArCk?(W^s0>a)-xQ>*FR_LcxrG~GnT)3{Hzs|*M1~f$>Phw8)xS+X zN$xf>=IolL1pvGwSE{+f50RU0Jw-8>guza!6gc2==;Aw@s?42xd;Ff`Ch9H z0YQ`%7%>Iz&8dN8iKy!hDrcQ#0l;8K3n1zD*Ytm7Ol>O-2CNOS-nYjE0fRG9f{EDS;gMw{Y5dtJSkwpPR)NB^Hv(4SI>#ugqmJ9XJS|r{$?jF7E zo~d&#L`^j}*Z1aNLZ(V3+&0-fb-4yt6PVff#5?1aM$uG9I1I{FYt>wxjkD&BdSBLr z0ANf=YYP`K3Uvqsl}H5?yC87g+NwGB1gPqcugaU7?Pk*gK(h}x$?H?X;2!PzaPyJN zZWTAHh-D1zB>Q(7pRFb30y~aLd~OgpGrvwP_Hre8bjD1s&W)*$Z(hV*gm2Kj=(9*` z@v7Il3jzxG7e`VdU(3x{0n$cIfc47hE?T88dKed!k^VQ?vD6aCqu`>&f5gWg9cvFB z8e0*DBa)H7bx#aoER`P7+Y?)kzObMKMi@hS!l+k{)ElEVLbt43H1I&!{ zB~zHADis7aOjX<4Nm8alAYR;V>~ceWa$F<3!Kb%yy?uwmHCauLh(+mj6Qm|UkbFJPT*0f1T8wBrHaiUKwv5b&P=z19K*gj+<&a@GtvjwZ6TZM8rw zEqt~O0aiHB?0S-9H=EyP`;d)K`7q75unJz}A=*clMPvFz@Ejo#>#UU%jN043;*Fl;iZn`o@){}BV=Lf^aCPw5;Ud$)yI zm|0=|HzwQ~x0)<&lpWhtLOryR>RlYv$Y;O zo;CA8=h?MhB^pXbd1De&`QT2nKv`Ee3v9GyxRc>cc5d|d?YItIl+AqzRL1q>E`Q&i zw$?!(L8yg@1CXBiuh)(afh{dY5UJHN7EQ88)^KNjIa`jp5^fMwIpgI3&a?pF5*Z*Z zNM9L=5+U8KZ?WYs+Fa@AxO1-WAU`w(X$(!vGqP3GW6wQJSUlUYsDk;QkOYvC$7cKB zxJDqlLsYn!B=TRgauf^E0?=z+4FRLLZKE*HH>T4}mETbuXdXh|OcQt1!j)c60(~8Z z8ysCCtHwGObY-GQ0t$^2Bw`wQrF!2QK8Q4MJ4GW)CLz+9R8r!8is((GL4)iI(gRx z;P#qoEt=BSF`+3KP%sdIV0Z6;hVS0oh0;S!rqL(oHmD@?&H``70<4QjbE{>dEwmD; zLEKdTV6SyK1a_xLca3fvO}bGg7n8YKUZa^RK?}H-As+>}aWD#0LGPi-IL>VVh28aV z3tyk9t5P4dk^Q>XCKRwS|2r1PVG3%L;cmmT&+{#UCoqZPhYUYv|S$!%>mJFjP20C2Ic5(%UNu)esREPc8ix&PDT&(2Up!?dCA zUMsP{(i9uhYB2syktyw>Lx|z&Un$=<&E;I#!PBn?+ zB}$?ixMyzoFan7}$M2p|9@bpm2AhQTo#`S)WeOqG6c7-5d#pDIye_%Sl+9}tZQ9t* zMTysbY6Gle+I_N8j`)jM1nD6UHlFlXf7PpdROaOT{*O1_K zvU&fs%yYU)iuE280GbWl2Q5PL*NP$W?FodPoVCu}+c}IXpWNOGpqVwGQ5^I-59z`f z?gRyZxxx-iA+-VoP8?AH$QFe6DxiQAITTu_*>A#>WixH2(Eja%)~x7zymSU;XZ@~G z(ieK*T*}-x$PigW(|^32*8N{cVOitg>%{#3m|k9vI?cxb*Th^@x}QaIFl6;!%Y zssL-Sp9MDH0@8$;Ps*wNKdEk$mc>N4UAu+==VY7t@Ep_Qi=U^bS6;n;9J_CvlYVTW zac0_lwx&}}rZWC?&J6B3=x(pvI{xssYJ9p7vh7v13c3G5=S7#-`_ud6Xb{j{<6IgP zC^H=!OtVs4+s<`8tnmA|hKsEhs=shtW{hQE6CognfU9Dme^`bQ*MroeTi~{z@IUY{ zo(UH1{>?2|8R>Ugs$}p};H{P`g-%^*mYcTtl(@(MkU($0B`Nbi8c5FVubn67MfcA- zn!Z7Qn)>HgQ*-|+3W~=jJU~}KgCwJC;0cat_Fw!zKmXZME1f#i0>D84ktxhmDs&a~ zU$gP-!e;o_u2IzH`s83}vbQGEv^E!?i?G)kgMb7t-8R?MrD~L0UT1O5;a{7@4d4QM ziWO#q#imL2>C$$5wuYNV;ed4-Ej#;%_k^VfAsocH>wFlYKTUw1+Fk6ixd=efL424~edTF#0yGsmqws zA1-Vq_vfLO;9%BXzRN!0%!gYP50YW;RH?ns@-M-V-<~cZ+@@(_?mURHNF5AoVWehb zBghp9WF(fz_TGKa7iow=$l==;&jLqb{NStcG710+u72+^3QkAt0q?n_*II-?W!K#Q zY}JzGFn#9i)2AEZ#z|cO&LO;D9onPtmP&3dKJE1W?A!?eN_dtE#my6v^(u_Xh1Z8@ zK8Tr53H&mCY*X7}^}3RK3$bAgS6)&hF9I|InK8L3OjSs0$_L|@GDR^qz$&>av z2K4N?)oa}iUcie)-hj{Y7qdrUs$VRS)_>3x- zn>$nyrQU@&q6IM&25!4U<#kwV~KZKmc*^F0PL;ZM)jn?(L-C(A^-W z5?(hWlCZitZRQzaK1aq780Fu-D70Uw^lPY3etR)?+V- zo0Amb0XHmwWt{=X=?*NxOgvW>rkFj1~&2EPE$Iso_Pdc;L-Ppq8&eTtu763l@^1mzsfnWUS z%|9A14fX#|r&*K=g2{`>qm=03f}CGV(||6*6mCr6D`Mf#jHUrTGBkh3WxduQ1k|WA zt$KLRZ*&i]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 z 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

PdrZ+BVhNC(a_Ny9Cn-=uc=BN0@`DdN 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

?wO?Hr> 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

ezG)WNrBMw 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 M-JO|pAI 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 U>KUiV+&Kf5X94m%`zQVJFD104SpWb4 literal 0 HcmV?d00001 diff --git a/assets/windows/tiger.ico b/assets/windows/tiger.ico new file mode 100644 index 0000000000000000000000000000000000000000..a1b190cafe6b05cc0dbbafd9eb45ca1328e54016 GIT binary patch literal 17598 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 kmA=D+ telegraf config check --config mysettings.conf + `, + Flags: configHandlingFlags, + Action: func(cCtx *cli.Context) error { + // Setup logging + logConfig := &logger.Config{Debug: cCtx.Bool("debug")} + if err := logger.SetupLogging(logConfig); err != nil { + return err + } + + // Collect the given configuration files + configFiles := cCtx.StringSlice("config") + configDir := cCtx.StringSlice("config-directory") + for _, fConfigDirectory := range configDir { + files, err := config.WalkDirectory(fConfigDirectory) + if err != nil { + return err + } + configFiles = append(configFiles, files...) + } + + // If no "config" or "config-directory" flag(s) was + // provided we should load default configuration files + if len(configFiles) == 0 { + paths, err := config.GetDefaultConfigPath() + if err != nil { + return err + } + configFiles = paths + } + + // Load the config and try to initialize the plugins + c := config.NewConfig() + c.Agent.Quiet = cCtx.Bool("quiet") + if err := c.LoadAll(configFiles...); err != nil { + return err + } + + ag := agent.NewAgent(c) + + // Set the default for processor skipping + if c.Agent.SkipProcessorsAfterAggregators == nil { + msg := `The default value of 'skip_processors_after_aggregators' will change to 'true' with Telegraf v1.40.0! ` + msg += `If you need the current default behavior, please explicitly set the option to 'false'!` + log.Print("W! [agent] ", color.YellowString(msg)) + skipProcessorsAfterAggregators := false + c.Agent.SkipProcessorsAfterAggregators = &skipProcessorsAfterAggregators + } + + return ag.InitPlugins() + }, + }, + { + Name: "create", + Usage: "create a full sample configuration and show it", + Description: ` +The 'create' produces a full configuration containing all plugins as an example +and shows it on the console. You may apply 'section' or 'plugin' filtering +to reduce the output to the plugins you need + +Create the full configuration + +> telegraf config create + +To produce a configuration only containing a Modbus input plugin and an +InfluxDB v2 output plugin use + +> telegraf config create --section-filter "inputs:outputs" --input-filter "modbus" --output-filter "influxdb_v2" +`, + Flags: configHandlingFlags, + Action: func(cCtx *cli.Context) error { + filters := processFilterFlags(cCtx) + + printSampleConfig(outputBuffer, filters) + return nil + }, + }, + { + Name: "migrate", + Usage: "migrate deprecated plugins and options of the configuration(s)", + Description: ` +The 'migrate' command reads the configuration files specified via '--config' or +'--config-directory' and tries to migrate plugins or options that are currently +deprecated using the recommended replacements. If no configuration file is +explicitly specified the command reads the default locations and uses those +configuration files. Migrated files are stored with a '.migrated' suffix at the +location of the inputs. If you are migrating remote configurations the migrated +configurations is stored in the current directory using the filename of the URL +with a '.migrated' suffix. +It is highly recommended to test those migrated configurations before using +those files unattended! + +To migrate the file 'mysettings.conf' use + +> telegraf config migrate --config mysettings.conf +`, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "force", + Usage: "forces overwriting of an existing migration file", + }, + }, + Action: func(cCtx *cli.Context) error { + // Setup logging + logConfig := &logger.Config{Debug: cCtx.Bool("debug")} + if err := logger.SetupLogging(logConfig); err != nil { + return err + } + + // Check if we have migrations at all. There might be + // none if you run a custom build without migrations + // enabled. + if len(migrations.PluginMigrations) == 0 { + return errors.New("no migrations available") + } + log.Printf("%d plugin migration(s) available", len(migrations.PluginMigrations)) + + // Collect the given configuration files + configFiles := cCtx.StringSlice("config") + configDir := cCtx.StringSlice("config-directory") + for _, fConfigDirectory := range configDir { + files, err := config.WalkDirectory(fConfigDirectory) + if err != nil { + return err + } + configFiles = append(configFiles, files...) + } + + // If no "config" or "config-directory" flag(s) was + // provided we should load default configuration files + if len(configFiles) == 0 { + paths, err := config.GetDefaultConfigPath() + if err != nil { + return err + } + configFiles = paths + } + + for _, fn := range configFiles { + log.Printf("D! Trying to migrate %q...", fn) + + // Read and parse the config file + data, remote, err := config.LoadConfigFile(fn) + if err != nil { + return fmt.Errorf("opening input %q failed: %w", fn, err) + } + + out, applied, err := config.ApplyMigrations(data) + if err != nil { + return err + } + + // Do not write a migration file if nothing was done + if applied == 0 { + log.Printf("I! No migration applied for %q", fn) + continue + } + + // Construct the output filename + // For remote locations we just save the filename + // with the migrated suffix. + outfn := fn + ".migrated" + if remote { + u, err := url.Parse(fn) + if err != nil { + return fmt.Errorf("parsing remote config URL %q failed: %w", fn, err) + } + outfn = filepath.Base(u.Path) + ".migrated" + } + + log.Printf("I! %d migration applied for %q, writing result as %q", applied, fn, outfn) + + // Make sure the file does not exist yet if we should not overwrite + if !cCtx.Bool("force") { + if _, err := os.Stat(outfn); !errors.Is(err, os.ErrNotExist) { + return fmt.Errorf("output file %q already exists", outfn) + } + } + + // Write the output file + if err := os.WriteFile(outfn, out, 0640); err != nil { + return fmt.Errorf("writing output %q failed: %w", outfn, err) + } + } + return nil + }, + }, + }, + }, + } +} diff --git a/cmd/telegraf/cmd_plugins.go b/cmd/telegraf/cmd_plugins.go new file mode 100644 index 0000000..3b68ff5 --- /dev/null +++ b/cmd/telegraf/cmd_plugins.go @@ -0,0 +1,192 @@ +// Command handling for configuration "plugins" command +package main + +import ( + "fmt" + "io" + "sort" + "strings" + + "github.com/urfave/cli/v2" + + "github.com/influxdata/telegraf/plugins/aggregators" + "github.com/influxdata/telegraf/plugins/inputs" + "github.com/influxdata/telegraf/plugins/outputs" + "github.com/influxdata/telegraf/plugins/parsers" + "github.com/influxdata/telegraf/plugins/processors" + "github.com/influxdata/telegraf/plugins/secretstores" + "github.com/influxdata/telegraf/plugins/serializers" +) + +func pluginNames[M ~map[string]V, V any](m M, prefix string) []byte { + names := make([]string, 0, len(m)) + for k := range m { + names = append(names, fmt.Sprintf("%s.%s\n", prefix, k)) + } + sort.Strings(names) + return []byte(strings.Join(names, "")) +} + +func getPluginCommands(outputBuffer io.Writer) []*cli.Command { + return []*cli.Command{ + { + Name: "plugins", + Usage: "commands for printing available plugins", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "deprecated", + Usage: "print only deprecated plugins", + }, + }, + Action: func(cCtx *cli.Context) error { + if cCtx.Bool("deprecated") { + outputBuffer.Write(pluginNames(inputs.Deprecations, "inputs")) + outputBuffer.Write(pluginNames(outputs.Deprecations, "outputs")) + outputBuffer.Write(pluginNames(processors.Deprecations, "processors")) + outputBuffer.Write(pluginNames(aggregators.Deprecations, "aggregators")) + outputBuffer.Write(pluginNames(secretstores.Deprecations, "secretstores")) + outputBuffer.Write(pluginNames(parsers.Deprecations, "parsers")) + outputBuffer.Write(pluginNames(serializers.Deprecations, "serializers")) + } else { + outputBuffer.Write(pluginNames(inputs.Inputs, "inputs")) + outputBuffer.Write(pluginNames(outputs.Outputs, "outputs")) + outputBuffer.Write(pluginNames(processors.Processors, "processors")) + outputBuffer.Write(pluginNames(aggregators.Aggregators, "aggregators")) + outputBuffer.Write(pluginNames(secretstores.SecretStores, "secretstores")) + outputBuffer.Write(pluginNames(parsers.Parsers, "parsers")) + outputBuffer.Write(pluginNames(serializers.Serializers, "serializers")) + } + + return nil + }, + Subcommands: []*cli.Command{ + { + Name: "inputs", + Usage: "Print available input plugins", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "deprecated", + Usage: "print only deprecated plugins", + }, + }, + Action: func(cCtx *cli.Context) error { + if cCtx.Bool("deprecated") { + outputBuffer.Write(pluginNames(inputs.Deprecations, "inputs")) + } else { + outputBuffer.Write(pluginNames(inputs.Inputs, "inputs")) + } + return nil + }, + }, + { + Name: "outputs", + Usage: "Print available output plugins", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "deprecated", + Usage: "print only deprecated plugins", + }, + }, + Action: func(cCtx *cli.Context) error { + if cCtx.Bool("deprecated") { + outputBuffer.Write(pluginNames(outputs.Deprecations, "outputs")) + } else { + outputBuffer.Write(pluginNames(outputs.Outputs, "outputs")) + } + return nil + }, + }, + { + Name: "processors", + Usage: "Print available processor plugins", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "deprecated", + Usage: "print only deprecated plugins", + }, + }, + Action: func(cCtx *cli.Context) error { + if cCtx.Bool("deprecated") { + outputBuffer.Write(pluginNames(processors.Deprecations, "processors")) + } else { + outputBuffer.Write(pluginNames(processors.Processors, "processors")) + } + return nil + }, + }, + { + Name: "aggregators", + Usage: "Print available aggregator plugins", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "deprecated", + Usage: "print only deprecated plugins", + }, + }, + Action: func(cCtx *cli.Context) error { + if cCtx.Bool("deprecated") { + outputBuffer.Write(pluginNames(aggregators.Deprecations, "aggregators")) + } else { + outputBuffer.Write(pluginNames(aggregators.Aggregators, "aggregators")) + } + return nil + }, + }, + { + Name: "secretstores", + Usage: "Print available secretstore plugins", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "deprecated", + Usage: "print only deprecated plugins", + }, + }, + Action: func(cCtx *cli.Context) error { + if cCtx.Bool("deprecated") { + outputBuffer.Write(pluginNames(secretstores.Deprecations, "secretstores")) + } else { + outputBuffer.Write(pluginNames(secretstores.SecretStores, "secretstores")) + } + return nil + }, + }, + { + Name: "parsers", + Usage: "Print available parser plugins", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "deprecated", + Usage: "print only deprecated plugins", + }, + }, + Action: func(cCtx *cli.Context) error { + if cCtx.Bool("deprecated") { + outputBuffer.Write(pluginNames(parsers.Deprecations, "parsers")) + } else { + outputBuffer.Write(pluginNames(parsers.Parsers, "parsers")) + } + return nil + }, + }, + { + Name: "serializers", + Usage: "Print available serializer plugins", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "deprecated", + Usage: "print only deprecated plugins", + }, + }, + Action: func(cCtx *cli.Context) error { + if cCtx.Bool("deprecated") { + outputBuffer.Write(pluginNames(serializers.Deprecations, "serializers")) + } else { + outputBuffer.Write(pluginNames(serializers.Serializers, "serializers")) + } + return nil + }, + }, + }, + }, + } +} diff --git a/cmd/telegraf/cmd_secretstore.go b/cmd/telegraf/cmd_secretstore.go new file mode 100644 index 0000000..41b8f2d --- /dev/null +++ b/cmd/telegraf/cmd_secretstore.go @@ -0,0 +1,261 @@ +// Command handling for secret-stores' "secrets" command +package main + +import ( + "errors" + "fmt" + "os" + "sort" + "strings" + + "github.com/awnumar/memguard" + "github.com/urfave/cli/v2" + "golang.org/x/term" +) + +func processFilterOnlySecretStoreFlags(ctx *cli.Context) Filters { + sectionFilters := []string{"inputs", "outputs", "processors", "aggregators"} + inputFilters := []string{"-"} + outputFilters := []string{"-"} + processorFilters := []string{"-"} + aggregatorFilters := []string{"-"} + + // Only load the secret-stores + var secretstore string + if len(ctx.Lineage()) >= 2 { + parent := ctx.Lineage()[1] // ancestor contexts in order from child to parent + secretstore = parent.String("secretstore-filter") + } + + // If both the parent and command filters are defined, append them together + secretstore = appendFilter(secretstore, ctx.String("secretstore-filter")) + secretstoreFilters := deleteEmpty(strings.Split(secretstore, ":")) + return Filters{sectionFilters, inputFilters, outputFilters, aggregatorFilters, processorFilters, secretstoreFilters} +} + +func getSecretStoreCommands(m App) []*cli.Command { + return []*cli.Command{ + { + Name: "secrets", + Usage: "commands for listing, adding and removing secrets on all known secret-stores", + Subcommands: []*cli.Command{ + { + Name: "list", + Usage: "list known secrets and secret-stores", + Description: ` +The 'list' command requires passing in your configuration file +containing the secret-store definitions you want to access. To get a +list of available secret-store plugins, please have a look at +https://github.com/influxdata/telegraf/tree/master/plugins/secretstores. + +For help on how to define secret-stores, check the documentation of the +different plugins. + +Assuming you use the default configuration file location, you can run +the following command to list the keys of all known secrets in ALL +available stores + +> telegraf secrets list + +To get the keys of all known secrets in a particular store, you can run + +> telegraf secrets list mystore + +To also reveal the actual secret, i.e. the value, you can pass the +'--reveal-secret' flag. +`, + ArgsUsage: "[secret-store ID]...[secret-store ID]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "reveal-secret", + Usage: "also print the secret value", + }, + }, + Action: func(cCtx *cli.Context) error { + // Only load the secret-stores + filters := processFilterOnlySecretStoreFlags(cCtx) + g := GlobalFlags{ + config: cCtx.StringSlice("config"), + configDir: cCtx.StringSlice("config-directory"), + plugindDir: cCtx.String("plugin-directory"), + password: cCtx.String("password"), + debug: cCtx.Bool("debug"), + } + w := WindowFlags{} + m.Init(nil, filters, g, w) + + args := cCtx.Args() + var storeIDs []string + if args.Present() { + storeIDs = args.Slice() + } else { + ids, err := m.ListSecretStores() + if err != nil { + return fmt.Errorf("unable to determine secret-store IDs: %w", err) + } + storeIDs = ids + } + sort.Strings(storeIDs) + + reveal := cCtx.Bool("reveal-secret") + for _, storeID := range storeIDs { + store, err := m.GetSecretStore(storeID) + if err != nil { + return fmt.Errorf("unable to get secret-store %q: %w", storeID, err) + } + keys, err := store.List() + if err != nil { + return fmt.Errorf("unable to get secrets from store %q: %w", storeID, err) + } + sort.Strings(keys) + + fmt.Printf("Known secrets for store %q:\n", storeID) + for _, k := range keys { + var v []byte + if reveal { + if v, err = store.Get(k); err != nil { + return fmt.Errorf("unable to get value of secret %q from store %q: %w", k, storeID, err) + } + } + fmt.Printf(" %-30s %s\n", k, string(v)) + memguard.WipeBytes(v) + } + } + + return nil + }, + }, + { + Name: "get", + Usage: "retrieves value of given secret from given store", + Description: ` +The 'get' command requires passing in your configuration file +containing the secret-store definitions you want to access. To get a +list of available secret-store plugins, please have a look at +https://github.com/influxdata/telegraf/tree/master/plugins/secretstores. +and use the 'secrets list' command to get the IDs of available stores and +key(s) of available secrets. + +For help on how to define secret-stores, check the documentation of the +different plugins. + +Assuming you use the default configuration file location, you can run +the following command to retrieve a secret from a secret store +available stores + +> telegraf secrets get mystore mysecretkey + +This will fetch the secret with the key 'mysecretkey' from the secret-store +with the ID 'mystore'. +`, + ArgsUsage: " ", + Action: func(cCtx *cli.Context) error { + // Only load the secret-stores + filters := processFilterOnlySecretStoreFlags(cCtx) + g := GlobalFlags{ + config: cCtx.StringSlice("config"), + configDir: cCtx.StringSlice("config-directory"), + plugindDir: cCtx.String("plugin-directory"), + password: cCtx.String("password"), + debug: cCtx.Bool("debug"), + } + w := WindowFlags{} + m.Init(nil, filters, g, w) + + args := cCtx.Args() + if !args.Present() || args.Len() != 2 { + return errors.New("invalid number of arguments") + } + + storeID := args.First() + key := args.Get(1) + + store, err := m.GetSecretStore(storeID) + if err != nil { + return fmt.Errorf("unable to get secret-store: %w", err) + } + value, err := store.Get(key) + if err != nil { + return fmt.Errorf("unable to get secret: %w", err) + } + fmt.Printf("%s:%s = %s\n", storeID, key, value) + + return nil + }, + }, + { + Name: "set", + Usage: "create or modify a secret in the given store", + Description: ` +The 'set' command requires passing in your configuration file +containing the secret-store definitions you want to access. To get a +list of available secret-store plugins, please have a look at +https://github.com/influxdata/telegraf/tree/master/plugins/secretstores. +and use the 'secrets list' command to get the IDs of available stores and keys. + +For help on how to define secret-stores, check the documentation of the +different plugins. + +Assuming you use the default configuration file location, you can run +the following command to create a secret in anm available secret-store + +> telegraf secrets set mystore mysecretkey mysecretvalue + +This will create a secret with the key 'mysecretkey' in the secret-store +with the ID 'mystore' with the value being set to 'mysecretvalue'. If a +secret with that key ('mysecretkey') already existed in that store, its +value will be modified. + +When you leave out the value of the secret like + +> telegraf secrets set mystore mysecretkey + +you will be prompted to enter the value of the secret. +`, + ArgsUsage: " ", + Action: func(cCtx *cli.Context) error { + // Only load the secret-stores + filters := processFilterOnlySecretStoreFlags(cCtx) + g := GlobalFlags{ + config: cCtx.StringSlice("config"), + configDir: cCtx.StringSlice("config-directory"), + plugindDir: cCtx.String("plugin-directory"), + password: cCtx.String("password"), + debug: cCtx.Bool("debug"), + } + w := WindowFlags{} + m.Init(nil, filters, g, w) + + args := cCtx.Args() + if !args.Present() || args.Len() < 2 { + return errors.New("invalid number of arguments") + } + + storeID := args.First() + key := args.Get(1) + value := args.Get(2) + if value == "" { + fmt.Printf("Enter secret value: ") + b, err := term.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + return err + } + fmt.Println() + value = string(b) + } + + store, err := m.GetSecretStore(storeID) + if err != nil { + return fmt.Errorf("unable to get secret-store: %w", err) + } + if err := store.Set(key, value); err != nil { + return fmt.Errorf("unable to set secret: %w", err) + } + + return nil + }, + }, + }, + }, + } +} diff --git a/cmd/telegraf/cmd_win_service.go b/cmd/telegraf/cmd_win_service.go new file mode 100644 index 0000000..1e24112 --- /dev/null +++ b/cmd/telegraf/cmd_win_service.go @@ -0,0 +1,203 @@ +//go:build windows + +// Command handling for configuration "service" command +package main + +import ( + "errors" + "fmt" + "io" + + "github.com/urfave/cli/v2" + "golang.org/x/sys/windows" +) + +func cliFlags() []cli.Flag { + return []cli.Flag{ + &cli.StringFlag{ + Name: "service", + Usage: "operate on the service (windows only)", + }, + &cli.StringFlag{ + Name: "service-name", + Value: "telegraf", + Usage: "service name (windows only)", + }, + &cli.StringFlag{ + Name: "service-display-name", + Value: "Telegraf Data Collector Service", + Usage: "service display name (windows only)", + }, + &cli.StringFlag{ + Name: "service-restart-delay", + Value: "5m", + }, + &cli.BoolFlag{ + Name: "service-auto-restart", + Usage: "auto restart service on failure (windows only)", + }, + &cli.BoolFlag{ + Name: "console", + Usage: "run as console application (windows only)", + }, + } +} + +func getServiceCommands(outputBuffer io.Writer) []*cli.Command { + return []*cli.Command{ + { + Name: "service", + Usage: "commands for operate on the Windows service", + Flags: nil, + Subcommands: []*cli.Command{ + { + Name: "install", + Usage: "install Telegraf as a Windows service", + Description: ` +The 'install' command with create a Windows service for automatically starting +Telegraf with the specified configuration and service parameters. If no +configuration(s) is specified the service will use the file in +"C:\Program Files\Telegraf\telegraf.conf". + +To install Telegraf as a service use + +> telegraf service install + +In case you are planning to start multiple Telegraf instances as a service, +you must use distinctive service-names for each instance. To install two +services with different configurations use + +> telegraf --config "C:\Program Files\Telegraf\telegraf-machine.conf" --service-name telegraf-machine service install +> telegraf --config "C:\Program Files\Telegraf\telegraf-service.conf" --service-name telegraf-service service install +`, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "display-name", + Value: "Telegraf Data Collector Service", + Usage: "service name as displayed in the service manager", + }, + &cli.StringFlag{ + Name: "restart-delay", + Value: "5m", + Usage: "duration for delaying the service restart on failure", + }, + &cli.BoolFlag{ + Name: "auto-restart", + Usage: "enable automatic service restart on failure", + }, + }, + Action: func(cCtx *cli.Context) error { + cfg := &serviceConfig{ + displayName: cCtx.String("display-name"), + restartDelay: cCtx.String("restart-delay"), + autoRestart: cCtx.Bool("auto-restart"), + + configs: cCtx.StringSlice("config"), + configDirs: cCtx.StringSlice("config-directory"), + } + name := cCtx.String("service-name") + if err := installService(name, cfg); err != nil { + return err + } + fmt.Fprintf(outputBuffer, "Successfully installed service %q\n", name) + return nil + }, + }, + { + Name: "uninstall", + Usage: "remove the Telegraf Windows service", + Description: ` +The 'uninstall' command removes the Telegraf service with the given name. To +remove a service use + +> telegraf service uninstall + +In case you specified a custom service-name during install use + +> telegraf --service-name telegraf-machine service uninstall +`, + Action: func(cCtx *cli.Context) error { + name := cCtx.String("service-name") + if err := uninstallService(name); err != nil { + return err + } + fmt.Fprintf(outputBuffer, "Successfully uninstalled service %q\n", name) + return nil + }, + }, + { + Name: "start", + Usage: "start the Telegraf Windows service", + Description: ` +The 'start' command triggers the start of the Windows service with the given +name. To start the service either use the Windows service manager or run + +> telegraf service start + +In case you specified a custom service-name during install use + +> telegraf --service-name telegraf-machine service start +`, + Action: func(cCtx *cli.Context) error { + name := cCtx.String("service-name") + if err := startService(name); err != nil { + return err + } + fmt.Fprintf(outputBuffer, "Successfully started service %q\n", name) + return nil + }, + }, + { + Name: "stop", + Usage: "stop the Telegraf Windows service", + Description: ` +The 'stop' command triggers the stop of the Windows service with the given +name and will wait until the service is actually stopped. To stop the service +either use the Windows service manager or run + +> telegraf service stop + +In case you specified a custom service-name during install use + +> telegraf --service-name telegraf-machine service stop +`, + Action: func(cCtx *cli.Context) error { + name := cCtx.String("service-name") + if err := stopService(name); err != nil { + if errors.Is(err, windows.ERROR_SERVICE_NOT_ACTIVE) { + fmt.Fprintf(outputBuffer, "Service %q not started\n", name) + return nil + } + return err + } + fmt.Fprintf(outputBuffer, "Successfully stopped service %q\n", name) + return nil + }, + }, + { + Name: "status", + Usage: "query the Telegraf Windows service status", + Description: ` +The 'status' command queries the current state of the Windows service with the +given name. To query the service either check the Windows service manager or run + +> telegraf service status + +In case you specified a custom service-name during install use + +> telegraf --service-name telegraf-machine service status +`, + Action: func(cCtx *cli.Context) error { + name := cCtx.String("service-name") + status, err := queryService(name) + if err != nil { + return err + } + fmt.Fprintf(outputBuffer, "Service %q is in %q state\n", name, status) + return nil + }, + }, + }, + }, + } +} diff --git a/cmd/telegraf/cmd_win_service_notwindows.go b/cmd/telegraf/cmd_win_service_notwindows.go new file mode 100644 index 0000000..258d5c9 --- /dev/null +++ b/cmd/telegraf/cmd_win_service_notwindows.go @@ -0,0 +1,17 @@ +//go:build !windows + +package main + +import ( + "io" + + "github.com/urfave/cli/v2" +) + +func cliFlags() []cli.Flag { + return make([]cli.Flag, 0) +} + +func getServiceCommands(io.Writer) []*cli.Command { + return nil +} diff --git a/cmd/telegraf/main.go b/cmd/telegraf/main.go new file mode 100644 index 0000000..600c979 --- /dev/null +++ b/cmd/telegraf/main.go @@ -0,0 +1,417 @@ +package main + +import ( + "fmt" + "io" + "log" + "os" + "sort" + "strings" + + "github.com/awnumar/memguard" + "github.com/urfave/cli/v2" + + "github.com/influxdata/telegraf/config" + "github.com/influxdata/telegraf/internal" + "github.com/influxdata/telegraf/internal/goplugin" + "github.com/influxdata/telegraf/logger" + _ "github.com/influxdata/telegraf/plugins/aggregators/all" + "github.com/influxdata/telegraf/plugins/inputs" + _ "github.com/influxdata/telegraf/plugins/inputs/all" + "github.com/influxdata/telegraf/plugins/outputs" + _ "github.com/influxdata/telegraf/plugins/outputs/all" + _ "github.com/influxdata/telegraf/plugins/parsers/all" + _ "github.com/influxdata/telegraf/plugins/processors/all" + _ "github.com/influxdata/telegraf/plugins/secretstores/all" + _ "github.com/influxdata/telegraf/plugins/serializers/all" +) + +type TelegrafConfig interface { + CollectDeprecationInfos([]string, []string, []string, []string) map[string][]config.PluginDeprecationInfo + PrintDeprecationList([]config.PluginDeprecationInfo) +} + +type Filters struct { + section []string + input []string + output []string + aggregator []string + processor []string + secretstore []string +} + +func appendFilter(a, b string) string { + if a != "" && b != "" { + return fmt.Sprintf("%s:%s", a, b) + } + if a != "" { + return a + } + return b +} + +func processFilterFlags(ctx *cli.Context) Filters { + var section, input, output, aggregator, processor, secretstore string + + // Support defining filters before and after the command + // The old style was: + // ./telegraf --section-filter inputs --input-filter cpu config >test.conf + // The new style is: + // ./telegraf config --section-filter inputs --input-filter cpu >test.conf + // To support the old style, check if the parent context has the filter flags defined + if len(ctx.Lineage()) >= 2 { + parent := ctx.Lineage()[1] // ancestor contexts in order from child to parent + section = parent.String("section-filter") + input = parent.String("input-filter") + output = parent.String("output-filter") + aggregator = parent.String("aggregator-filter") + processor = parent.String("processor-filter") + secretstore = parent.String("secretstore-filter") + } + + // If both the parent and command filters are defined, append them together + section = appendFilter(section, ctx.String("section-filter")) + input = appendFilter(input, ctx.String("input-filter")) + output = appendFilter(output, ctx.String("output-filter")) + aggregator = appendFilter(aggregator, ctx.String("aggregator-filter")) + processor = appendFilter(processor, ctx.String("processor-filter")) + secretstore = appendFilter(secretstore, ctx.String("secretstore-filter")) + + sectionFilters := deleteEmpty(strings.Split(section, ":")) + inputFilters := deleteEmpty(strings.Split(input, ":")) + outputFilters := deleteEmpty(strings.Split(output, ":")) + aggregatorFilters := deleteEmpty(strings.Split(aggregator, ":")) + processorFilters := deleteEmpty(strings.Split(processor, ":")) + secretstoreFilters := deleteEmpty(strings.Split(secretstore, ":")) + return Filters{sectionFilters, inputFilters, outputFilters, aggregatorFilters, processorFilters, secretstoreFilters} +} + +func deleteEmpty(s []string) []string { + var r []string + for _, str := range s { + if str != "" { + r = append(r, str) + } + } + return r +} + +// runApp defines all the subcommands and flags for Telegraf +// this abstraction is used for testing, so outputBuffer and args can be changed +func runApp(args []string, outputBuffer io.Writer, pprof Server, c TelegrafConfig, m App) error { + configHandlingFlags := []cli.Flag{ + &cli.StringSliceFlag{ + Name: "config", + Usage: "configuration file to load", + }, + &cli.StringSliceFlag{ + Name: "config-directory", + Usage: "directory containing additional *.conf files", + }, + &cli.StringFlag{ + Name: "section-filter", + Usage: "filter the sections to print, separator is ':'. " + + "Valid values are 'agent', 'global_tags', 'outputs', 'processors', 'aggregators' and 'inputs'", + }, + &cli.StringFlag{ + Name: "input-filter", + Usage: "filter the inputs to enable, separator is ':'", + }, + &cli.StringFlag{ + Name: "output-filter", + Usage: "filter the outputs to enable, separator is ':'", + }, + &cli.StringFlag{ + Name: "aggregator-filter", + Usage: "filter the aggregators to enable, separator is ':'", + }, + &cli.StringFlag{ + Name: "processor-filter", + Usage: "filter the processors to enable, separator is ':'", + }, + &cli.StringFlag{ + Name: "secretstore-filter", + Usage: "filter the secret-stores to enable, separator is ':'", + }, + } + + mainFlags := append(configHandlingFlags, cliFlags()...) + + // This function is used when Telegraf is run with only flags + action := func(cCtx *cli.Context) error { + // We do not expect any arguments this is likely a misspelling of + // a command... + if cCtx.NArg() > 0 { + return fmt.Errorf("unknown command %q", cCtx.Args().First()) + } + + // Deprecated: Use execd instead + // Load external plugins, if requested. + if cCtx.String("plugin-directory") != "" { + log.Printf("I! Loading external plugins from: %s", cCtx.String("plugin-directory")) + if err := goplugin.LoadExternalPlugins(cCtx.String("plugin-directory")); err != nil { + return err + } + } + + // switch for flags which just do something and exit immediately + switch { + // print available input plugins + case cCtx.Bool("deprecation-list"): + filters := processFilterFlags(cCtx) + infos := c.CollectDeprecationInfos( + filters.input, filters.output, filters.aggregator, filters.processor, + ) + outputBuffer.Write([]byte("Deprecated Input Plugins:\n")) + c.PrintDeprecationList(infos["inputs"]) + outputBuffer.Write([]byte("Deprecated Output Plugins:\n")) + c.PrintDeprecationList(infos["outputs"]) + outputBuffer.Write([]byte("Deprecated Processor Plugins:\n")) + c.PrintDeprecationList(infos["processors"]) + outputBuffer.Write([]byte("Deprecated Aggregator Plugins:\n")) + c.PrintDeprecationList(infos["aggregators"]) + return nil + // print available output plugins + case cCtx.Bool("output-list"): + outputBuffer.Write([]byte("DEPRECATED: use telegraf plugins outputs\n")) + outputBuffer.Write([]byte("Available Output Plugins:\n")) + names := make([]string, 0, len(outputs.Outputs)) + for k := range outputs.Outputs { + names = append(names, k) + } + sort.Strings(names) + for _, k := range names { + fmt.Fprintf(outputBuffer, " %s\n", k) + } + return nil + // print available input plugins + case cCtx.Bool("input-list"): + outputBuffer.Write([]byte("DEPRECATED: use telegraf plugins inputs\n")) + outputBuffer.Write([]byte("Available Input Plugins:\n")) + names := make([]string, 0, len(inputs.Inputs)) + for k := range inputs.Inputs { + names = append(names, k) + } + sort.Strings(names) + for _, k := range names { + fmt.Fprintf(outputBuffer, " %s\n", k) + } + return nil + // print usage for a plugin, ie, 'telegraf --usage mysql' + case cCtx.String("usage") != "": + err := PrintInputConfig(cCtx.String("usage"), outputBuffer) + err2 := PrintOutputConfig(cCtx.String("usage"), outputBuffer) + if err != nil && err2 != nil { + return fmt.Errorf("%w and %w", err, err2) + } + return nil + // DEPRECATED + case cCtx.Bool("version"): + fmt.Fprintf(outputBuffer, "%s\n", internal.FormatFullVersion()) + return nil + // DEPRECATED + case cCtx.Bool("sample-config"): + filters := processFilterFlags(cCtx) + + printSampleConfig(outputBuffer, filters) + return nil + } + + if cCtx.String("pprof-addr") != "" { + pprof.Start(cCtx.String("pprof-addr")) + } + + filters := processFilterFlags(cCtx) + + g := GlobalFlags{ + config: cCtx.StringSlice("config"), + configDir: cCtx.StringSlice("config-directory"), + testWait: cCtx.Int("test-wait"), + configURLRetryAttempts: cCtx.Int("config-url-retry-attempts"), + configURLWatchInterval: cCtx.Duration("config-url-watch-interval"), + watchConfig: cCtx.String("watch-config"), + watchInterval: cCtx.Duration("watch-interval"), + pidFile: cCtx.String("pidfile"), + plugindDir: cCtx.String("plugin-directory"), + password: cCtx.String("password"), + oldEnvBehavior: cCtx.Bool("old-env-behavior"), + printPluginConfigSource: cCtx.Bool("print-plugin-config-source"), + test: cCtx.Bool("test"), + debug: cCtx.Bool("debug"), + once: cCtx.Bool("once"), + quiet: cCtx.Bool("quiet"), + unprotected: cCtx.Bool("unprotected"), + } + + w := WindowFlags{ + service: cCtx.String("service"), + serviceName: cCtx.String("service-name"), + serviceDisplayName: cCtx.String("service-display-name"), + serviceRestartDelay: cCtx.String("service-restart-delay"), + serviceAutoRestart: cCtx.Bool("service-auto-restart"), + console: cCtx.Bool("console"), + } + + m.Init(pprof.ErrChan(), filters, g, w) + return m.Run() + } + + commands := append( + getConfigCommands(configHandlingFlags, outputBuffer), + getSecretStoreCommands(m)..., + ) + commands = append(commands, getPluginCommands(outputBuffer)...) + commands = append(commands, getServiceCommands(outputBuffer)...) + + app := &cli.App{ + Name: "Telegraf", + Usage: "The plugin-driven server agent for collecting & reporting metrics.", + Writer: outputBuffer, + Flags: append( + []cli.Flag{ + // Int flags + &cli.IntFlag{ + Name: "test-wait", + Usage: "wait up to this many seconds for service inputs to complete in test mode", + }, + &cli.IntFlag{ + Name: "config-url-retry-attempts", + Usage: "Number of attempts to obtain a remote configuration via a URL during startup. " + + "Set to -1 for unlimited attempts.", + DefaultText: "3", + }, + // + // String flags + &cli.StringFlag{ + Name: "usage", + Usage: "print usage for a plugin, ie, 'telegraf --usage mysql'", + }, + &cli.StringFlag{ + Name: "pprof-addr", + Usage: "pprof host/IP and port to listen on (e.g. 'localhost:6060')", + }, + &cli.StringFlag{ + Name: "watch-config", + Usage: "monitoring config changes [notify, poll] of --config and --config-directory options. " + + "Notify supports linux, *bsd, and macOS. Poll is required for Windows and checks every 250ms.", + }, + &cli.StringFlag{ + Name: "pidfile", + Usage: "file to write our pid to", + }, + &cli.StringFlag{ + Name: "password", + Usage: "password to unlock secret-stores", + }, + // + // Bool flags + &cli.BoolFlag{ + Name: "old-env-behavior", + Usage: "switch back to pre v1.27 environment replacement behavior", + }, + &cli.BoolFlag{ + Name: "print-plugin-config-source", + Usage: "print the source for a given plugin", + }, + &cli.BoolFlag{ + Name: "once", + Usage: "run one gather and exit", + }, + &cli.BoolFlag{ + Name: "debug", + Usage: "turn on debug logging", + }, + &cli.BoolFlag{ + Name: "quiet", + Usage: "run in quiet mode", + }, + &cli.BoolFlag{ + Name: "unprotected", + Usage: "do not protect secrets in memory", + }, + &cli.BoolFlag{ + Name: "test", + Usage: "enable test mode: gather metrics, print them out, and exit. " + + "Note: Test mode only runs inputs, not processors, aggregators, or outputs", + }, + // + // Duration flags + &cli.DurationFlag{ + Name: "watch-interval", + Usage: "Time duration to check for updates to config files specified by --config and " + + "--config-directory options. Use with '--watch-config poll'", + DefaultText: "disabled", + }, + &cli.DurationFlag{ + Name: "config-url-watch-interval", + Usage: "Time duration to check for updates to URL based configuration files", + DefaultText: "disabled", + }, + // TODO: Change "deprecation-list, input-list, output-list" flags to become a subcommand "list" that takes + // "input,output,aggregator,processor, deprecated" as parameters + &cli.BoolFlag{ + Name: "deprecation-list", + Usage: "print all deprecated plugins or plugin options", + }, + &cli.BoolFlag{ + Name: "input-list", + Usage: "print available input plugins", + }, + &cli.BoolFlag{ + Name: "output-list", + Usage: "print available output plugins", + }, + // + // !!! The following flags are DEPRECATED !!! + // Already covered with the subcommand `./telegraf version` + &cli.BoolFlag{ + Name: "version", + Usage: "DEPRECATED: display the version and exit", + }, + // Already covered with the subcommand `./telegraf config` + &cli.BoolFlag{ + Name: "sample-config", + Usage: "DEPRECATED: print out full sample configuration", + }, + // Using execd plugin to add external plugins is preferred (less size impact, easier for end user) + &cli.StringFlag{ + Name: "plugin-directory", + Usage: "DEPRECATED: path to directory containing external plugins", + }, + // !!! + }, mainFlags...), + Action: action, + Commands: append([]*cli.Command{ + { + Name: "version", + Usage: "print current version to stdout", + Action: func(*cli.Context) error { + fmt.Fprintf(outputBuffer, "%s\n", internal.FormatFullVersion()) + return nil + }, + }, + }, commands...), + } + + // Make sure we safely erase secrets + defer memguard.Purge() + defer logger.CloseLogging() + + if err := app.Run(args); err != nil { + log.Printf("E! %s", err) + return err + } + return nil +} + +func main() { + // #13481: disables gh:99designs/keyring kwallet.go from connecting to dbus + os.Setenv("DISABLE_KWALLET", "1") + + agent := Telegraf{} + pprof := NewPprofServer() + c := config.NewConfig() + if err := runApp(os.Args, os.Stdout, pprof, c, &agent); err != nil { + os.Exit(1) + } +} diff --git a/cmd/telegraf/main_test.go b/cmd/telegraf/main_test.go new file mode 100644 index 0000000..63da18a --- /dev/null +++ b/cmd/telegraf/main_test.go @@ -0,0 +1,574 @@ +package main + +import ( + "bytes" + "errors" + "fmt" + "io" + "os" + "strconv" + "strings" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/config" + "github.com/influxdata/telegraf/internal" + "github.com/influxdata/telegraf/plugins/inputs" + "github.com/influxdata/telegraf/plugins/outputs" +) + +var secrets = map[string]map[string][]byte{ + "yoda": { + "episode1": []byte("member"), + "episode2": []byte("member"), + "episode3": []byte("member"), + }, + "mace_windu": { + "episode1": []byte("member"), + "episode2": []byte("member"), + "episode3": []byte("member"), + }, + "oppo_rancisis": { + "episode1": []byte("member"), + "episode2": []byte("member"), + }, + "coleman_kcaj": { + "episode3": []byte("member"), + }, +} + +type MockTelegraf struct { + GlobalFlags + WindowFlags +} + +func NewMockTelegraf() *MockTelegraf { + return &MockTelegraf{} +} + +func (m *MockTelegraf) Init(_ <-chan error, _ Filters, g GlobalFlags, w WindowFlags) { + m.GlobalFlags = g + m.WindowFlags = w +} + +func (*MockTelegraf) Run() error { + return nil +} + +func (*MockTelegraf) ListSecretStores() ([]string, error) { + ids := make([]string, 0, len(secrets)) + for k := range secrets { + ids = append(ids, k) + } + return ids, nil +} + +func (*MockTelegraf) GetSecretStore(id string) (telegraf.SecretStore, error) { + v, found := secrets[id] + if !found { + return nil, errors.New("unknown secret store") + } + s := &MockSecretStore{Secrets: v} + return s, nil +} + +type MockSecretStore struct { + Secrets map[string][]byte +} + +func (*MockSecretStore) Init() error { + return nil +} + +func (*MockSecretStore) SampleConfig() string { + return "I'm just a dummy" +} + +func (s *MockSecretStore) Get(key string) ([]byte, error) { + v, found := s.Secrets[key] + if !found { + return nil, errors.New("not found") + } + return v, nil +} + +func (s *MockSecretStore) Set(key, value string) error { + if strings.HasPrefix(key, "darth") { + return errors.New("don't join the dark side") + } + s.Secrets[key] = []byte(value) + return nil +} +func (s *MockSecretStore) List() ([]string, error) { + keys := make([]string, 0, len(s.Secrets)) + for k := range s.Secrets { + keys = append(keys, k) + } + return keys, nil +} + +func (s *MockSecretStore) GetResolver(key string) (telegraf.ResolveFunc, error) { + return func() ([]byte, bool, error) { + v, err := s.Get(key) + return v, false, err + }, nil +} + +type MockConfig struct { + Buffer io.Writer + ExpectedDeprecatedPlugins map[string][]config.PluginDeprecationInfo +} + +func NewMockConfig(buffer io.Writer) *MockConfig { + return &MockConfig{ + Buffer: buffer, + } +} + +func (m *MockConfig) CollectDeprecationInfos(_, _, _, _ []string) map[string][]config.PluginDeprecationInfo { + return m.ExpectedDeprecatedPlugins +} + +func (m *MockConfig) PrintDeprecationList(plugins []config.PluginDeprecationInfo) { + for _, p := range plugins { + fmt.Fprintf(m.Buffer, "plugin name: %s\n", p.Name) + } +} + +type MockServer struct { + Address string +} + +func NewMockServer() *MockServer { + return &MockServer{} +} + +func (m *MockServer) Start(_ string) { + m.Address = "localhost:6060" +} + +func (*MockServer) ErrChan() <-chan error { + return nil +} + +func TestUsageFlag(t *testing.T) { + tests := []struct { + PluginName string + ExpectedError string + ExpectedOutput string + }{ + { + PluginName: "example", + ExpectedError: "input example not found and output example not found", + }, + { + PluginName: "temp", + ExpectedOutput: ` +# Read metrics about temperature +[[inputs.temp]] + ## Desired output format (Linux only) + ## Available values are + ## v1 -- use pre-v1.22.4 sensor naming, e.g. coretemp_core0_input + ## v2 -- use v1.22.4+ sensor naming, e.g. coretemp_core_0_input + # metric_format = "v2" + + ## Add device tag to distinguish devices with the same name (Linux only) + # add_device_tag = false + +`, + }, + } + + for _, test := range tests { + buf := new(bytes.Buffer) + args := os.Args[0:1] + args = append(args, "--usage", test.PluginName) + err := runApp(args, buf, NewMockServer(), NewMockConfig(buf), NewMockTelegraf()) + if test.ExpectedError != "" { + require.ErrorContains(t, err, test.ExpectedError) + continue + } + require.NoError(t, err) + // To run this test on windows and linux, remove windows carriage return + o := strings.Replace(buf.String(), "\r", "", -1) + require.Equal(t, test.ExpectedOutput, o) + } +} + +func TestInputListFlag(t *testing.T) { + buf := new(bytes.Buffer) + args := os.Args[0:1] + args = append(args, "--input-list") + temp := inputs.Inputs + inputs.Inputs = map[string]inputs.Creator{ + "test": func() telegraf.Input { return nil }, + } + err := runApp(args, buf, NewMockServer(), NewMockConfig(buf), NewMockTelegraf()) + require.NoError(t, err) + expectedOutput := `DEPRECATED: use telegraf plugins inputs +Available Input Plugins: + test +` + require.Equal(t, expectedOutput, buf.String()) + inputs.Inputs = temp +} + +func TestOutputListFlag(t *testing.T) { + buf := new(bytes.Buffer) + args := os.Args[0:1] + args = append(args, "--output-list") + temp := outputs.Outputs + outputs.Outputs = map[string]outputs.Creator{ + "test": func() telegraf.Output { return nil }, + } + err := runApp(args, buf, NewMockServer(), NewMockConfig(buf), NewMockTelegraf()) + require.NoError(t, err) + expectedOutput := `DEPRECATED: use telegraf plugins outputs +Available Output Plugins: + test +` + require.Equal(t, expectedOutput, buf.String()) + outputs.Outputs = temp +} + +func TestDeprecationListFlag(t *testing.T) { + buf := new(bytes.Buffer) + args := os.Args[0:1] + args = append(args, "--deprecation-list") + mS := NewMockServer() + mC := NewMockConfig(buf) + mC.ExpectedDeprecatedPlugins = make(map[string][]config.PluginDeprecationInfo) + mC.ExpectedDeprecatedPlugins["inputs"] = []config.PluginDeprecationInfo{ + { + DeprecationInfo: config.DeprecationInfo{ + Name: "test", + }, + }, + } + err := runApp(args, buf, mS, mC, NewMockTelegraf()) + require.NoError(t, err) + expectedOutput := `Deprecated Input Plugins: +plugin name: test +Deprecated Output Plugins: +Deprecated Processor Plugins: +Deprecated Aggregator Plugins: +` + + require.Equal(t, expectedOutput, buf.String()) +} + +func TestPprofAddressFlag(t *testing.T) { + buf := new(bytes.Buffer) + args := os.Args[0:1] + address := "localhost:6060" + args = append(args, "--pprof-addr", address) + m := NewMockServer() + err := runApp(args, buf, m, NewMockConfig(buf), NewMockTelegraf()) + require.NoError(t, err) + require.Equal(t, address, m.Address) +} + +// !!! DEPRECATED !!! +// TestPluginDirectoryFlag tests `--plugin-directory` +func TestPluginDirectoryFlag(t *testing.T) { + buf := new(bytes.Buffer) + args := os.Args[0:1] + args = append(args, "--plugin-directory", ".") + err := runApp(args, buf, NewMockServer(), NewMockConfig(buf), NewMockTelegraf()) + require.ErrorContains(t, err, "go plugin support is not enabled") +} + +func TestCommandConfig(t *testing.T) { + tests := []struct { + name string + commands []string + expectedHeaders []string + removedHeaders []string + expectedPlugins []string + removedPlugins []string + }{ + { + name: "deprecated flag --sample-config", + commands: []string{"--sample-config"}, + expectedHeaders: []string{ + outputHeader, + inputHeader, + aggregatorHeader, + processorHeader, + serviceInputHeader, + }, + }, + { + name: "no filters", + commands: []string{"config"}, + expectedHeaders: []string{ + outputHeader, + inputHeader, + aggregatorHeader, + processorHeader, + serviceInputHeader, + }, + }, + { + name: "filter sections for inputs", + commands: []string{"config", "--section-filter", "inputs"}, + expectedHeaders: []string{ + inputHeader, + }, + removedHeaders: []string{ + outputHeader, + aggregatorHeader, + processorHeader, + }, + }, + { + name: "filter sections for inputs,outputs", + commands: []string{"config", "--section-filter", "inputs:outputs"}, + expectedHeaders: []string{ + inputHeader, + outputHeader, + }, + removedHeaders: []string{ + aggregatorHeader, + processorHeader, + }, + }, + { + name: "filter input plugins", + commands: []string{"config", "--input-filter", "cpu:file"}, + expectedPlugins: []string{ + "[[inputs.cpu]]", + "[[inputs.file]]", + }, + removedPlugins: []string{ + "[[inputs.disk]]", + }, + }, + { + name: "filter output plugins", + commands: []string{"config", "--output-filter", "influxdb:http"}, + expectedPlugins: []string{ + "[[outputs.influxdb]]", + "[[outputs.http]]", + }, + removedPlugins: []string{ + "[[outputs.file]]", + }, + }, + { + name: "filter processor plugins", + commands: []string{"config", "--processor-filter", "date:enum"}, + expectedPlugins: []string{ + "[[processors.date]]", + "[[processors.enum]]", + }, + removedPlugins: []string{ + "[[processors.parser]]", + }, + }, + { + name: "filter aggregator plugins", + commands: []string{"config", "--aggregator-filter", "basicstats:starlark"}, + expectedPlugins: []string{ + "[[aggregators.basicstats]]", + "[[aggregators.starlark]]", + }, + removedPlugins: []string{ + "[[aggregators.minmax]]", + }, + }, + { + name: "test filters before config", + commands: []string{"--input-filter", "cpu:file", "config"}, + expectedPlugins: []string{ + "[[inputs.cpu]]", + "[[inputs.file]]", + }, + removedPlugins: []string{ + "[[inputs.disk]]", + }, + }, + { + name: "test filters before and after config", + commands: []string{"--input-filter", "file", "config", "--input-filter", "cpu"}, + expectedPlugins: []string{ + "[[inputs.cpu]]", + "[[inputs.file]]", + }, + removedPlugins: []string{ + "[[inputs.disk]]", + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + buf := new(bytes.Buffer) + args := os.Args[0:1] + args = append(args, test.commands...) + err := runApp(args, buf, NewMockServer(), NewMockConfig(buf), NewMockTelegraf()) + require.NoError(t, err) + output := buf.String() + for _, e := range test.expectedHeaders { + require.Contains(t, output, e, "expected header not found") + } + for _, r := range test.removedHeaders { + require.NotContains(t, output, r, "removed header found") + } + for _, e := range test.expectedPlugins { + require.Contains(t, output, e, "expected plugin not found") + } + for _, r := range test.removedPlugins { + require.NotContains(t, output, r, "removed plugin found") + } + }) + } +} + +func TestCommandVersion(t *testing.T) { + tests := []struct { + Version string + Branch string + Commit string + ExpectedOutput string + }{ + { + Version: "v2.0.0", + ExpectedOutput: "Telegraf v2.0.0\n", + }, + { + ExpectedOutput: "Telegraf unknown\n", + }, + { + Version: "v2.0.0", + Branch: "master", + ExpectedOutput: "Telegraf v2.0.0 (git: master@unknown)\n", + }, + { + Version: "v2.0.0", + Branch: "master", + Commit: "123", + ExpectedOutput: "Telegraf v2.0.0 (git: master@123)\n", + }, + { + Version: "v2.0.0", + Commit: "123", + ExpectedOutput: "Telegraf v2.0.0 (git: unknown@123)\n", + }, + } + + for _, test := range tests { + buf := new(bytes.Buffer) + args := os.Args[0:1] + args = append(args, "version") + internal.Version = test.Version + internal.Branch = test.Branch + internal.Commit = test.Commit + err := runApp(args, buf, NewMockServer(), NewMockConfig(buf), NewMockTelegraf()) + require.NoError(t, err) + require.Equal(t, test.ExpectedOutput, buf.String()) + } +} + +// Users should use the version subcommand +func TestFlagVersion(t *testing.T) { + tests := []struct { + Version string + Branch string + Commit string + ExpectedOutput string + }{ + { + Version: "v2.0.0", + ExpectedOutput: "Telegraf v2.0.0\n", + }, + { + ExpectedOutput: "Telegraf unknown\n", + }, + { + Version: "v2.0.0", + Branch: "master", + ExpectedOutput: "Telegraf v2.0.0 (git: master@unknown)\n", + }, + { + Version: "v2.0.0", + Branch: "master", + Commit: "123", + ExpectedOutput: "Telegraf v2.0.0 (git: master@123)\n", + }, + { + Version: "v2.0.0", + Commit: "123", + ExpectedOutput: "Telegraf v2.0.0 (git: unknown@123)\n", + }, + } + + for _, test := range tests { + buf := new(bytes.Buffer) + args := os.Args[0:1] + args = append(args, "--version") + internal.Version = test.Version + internal.Branch = test.Branch + internal.Commit = test.Commit + err := runApp(args, buf, NewMockServer(), NewMockConfig(buf), NewMockTelegraf()) + require.NoError(t, err) + require.Equal(t, test.ExpectedOutput, buf.String()) + } +} + +func TestGlobablBoolFlags(t *testing.T) { + commands := []string{ + "--debug", + "--test", + "--quiet", + "--once", + } + + buf := new(bytes.Buffer) + args := os.Args[0:1] + args = append(args, commands...) + m := NewMockTelegraf() + err := runApp(args, buf, NewMockServer(), NewMockConfig(buf), m) + require.NoError(t, err) + + require.True(t, m.debug) + require.True(t, m.test) + require.True(t, m.once) + require.True(t, m.quiet) +} + +func TestFlagsAreSet(t *testing.T) { + expectedInt := 1 + expectedString := "test" + + commands := []string{ + "--config", expectedString, + "--config-directory", expectedString, + "--debug", + "--test", + "--quiet", + "--once", + "--test-wait", strconv.Itoa(expectedInt), + "--watch-config", expectedString, + "--pidfile", expectedString, + } + + buf := new(bytes.Buffer) + args := os.Args[0:1] + args = append(args, commands...) + m := NewMockTelegraf() + err := runApp(args, buf, NewMockServer(), NewMockConfig(buf), m) + require.NoError(t, err) + + require.Equal(t, []string{expectedString}, m.config) + require.Equal(t, []string{expectedString}, m.configDir) + require.True(t, m.debug) + require.True(t, m.test) + require.True(t, m.once) + require.True(t, m.quiet) + require.Equal(t, expectedInt, m.testWait) + require.Equal(t, expectedString, m.watchConfig) + require.Equal(t, expectedString, m.pidFile) +} diff --git a/cmd/telegraf/main_win_test.go b/cmd/telegraf/main_win_test.go new file mode 100644 index 0000000..000d148 --- /dev/null +++ b/cmd/telegraf/main_win_test.go @@ -0,0 +1,38 @@ +//go:build windows + +package main + +import ( + "bytes" + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestWindowsFlagsAreSet(t *testing.T) { + expectedString := "test" + + commands := []string{ + "--service", expectedString, + "--service-name", expectedString, + "--service-display-name", expectedString, + "--service-restart-delay", expectedString, + "--service-auto-restart", + "--console", + } + + buf := new(bytes.Buffer) + args := os.Args[0:1] + args = append(args, commands...) + m := NewMockTelegraf() + err := runApp(args, buf, NewMockServer(), NewMockConfig(buf), m) + require.NoError(t, err) + + require.Equal(t, expectedString, m.service) + require.Equal(t, expectedString, m.serviceName) + require.Equal(t, expectedString, m.serviceDisplayName) + require.Equal(t, expectedString, m.serviceRestartDelay) + require.True(t, m.serviceAutoRestart) + require.True(t, m.console) +} diff --git a/cmd/telegraf/pprof.go b/cmd/telegraf/pprof.go new file mode 100644 index 0000000..60d217f --- /dev/null +++ b/cmd/telegraf/pprof.go @@ -0,0 +1,52 @@ +package main + +import ( + "log" + "net/http" + _ "net/http/pprof" //nolint:gosec // Import for pprof, only enabled via CLI flag + "strings" + "time" +) + +type Server interface { + Start(string) + ErrChan() <-chan error +} + +type PprofServer struct { + err chan error +} + +func NewPprofServer() *PprofServer { + return &PprofServer{ + err: make(chan error), + } +} + +func (p *PprofServer) Start(address string) { + go func() { + pprofHostPort := address + parts := strings.Split(pprofHostPort, ":") + if len(parts) == 2 && parts[0] == "" { + pprofHostPort = "localhost:" + parts[1] + } + pprofHostPort = "http://" + pprofHostPort + "/debug/pprof" + + log.Printf("I! Starting pprof HTTP server at: %s", pprofHostPort) + + server := &http.Server{ + Addr: address, + ReadTimeout: 10 * time.Second, + WriteTimeout: 10 * time.Second, + } + + if err := server.ListenAndServe(); err != nil { + p.err <- err + } + close(p.err) + }() +} + +func (p *PprofServer) ErrChan() <-chan error { + return p.err +} diff --git a/cmd/telegraf/printer.go b/cmd/telegraf/printer.go new file mode 100644 index 0000000..de92d6f --- /dev/null +++ b/cmd/telegraf/printer.go @@ -0,0 +1,408 @@ +package main + +import ( + _ "embed" + "fmt" + "io" + "sort" + "strings" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/internal/choice" + "github.com/influxdata/telegraf/plugins/aggregators" + "github.com/influxdata/telegraf/plugins/inputs" + "github.com/influxdata/telegraf/plugins/outputs" + "github.com/influxdata/telegraf/plugins/processors" + "github.com/influxdata/telegraf/plugins/secretstores" +) + +var ( + // Default sections + sectionDefaults = []string{"global_tags", "agent", "secretstores", "outputs", "processors", "aggregators", "inputs"} + + // Default input plugins + inputDefaults = []string{"cpu", "mem", "swap", "system", "kernel", "processes", "disk", "diskio"} + + // Default output plugins + outputDefaults = make([]string, 0) +) + +var header = `# Telegraf Configuration +# +# Telegraf is entirely plugin driven. All metrics are gathered from the +# declared inputs, and sent to the declared outputs. +# +# Plugins must be declared in here to be active. +# To deactivate a plugin, comment out the name and any variables. +# +# Use 'telegraf -config telegraf.conf -test' to see what metrics a config +# file would generate. +# +# Environment variables can be used anywhere in this config file, simply surround +# them with ${}. For strings the variable must be within quotes (ie, "${STR_VAR}"), +# for numbers and booleans they should be plain (ie, ${INT_VAR}, ${BOOL_VAR}) + +` +var globalTagsConfig = ` +# Global tags can be specified here in key="value" format. +[global_tags] + # dc = "us-east-1" # will tag all metrics with dc=us-east-1 + # rack = "1a" + ## Environment variables can be used as tags, and throughout the config file + # user = "$USER" + +` + +// DO NOT REMOVE THE NEXT TWO LINES! This is required to embed the agentConfig data. +// +//go:embed agent.conf +var agentConfig string + +var secretstoreHeader = ` +############################################################################### +# SECRETSTORE PLUGINS # +############################################################################### + +` + +var outputHeader = ` +############################################################################### +# OUTPUT PLUGINS # +############################################################################### + +` + +var processorHeader = ` +############################################################################### +# PROCESSOR PLUGINS # +############################################################################### + +` + +var aggregatorHeader = ` +############################################################################### +# AGGREGATOR PLUGINS # +############################################################################### + +` + +var inputHeader = ` +############################################################################### +# INPUT PLUGINS # +############################################################################### + +` + +var serviceInputHeader = ` +############################################################################### +# SERVICE INPUT PLUGINS # +############################################################################### + +` + +// printSampleConfig prints the sample config +func printSampleConfig(outputBuffer io.Writer, filters Filters) { + sectionFilters := filters.section + inputFilters := filters.input + outputFilters := filters.output + aggregatorFilters := filters.aggregator + processorFilters := filters.processor + secretstoreFilters := filters.secretstore + + // print headers + outputBuffer.Write([]byte(header)) + + if len(sectionFilters) == 0 { + sectionFilters = sectionDefaults + } + printFilteredGlobalSections(sectionFilters, outputBuffer) + + // print secretstore plugins + if choice.Contains("secretstores", sectionFilters) { + if len(secretstoreFilters) != 0 { + if len(secretstoreFilters) >= 3 && secretstoreFilters[1] != "none" { + fmt.Print(secretstoreHeader) + } + printFilteredSecretstores(secretstoreFilters, false, outputBuffer) + } else { + fmt.Print(secretstoreHeader) + snames := make([]string, 0, len(secretstores.SecretStores)) + for sname := range secretstores.SecretStores { + snames = append(snames, sname) + } + sort.Strings(snames) + printFilteredSecretstores(snames, true, outputBuffer) + } + } + + // print output plugins + if choice.Contains("outputs", sectionFilters) { + if len(outputFilters) != 0 { + if len(outputFilters) >= 3 && outputFilters[1] != "none" { + outputBuffer.Write([]byte(outputHeader)) + } + printFilteredOutputs(outputFilters, false, outputBuffer) + } else { + outputBuffer.Write([]byte(outputHeader)) + printFilteredOutputs(outputDefaults, false, outputBuffer) + // Print non-default outputs, commented + var pnames []string + for pname := range outputs.Outputs { + if !choice.Contains(pname, outputDefaults) { + pnames = append(pnames, pname) + } + } + printFilteredOutputs(pnames, true, outputBuffer) + } + } + + // print processor plugins + if choice.Contains("processors", sectionFilters) { + if len(processorFilters) != 0 { + if len(processorFilters) >= 3 && processorFilters[1] != "none" { + outputBuffer.Write([]byte(processorHeader)) + } + printFilteredProcessors(processorFilters, false, outputBuffer) + } else { + outputBuffer.Write([]byte(processorHeader)) + pnames := make([]string, 0, len(processors.Processors)) + for pname := range processors.Processors { + pnames = append(pnames, pname) + } + printFilteredProcessors(pnames, true, outputBuffer) + } + } + + // print aggregator plugins + if choice.Contains("aggregators", sectionFilters) { + if len(aggregatorFilters) != 0 { + if len(aggregatorFilters) >= 3 && aggregatorFilters[1] != "none" { + outputBuffer.Write([]byte(aggregatorHeader)) + } + printFilteredAggregators(aggregatorFilters, false, outputBuffer) + } else { + outputBuffer.Write([]byte(aggregatorHeader)) + pnames := make([]string, 0, len(aggregators.Aggregators)) + for pname := range aggregators.Aggregators { + pnames = append(pnames, pname) + } + printFilteredAggregators(pnames, true, outputBuffer) + } + } + + // print input plugins + if choice.Contains("inputs", sectionFilters) { + if len(inputFilters) != 0 { + if len(inputFilters) >= 3 && inputFilters[1] != "none" { + outputBuffer.Write([]byte(inputHeader)) + } + printFilteredInputs(inputFilters, false, outputBuffer) + } else { + outputBuffer.Write([]byte(inputHeader)) + printFilteredInputs(inputDefaults, false, outputBuffer) + // Print non-default inputs, commented + var pnames []string + for pname := range inputs.Inputs { + if !choice.Contains(pname, inputDefaults) { + pnames = append(pnames, pname) + } + } + printFilteredInputs(pnames, true, outputBuffer) + } + } +} + +func printFilteredProcessors(processorFilters []string, commented bool, outputBuffer io.Writer) { + // Filter processors + var pnames []string + for pname := range processors.Processors { + if choice.Contains(pname, processorFilters) { + pnames = append(pnames, pname) + } + } + sort.Strings(pnames) + + // Print Outputs + for _, pname := range pnames { + creator := processors.Processors[pname] + output := creator() + printConfig(pname, output, "processors", commented, processors.Deprecations[pname], outputBuffer) + } +} + +func printFilteredAggregators(aggregatorFilters []string, commented bool, outputBuffer io.Writer) { + // Filter outputs + var anames []string + for aname := range aggregators.Aggregators { + if choice.Contains(aname, aggregatorFilters) { + anames = append(anames, aname) + } + } + sort.Strings(anames) + + // Print Outputs + for _, aname := range anames { + creator := aggregators.Aggregators[aname] + output := creator() + printConfig(aname, output, "aggregators", commented, aggregators.Deprecations[aname], outputBuffer) + } +} + +func printFilteredInputs(inputFilters []string, commented bool, outputBuffer io.Writer) { + // Filter inputs + var pnames []string + for pname := range inputs.Inputs { + if choice.Contains(pname, inputFilters) { + pnames = append(pnames, pname) + } + } + sort.Strings(pnames) + + // cache service inputs to print them at the end + servInputs := make(map[string]telegraf.ServiceInput) + // for alphabetical looping: + servInputNames := make([]string, 0, len(pnames)) + + // Print Inputs + for _, pname := range pnames { + // Skip inputs that are registered twice for backward compatibility + switch pname { + case "cisco_telemetry_gnmi", "http_listener", "io", "KNXListener": + continue + } + creator := inputs.Inputs[pname] + input := creator() + + if p, ok := input.(telegraf.ServiceInput); ok { + servInputs[pname] = p + servInputNames = append(servInputNames, pname) + continue + } + + printConfig(pname, input, "inputs", commented, inputs.Deprecations[pname], outputBuffer) + } + + // Print Service Inputs + if len(servInputs) == 0 { + return + } + sort.Strings(servInputNames) + + outputBuffer.Write([]byte(serviceInputHeader)) + for _, name := range servInputNames { + printConfig(name, servInputs[name], "inputs", commented, inputs.Deprecations[name], outputBuffer) + } +} + +func printFilteredOutputs(outputFilters []string, commented bool, outputBuffer io.Writer) { + // Filter outputs + var onames []string + var influxdbV2 string + + for oname := range outputs.Outputs { + if choice.Contains(oname, outputFilters) { + // Make influxdb_v2 the exception and have it be first in the list + // Store it and add it later + if oname == "influxdb_v2" { + influxdbV2 = oname + continue + } + + onames = append(onames, oname) + } + } + sort.Strings(onames) + + if influxdbV2 != "" { + onames = append([]string{influxdbV2}, onames...) + } + + // Print Outputs + for _, oname := range onames { + creator := outputs.Outputs[oname] + output := creator() + printConfig(oname, output, "outputs", commented, outputs.Deprecations[oname], outputBuffer) + } +} + +func printFilteredSecretstores(secretstoreFilters []string, commented bool, outputBuffer io.Writer) { + // Filter secretstores + var snames []string + for sname := range secretstores.SecretStores { + if choice.Contains(sname, secretstoreFilters) { + snames = append(snames, sname) + } + } + sort.Strings(snames) + + // Print SecretStores + for _, sname := range snames { + creator := secretstores.SecretStores[sname] + store := creator("dummy") + printConfig(sname, store, "secretstores", commented, secretstores.Deprecations[sname], outputBuffer) + } +} + +func printFilteredGlobalSections(sectionFilters []string, outputBuffer io.Writer) { + if choice.Contains("global_tags", sectionFilters) { + outputBuffer.Write([]byte(globalTagsConfig)) + } + + if choice.Contains("agent", sectionFilters) { + outputBuffer.Write([]byte(agentConfig)) + } +} + +func printConfig(name string, p telegraf.PluginDescriber, op string, commented bool, di telegraf.DeprecationInfo, outputBuffer io.Writer) { + comment := "" + if commented { + comment = "# " + } + + if di.Since != "" { + removalNote := "" + if di.RemovalIn != "" { + removalNote = " and will be removed in " + di.RemovalIn + } + fmt.Fprintf(outputBuffer, "\n%s## DEPRECATED: The %q plugin is deprecated in version %s%s, %s.", + comment, name, di.Since, removalNote, di.Notice) + } + + sample := p.SampleConfig() + if sample == "" { + fmt.Fprintf(outputBuffer, "\n#[[%s.%s]]", op, name) + fmt.Fprintf(outputBuffer, "\n%s # no configuration\n\n", comment) + } else { + lines := strings.Split(sample, "\n") + outputBuffer.Write([]byte("\n")) + for i, line := range lines { + if i == len(lines)-1 { + outputBuffer.Write([]byte("\n")) + continue + } + outputBuffer.Write([]byte(strings.TrimRight(comment+line, " ") + "\n")) + } + } +} + +// PrintInputConfig prints the config usage of a single input. +func PrintInputConfig(name string, outputBuffer io.Writer) error { + creator, ok := inputs.Inputs[name] + if !ok { + return fmt.Errorf("input %s not found", name) + } + + printConfig(name, creator(), "inputs", false, inputs.Deprecations[name], outputBuffer) + return nil +} + +// PrintOutputConfig prints the config usage of a single output. +func PrintOutputConfig(name string, outputBuffer io.Writer) error { + creator, ok := outputs.Outputs[name] + if !ok { + return fmt.Errorf("output %s not found", name) + } + + printConfig(name, creator(), "outputs", false, outputs.Deprecations[name], outputBuffer) + return nil +} diff --git a/cmd/telegraf/telegraf.go b/cmd/telegraf/telegraf.go new file mode 100644 index 0000000..d41d28b --- /dev/null +++ b/cmd/telegraf/telegraf.go @@ -0,0 +1,493 @@ +package main + +import ( + "context" + "errors" + "fmt" + "log" + "net/http" + "net/url" + "os" + "os/signal" + "strings" + "syscall" + "time" + + "github.com/coreos/go-systemd/v22/daemon" + "github.com/fatih/color" + "github.com/influxdata/tail/watch" + "gopkg.in/tomb.v1" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/agent" + "github.com/influxdata/telegraf/config" + "github.com/influxdata/telegraf/internal" + "github.com/influxdata/telegraf/logger" + "github.com/influxdata/telegraf/plugins/aggregators" + "github.com/influxdata/telegraf/plugins/inputs" + "github.com/influxdata/telegraf/plugins/outputs" + "github.com/influxdata/telegraf/plugins/parsers" + "github.com/influxdata/telegraf/plugins/processors" + "github.com/influxdata/telegraf/plugins/secretstores" +) + +var stop chan struct{} + +type GlobalFlags struct { + config []string + configDir []string + testWait int + configURLRetryAttempts int + configURLWatchInterval time.Duration + watchConfig string + watchInterval time.Duration + pidFile string + plugindDir string + password string + oldEnvBehavior bool + printPluginConfigSource bool + test bool + debug bool + once bool + quiet bool + unprotected bool +} + +type WindowFlags struct { + service string + serviceName string + serviceDisplayName string + serviceRestartDelay string + serviceAutoRestart bool + console bool +} + +type App interface { + Init(<-chan error, Filters, GlobalFlags, WindowFlags) + Run() error + + // Secret store commands + ListSecretStores() ([]string, error) + GetSecretStore(string) (telegraf.SecretStore, error) +} + +type Telegraf struct { + pprofErr <-chan error + + inputFilters []string + outputFilters []string + configFiles []string + secretstoreFilters []string + + cfg *config.Config + + GlobalFlags + WindowFlags +} + +func (t *Telegraf) Init(pprofErr <-chan error, f Filters, g GlobalFlags, w WindowFlags) { + t.pprofErr = pprofErr + t.inputFilters = f.input + t.outputFilters = f.output + t.secretstoreFilters = f.secretstore + t.GlobalFlags = g + t.WindowFlags = w + + // Disable secret protection before performing any other operation + if g.unprotected { + log.Println("W! Running without secret protection!") + config.DisableSecretProtection() + } + + // Set global password + if g.password != "" { + config.Password = config.NewSecret([]byte(g.password)) + } + + // Set environment replacement behavior + config.OldEnvVarReplacement = g.oldEnvBehavior + + config.PrintPluginConfigSource = g.printPluginConfigSource +} + +func (t *Telegraf) ListSecretStores() ([]string, error) { + c, err := t.loadConfiguration() + if err != nil { + return nil, err + } + + ids := make([]string, 0, len(c.SecretStores)) + for k := range c.SecretStores { + ids = append(ids, k) + } + return ids, nil +} + +func (t *Telegraf) GetSecretStore(id string) (telegraf.SecretStore, error) { + t.quiet = true + c, err := t.loadConfiguration() + if err != nil { + return nil, err + } + + store, found := c.SecretStores[id] + if !found { + return nil, errors.New("unknown secret store") + } + + return store, nil +} + +func (t *Telegraf) reloadLoop() error { + reloadConfig := false + reload := make(chan bool, 1) + reload <- true + for <-reload { + reload <- false + ctx, cancel := context.WithCancel(context.Background()) + + signals := make(chan os.Signal, 1) + signal.Notify(signals, os.Interrupt, syscall.SIGHUP, + syscall.SIGTERM, syscall.SIGINT) + if t.watchConfig != "" { + for _, fConfig := range t.configFiles { + if isURL(fConfig) { + continue + } + + if _, err := os.Stat(fConfig); err != nil { + log.Printf("W! Cannot watch config %s: %s", fConfig, err) + } else { + go t.watchLocalConfig(ctx, signals, fConfig) + } + } + for _, fConfigDirectory := range t.configDir { + if _, err := os.Stat(fConfigDirectory); err != nil { + log.Printf("W! Cannot watch config directory %s: %s", fConfigDirectory, err) + } else { + go t.watchLocalConfig(ctx, signals, fConfigDirectory) + } + } + } + if t.configURLWatchInterval > 0 { + remoteConfigs := make([]string, 0) + for _, fConfig := range t.configFiles { + if isURL(fConfig) { + remoteConfigs = append(remoteConfigs, fConfig) + } + } + if len(remoteConfigs) > 0 { + go t.watchRemoteConfigs(ctx, signals, t.configURLWatchInterval, remoteConfigs) + } + } + go func() { + select { + case sig := <-signals: + if sig == syscall.SIGHUP { + log.Println("I! Reloading Telegraf config") + // May need to update the list of known config files + // if a delete or create occured. That way on the reload + // we ensure we watch the correct files. + if err := t.getConfigFiles(); err != nil { + log.Println("E! Error loading config files: ", err) + } + <-reload + reload <- true + } + cancel() + case err := <-t.pprofErr: + log.Printf("E! pprof server failed: %v", err) + cancel() + case <-stop: + cancel() + } + }() + + err := t.runAgent(ctx, reloadConfig) + if err != nil && !errors.Is(err, context.Canceled) { + return fmt.Errorf("[telegraf] Error running agent: %w", err) + } + reloadConfig = true + } + + return nil +} + +func (t *Telegraf) watchLocalConfig(ctx context.Context, signals chan os.Signal, fConfig string) { + var mytomb tomb.Tomb + var watcher watch.FileWatcher + if t.watchConfig == "poll" { + if t.watchInterval > 0 { + watcher = watch.NewPollingFileWatcherWithDuration(fConfig, t.watchInterval) + } else { + watcher = watch.NewPollingFileWatcher(fConfig) + } + } else { + watcher = watch.NewInotifyFileWatcher(fConfig) + } + changes, err := watcher.ChangeEvents(&mytomb, 0) + if err != nil { + log.Printf("E! Error watching config file/directory %q: %s\n", fConfig, err) + return + } + log.Printf("I! Config watcher started for %s\n", fConfig) + select { + case <-ctx.Done(): + mytomb.Done() + return + case <-changes.Modified: + log.Printf("I! Config file/directory %q modified\n", fConfig) + case <-changes.Deleted: + // deleted can mean moved. wait a bit a check existence + <-time.After(time.Second) + if _, err := os.Stat(fConfig); err == nil { + log.Printf("I! Config file/directory %q overwritten\n", fConfig) + } else { + log.Printf("W! Config file/directory %q deleted\n", fConfig) + } + case <-changes.Truncated: + log.Printf("I! Config file/directory %q truncated\n", fConfig) + case <-changes.Created: + log.Printf("I! Config directory %q has new file(s)\n", fConfig) + case <-mytomb.Dying(): + log.Printf("I! Config watcher %q ended\n", fConfig) + return + } + mytomb.Done() + signals <- syscall.SIGHUP +} + +func (*Telegraf) watchRemoteConfigs(ctx context.Context, signals chan os.Signal, interval time.Duration, remoteConfigs []string) { + configs := strings.Join(remoteConfigs, ", ") + log.Printf("I! Remote config watcher started for: %s\n", configs) + + ticker := time.NewTicker(interval) + defer ticker.Stop() + + lastModified := make(map[string]string, len(remoteConfigs)) + for { + select { + case <-ctx.Done(): + return + case <-signals: + return + case <-ticker.C: + for _, configURL := range remoteConfigs { + req, err := http.NewRequest("HEAD", configURL, nil) + if err != nil { + log.Printf("W! Creating request for fetching config from %q failed: %v\n", configURL, err) + continue + } + + if v, exists := os.LookupEnv("INFLUX_TOKEN"); exists { + req.Header.Add("Authorization", "Token "+v) + } + req.Header.Set("User-Agent", internal.ProductToken()) + + resp, err := http.DefaultClient.Do(req) + if err != nil { + log.Printf("W! Fetching config from %q failed: %v\n", configURL, err) + continue + } + resp.Body.Close() + + modified := resp.Header.Get("Last-Modified") + if modified == "" { + log.Printf("E! Last-Modified header not found, stopping the watcher for %s\n", configURL) + delete(lastModified, configURL) + } + + if lastModified[configURL] == "" { + lastModified[configURL] = modified + } else if lastModified[configURL] != modified { + log.Printf("I! Remote config modified: %s\n", configURL) + signals <- syscall.SIGHUP + return + } + } + } + } +} + +func (t *Telegraf) loadConfiguration() (*config.Config, error) { + // If no other options are specified, load the config file and run. + c := config.NewConfig() + c.Agent.Quiet = t.quiet + c.Agent.ConfigURLRetryAttempts = t.configURLRetryAttempts + c.OutputFilters = t.outputFilters + c.InputFilters = t.inputFilters + c.SecretStoreFilters = t.secretstoreFilters + + if err := t.getConfigFiles(); err != nil { + return c, err + } + if err := c.LoadAll(t.configFiles...); err != nil { + return c, err + } + return c, nil +} + +func (t *Telegraf) getConfigFiles() error { + var configFiles []string + + configFiles = append(configFiles, t.config...) + for _, fConfigDirectory := range t.configDir { + files, err := config.WalkDirectory(fConfigDirectory) + if err != nil { + return err + } + configFiles = append(configFiles, files...) + } + + // load default config paths if none are found + if len(configFiles) == 0 { + defaultFiles, err := config.GetDefaultConfigPath() + if err != nil { + return fmt.Errorf("unable to load default config paths: %w", err) + } + configFiles = append(configFiles, defaultFiles...) + } + + t.configFiles = configFiles + return nil +} + +func (t *Telegraf) runAgent(ctx context.Context, reloadConfig bool) error { + c := t.cfg + var err error + if reloadConfig { + if c, err = t.loadConfiguration(); err != nil { + return err + } + } + + if !t.test && t.testWait == 0 && len(c.Outputs) == 0 { + return errors.New("no outputs found, probably invalid config file provided") + } + if t.plugindDir == "" && len(c.Inputs) == 0 { + return errors.New("no inputs found, probably invalid config file provided") + } + + if int64(c.Agent.Interval) <= 0 { + return fmt.Errorf("agent interval must be positive, found %v", c.Agent.Interval) + } + + if int64(c.Agent.FlushInterval) <= 0 { + return fmt.Errorf("agent flush_interval must be positive; found %v", c.Agent.Interval) + } + + // Setup logging as configured. + logConfig := &logger.Config{ + Debug: c.Agent.Debug || t.debug, + Quiet: c.Agent.Quiet || t.quiet, + LogTarget: c.Agent.LogTarget, + LogFormat: c.Agent.LogFormat, + Logfile: c.Agent.Logfile, + StructuredLogMessageKey: c.Agent.StructuredLogMessageKey, + RotationInterval: time.Duration(c.Agent.LogfileRotationInterval), + RotationMaxSize: int64(c.Agent.LogfileRotationMaxSize), + RotationMaxArchives: c.Agent.LogfileRotationMaxArchives, + LogWithTimezone: c.Agent.LogWithTimezone, + } + + if err := logger.SetupLogging(logConfig); err != nil { + return err + } + + log.Printf("I! Starting Telegraf %s%s brought to you by InfluxData the makers of InfluxDB", internal.Version, internal.Customized) + log.Printf("I! Available plugins: %d inputs, %d aggregators, %d processors, %d parsers, %d outputs, %d secret-stores", + len(inputs.Inputs), + len(aggregators.Aggregators), + len(processors.Processors), + len(parsers.Parsers), + len(outputs.Outputs), + len(secretstores.SecretStores), + ) + log.Printf("I! Loaded inputs: %s\n%s", strings.Join(c.InputNames(), " "), c.InputNamesWithSources()) + log.Printf("I! Loaded aggregators: %s\n%s", strings.Join(c.AggregatorNames(), " "), c.AggregatorNamesWithSources()) + log.Printf("I! Loaded processors: %s\n%s", strings.Join(c.ProcessorNames(), " "), c.ProcessorNamesWithSources()) + log.Printf("I! Loaded secretstores: %s\n%s", strings.Join(c.SecretstoreNames(), " "), c.SecretstoreNamesWithSources()) + if !t.once && (t.test || t.testWait != 0) { + log.Print("W! " + color.RedString("Outputs are not used in testing mode!")) + } else { + log.Printf("I! Loaded outputs: %s\n%s", strings.Join(c.OutputNames(), " "), c.OutputNamesWithSources()) + } + log.Printf("I! Tags enabled: %s", c.ListTags()) + + if count, found := c.Deprecations["inputs"]; found && (count[0] > 0 || count[1] > 0) { + log.Printf("W! Deprecated inputs: %d and %d options", count[0], count[1]) + } + if count, found := c.Deprecations["aggregators"]; found && (count[0] > 0 || count[1] > 0) { + log.Printf("W! Deprecated aggregators: %d and %d options", count[0], count[1]) + } + if count, found := c.Deprecations["processors"]; found && (count[0] > 0 || count[1] > 0) { + log.Printf("W! Deprecated processors: %d and %d options", count[0], count[1]) + } + if count, found := c.Deprecations["outputs"]; found && (count[0] > 0 || count[1] > 0) { + log.Printf("W! Deprecated outputs: %d and %d options", count[0], count[1]) + } + if count, found := c.Deprecations["secretstores"]; found && (count[0] > 0 || count[1] > 0) { + log.Printf("W! Deprecated secretstores: %d and %d options", count[0], count[1]) + } + + // Compute the amount of locked memory needed for the secrets + if !t.GlobalFlags.unprotected { + required := 3 * c.NumberSecrets * uint64(os.Getpagesize()) + available := getLockedMemoryLimit() + if required > available { + required /= 1024 + available /= 1024 + log.Printf("I! Found %d secrets...", c.NumberSecrets) + msg := fmt.Sprintf("Insufficient lockable memory %dkb when %dkb is required.", available, required) + msg += " Please increase the limit for Telegraf in your Operating System!" + log.Print("W! " + color.RedString(msg)) + } + } + ag := agent.NewAgent(c) + + // Notify systemd that telegraf is ready + // SdNotify() only tries to notify if the NOTIFY_SOCKET environment is set, so it's safe to call when systemd isn't present. + // Ignore the return values here because they're not valid for platforms that don't use systemd. + // For platforms that use systemd, telegraf doesn't log if the notification failed. + //nolint:errcheck // see above + daemon.SdNotify(false, daemon.SdNotifyReady) + + if t.once { + wait := time.Duration(t.testWait) * time.Second + return ag.Once(ctx, wait) + } + + if t.test || t.testWait != 0 { + wait := time.Duration(t.testWait) * time.Second + return ag.Test(ctx, wait) + } + + if t.pidFile != "" { + f, err := os.OpenFile(t.pidFile, os.O_CREATE|os.O_WRONLY, 0640) + if err != nil { + log.Printf("E! Unable to create pidfile: %s", err) + } else { + fmt.Fprintf(f, "%d\n", os.Getpid()) + + err = f.Close() + if err != nil { + return err + } + + defer func() { + err := os.Remove(t.pidFile) + if err != nil { + log.Printf("E! Unable to remove pidfile: %s", err) + } + }() + } + } + + return ag.Run(ctx) +} + +// isURL checks if string is valid url +func isURL(str string) bool { + u, err := url.Parse(str) + return err == nil && u.Scheme != "" && u.Host != "" +} diff --git a/cmd/telegraf/telegraf_posix.go b/cmd/telegraf/telegraf_posix.go new file mode 100644 index 0000000..3a6c43d --- /dev/null +++ b/cmd/telegraf/telegraf_posix.go @@ -0,0 +1,42 @@ +//go:build !windows + +package main + +import ( + "log" + "runtime" + "syscall" +) + +func (t *Telegraf) Run() error { + stop = make(chan struct{}) + defer close(stop) + + cfg, err := t.loadConfiguration() + if err != nil { + return err + } + t.cfg = cfg + return t.reloadLoop() +} + +func getLockedMemoryLimit() uint64 { + var rLimitMemlock int + + switch runtime.GOOS { + case "dragonfly", "freebsd", "netbsd", "openbsd": + // From https://cgit.freebsd.org/src/tree/sys/sys/resource.h#n107 + rLimitMemlock = 6 + default: + // From https://elixir.bootlin.com/linux/latest/source/include/uapi/asm-generic/resource.h#L35 + rLimitMemlock = 8 + } + + var limit syscall.Rlimit + if err := syscall.Getrlimit(rLimitMemlock, &limit); err != nil { + log.Printf("E! Cannot get limit for locked memory: %v", err) + return 0 + } + //nolint:unconvert // required for e.g. FreeBSD that has the field as int64 + return uint64(limit.Max) +} diff --git a/cmd/telegraf/telegraf_windows.go b/cmd/telegraf/telegraf_windows.go new file mode 100644 index 0000000..54d5c61 --- /dev/null +++ b/cmd/telegraf/telegraf_windows.go @@ -0,0 +1,408 @@ +//go:build windows + +//go:generate ../../scripts/windows-gen-syso.sh $GOARCH + +package main + +import ( + "fmt" + "log" + "os" + "path/filepath" + "syscall" + "time" + + "golang.org/x/sys/windows" + "golang.org/x/sys/windows/svc" + "golang.org/x/sys/windows/svc/eventlog" + "golang.org/x/sys/windows/svc/mgr" +) + +func getLockedMemoryLimit() uint64 { + handle := windows.CurrentProcess() + + var low, high uintptr + var flag uint32 + windows.GetProcessWorkingSetSizeEx(handle, &low, &high, &flag) + + return uint64(high) +} + +func (t *Telegraf) Run() error { + // Process the service commands + if t.service != "" { + fmt.Println("The use of --service is deprecated, please use the 'service' command instead!") + switch t.service { + case "install": + cfg := &serviceConfig{ + displayName: t.serviceDisplayName, + restartDelay: t.serviceRestartDelay, + autoRestart: t.serviceAutoRestart, + configs: t.config, + configDirs: t.configDir, + watchConfig: t.watchConfig, + } + if err := installService(t.serviceName, cfg); err != nil { + return err + } + fmt.Printf("Successfully installed service %q\n", t.serviceName) + case "uninstall": + if err := uninstallService(t.serviceName); err != nil { + return err + } + fmt.Printf("Successfully uninstalled service %q\n", t.serviceName) + case "start": + if err := startService(t.serviceName); err != nil { + return err + } + fmt.Printf("Successfully started service %q\n", t.serviceName) + case "stop": + if err := stopService(t.serviceName); err != nil { + return err + } + fmt.Printf("Successfully stopped service %q\n", t.serviceName) + case "status": + status, err := queryService(t.serviceName) + if err != nil { + return err + } + fmt.Printf("Service %q is in %q state\n", t.serviceName, status) + default: + return fmt.Errorf("invalid service command %q", t.service) + } + return nil + } + + // Determine if Telegraf is started as a Windows service. + isWinService, err := svc.IsWindowsService() + if err != nil { + return fmt.Errorf("cannot determine if run as Windows service: %w", err) + } + if !t.console && isWinService { + return svc.Run(t.serviceName, t) + } + + // Load the configuration file(s) + cfg, err := t.loadConfiguration() + if err != nil { + return err + } + t.cfg = cfg + + stop = make(chan struct{}) + defer close(stop) + return t.reloadLoop() +} + +// Handler for the Windows service framework +func (t *Telegraf) Execute(_ []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (bool, uint32) { + // Mark the status as startup pending until we are fully started + const accepted = svc.AcceptStop | svc.AcceptShutdown + changes <- svc.Status{State: svc.StartPending} + defer func() { + changes <- svc.Status{State: svc.Stopped} + }() + + // Create a eventlog logger for all service related things + svclog, err := eventlog.Open(t.serviceName) + if err != nil { + log.Printf("E! Initializing the service logger failed: %s", err) + return true, 1 + } + defer svclog.Close() + + // Load the configuration file(s) + cfg, err := t.loadConfiguration() + if err != nil { + if lerr := svclog.Error(100, err.Error()); lerr != nil { + log.Printf("E! Logging error %q failed: %s", err, lerr) + } + return true, 2 + } + t.cfg = cfg + + // Actually start the processing loop in the background to be able to + // react to service change requests + loopErr := make(chan error) + stop = make(chan struct{}) + defer close(loopErr) + defer close(stop) + go func() { + loopErr <- t.reloadLoop() + }() + changes <- svc.Status{State: svc.Running, Accepts: accepted} + + for { + select { + case err := <-loopErr: + if err != nil { + if lerr := svclog.Error(100, err.Error()); lerr != nil { + log.Printf("E! Logging error %q failed: %s", err, lerr) + } + return true, 3 + } + return false, 0 + case c := <-r: + switch c.Cmd { + case svc.Interrogate: + changes <- c.CurrentStatus + // Testing deadlock from https://code.google.com/p/winsvc/issues/detail?id=4 + time.Sleep(100 * time.Millisecond) + changes <- c.CurrentStatus + case svc.Stop, svc.Shutdown: + changes <- svc.Status{State: svc.StopPending} + var empty struct{} + stop <- empty // signal reloadLoop to finish (context cancel) + default: + msg := fmt.Sprintf("Unexpected control request #%d", c) + if lerr := svclog.Error(100, msg); lerr != nil { + log.Printf("E! Logging error %q failed: %s", msg, lerr) + } + } + } + } +} + +type serviceConfig struct { + displayName string + restartDelay string + autoRestart bool + + // Telegraf parameters + configs []string + configDirs []string + watchConfig string +} + +func installService(name string, cfg *serviceConfig) error { + // Determine the executable to use in the service + executable, err := os.Executable() + if err != nil { + return fmt.Errorf("determining executable failed: %w", err) + } + + // Determine the program files directory name + programFiles := os.Getenv("ProgramFiles") + if programFiles == "" { // Should never happen + programFiles = "C:\\Program Files" + } + + // Collect the command line arguments + args := make([]string, 0, 2*(len(cfg.configs)+len(cfg.configDirs))+2) + for _, fn := range cfg.configs { + args = append(args, "--config", fn) + } + for _, dn := range cfg.configDirs { + args = append(args, "--config-directory", dn) + } + if len(args) == 0 { + args = append(args, "--config", filepath.Join(programFiles, "Telegraf", "telegraf.conf")) + } + if cfg.watchConfig != "" { + args = append(args, "--watch-config", cfg.watchConfig) + } + // Pass the service name to the command line, to have a custom name when relaunching as a service + args = append(args, "--service-name", name) + + // Create a configuration for the service + svccfg := mgr.Config{ + DisplayName: cfg.displayName, + Description: "Collects, processes and publishes data using a series of plugins.", + StartType: mgr.StartAutomatic, + ServiceType: windows.SERVICE_WIN32_OWN_PROCESS, + } + + // Connect to the service manager and try to install the service if it + // doesn't exist. Fail on existing service and stop installation. + svcmgr, err := mgr.Connect() + if err != nil { + return fmt.Errorf("connecting to service manager failed: %w", err) + } + defer svcmgr.Disconnect() + + if service, err := svcmgr.OpenService(name); err == nil { + service.Close() + return fmt.Errorf("service %q is already installed", name) + } + + service, err := svcmgr.CreateService(name, executable, svccfg, args...) + if err != nil { + return fmt.Errorf("creating service failed: %w", err) + } + defer service.Close() + + // Set the recovery strategy to restart with a fixed period of 10 seconds + // and the user specified delay if requested + if cfg.autoRestart { + delay, err := time.ParseDuration(cfg.restartDelay) + if err != nil { + return fmt.Errorf("cannot parse restart delay %q: %w", cfg.restartDelay, err) + } + recovery := []mgr.RecoveryAction{{Type: mgr.ServiceRestart, Delay: delay}} + if err := service.SetRecoveryActions(recovery, 10); err != nil { + return err + } + } + + // Register the event as a source of eventlog events + events := uint32(eventlog.Error | eventlog.Warning | eventlog.Info) + if err := eventlog.InstallAsEventCreate(name, events); err != nil { + //nolint:errcheck // Try to remove the service on best effort basis as we cannot handle any error here + service.Delete() + return fmt.Errorf("setting up eventlog source failed: %w", err) + } + + return nil +} + +func uninstallService(name string) error { + // Connect to the service manager and try to open the service. In case the + // service is not installed, return with the corresponding error. + svcmgr, err := mgr.Connect() + if err != nil { + return fmt.Errorf("connecting to service manager failed: %w", err) + } + defer svcmgr.Disconnect() + + service, err := svcmgr.OpenService(name) + if err != nil { + return fmt.Errorf("opening service failed: %w", err) + } + defer service.Close() + + // Uninstall the service and remove the eventlog source + if err := service.Delete(); err != nil { + return fmt.Errorf("uninstalling service failed: %w", err) + } + + if err := eventlog.Remove(name); err != nil { + return fmt.Errorf("removing eventlog source failed: %w", err) + } + + return nil +} + +func startService(name string) error { + nameUTF16, err := syscall.UTF16PtrFromString(name) + if err != nil { + return fmt.Errorf("conversion of service name %q to UTF16 failed: %w", name, err) + } + + // Open the service manager and service with the least privileges required to start the service + mgrhandle, err := windows.OpenSCManager(nil, nil, windows.SC_MANAGER_CONNECT|windows.SC_MANAGER_ENUMERATE_SERVICE) + if err != nil { + return fmt.Errorf("opening service manager failed: %w", err) + } + defer windows.CloseServiceHandle(mgrhandle) + + svchandle, err := windows.OpenService(mgrhandle, nameUTF16, windows.SERVICE_QUERY_STATUS|windows.SERVICE_START) + if err != nil { + return fmt.Errorf("opening service failed: %w", err) + } + service := &mgr.Service{Handle: svchandle, Name: name} + defer service.Close() + + // Check if the service is actually stopped + status, err := service.Query() + if err != nil { + return fmt.Errorf("querying service state failed: %w", err) + } + if status.State != svc.Stopped { + return fmt.Errorf("service is not stopped but in state %q", stateDescription(status.State)) + } + + return service.Start() +} + +func stopService(name string) error { + nameUTF16, err := syscall.UTF16PtrFromString(name) + if err != nil { + return fmt.Errorf("conversion of service name %q to UTF16 failed: %w", name, err) + } + + // Open the service manager and service with the least privileges required to start the service + mgrhandle, err := windows.OpenSCManager(nil, nil, windows.SC_MANAGER_CONNECT|windows.SC_MANAGER_ENUMERATE_SERVICE) + if err != nil { + return fmt.Errorf("opening service manager failed: %w", err) + } + defer windows.CloseServiceHandle(mgrhandle) + + svchandle, err := windows.OpenService(mgrhandle, nameUTF16, windows.SERVICE_QUERY_STATUS|windows.SERVICE_STOP) + if err != nil { + return fmt.Errorf("opening service failed: %w", err) + } + service := &mgr.Service{Handle: svchandle, Name: name} + defer service.Close() + + // Stop the service and wait for it to finish + status, err := service.Control(svc.Stop) + if err != nil { + return fmt.Errorf("stopping service failed: %w", err) + } + for status.State != svc.Stopped { + // Wait for the hinted time, but clip it to prevent stalling operation + wait := time.Duration(status.WaitHint) * time.Millisecond + if wait < 100*time.Millisecond { + wait = 100 * time.Millisecond + } else if wait > 10*time.Second { + wait = 10 * time.Second + } + time.Sleep(wait) + + status, err = service.Query() + if err != nil { + return fmt.Errorf("querying service state failed: %w", err) + } + } + + return nil +} + +func queryService(name string) (string, error) { + nameUTF16, err := syscall.UTF16PtrFromString(name) + if err != nil { + return "", fmt.Errorf("conversion of service name %q to UTF16 failed: %w", name, err) + } + + // Open the service manager and service with the least privileges required to start the service + mgrhandle, err := windows.OpenSCManager(nil, nil, windows.SC_MANAGER_CONNECT|windows.SC_MANAGER_ENUMERATE_SERVICE) + if err != nil { + return "", fmt.Errorf("opening service manager failed: %w", err) + } + defer windows.CloseServiceHandle(mgrhandle) + + svchandle, err := windows.OpenService(mgrhandle, nameUTF16, windows.SERVICE_QUERY_STATUS) + if err != nil { + return "", fmt.Errorf("opening service failed: %w", err) + } + service := &mgr.Service{Handle: svchandle, Name: name} + defer service.Close() + + // Query the service state and report it to the user + status, err := service.Query() + if err != nil { + return "", fmt.Errorf("querying service state failed: %w", err) + } + + return stateDescription(status.State), nil +} + +func stateDescription(state svc.State) string { + switch state { + case svc.Stopped: + return "stopped" + case svc.StartPending: + return "start pending" + case svc.StopPending: + return "stop pending" + case svc.Running: + return "running" + case svc.ContinuePending: + return "continue pending" + case svc.PausePending: + return "pause pending" + case svc.Paused: + return "paused" + } + return fmt.Sprintf("unknown %v", state) +} diff --git a/config/README.md b/config/README.md new file mode 120000 index 0000000..5455122 --- /dev/null +++ b/config/README.md @@ -0,0 +1 @@ +../docs/CONFIGURATION.md \ No newline at end of file diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..baabf64 --- /dev/null +++ b/config/config.go @@ -0,0 +1,1924 @@ +package config + +import ( + "bytes" + "crypto/tls" + "errors" + "fmt" + "io" + "log" + "net/http" + "net/url" + "os" + "path/filepath" + "reflect" + "regexp" + "runtime" + "sort" + "strconv" + "strings" + "sync" + "time" + + "github.com/coreos/go-semver/semver" + "github.com/influxdata/toml" + "github.com/influxdata/toml/ast" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/internal" + logging "github.com/influxdata/telegraf/logger" + "github.com/influxdata/telegraf/models" + "github.com/influxdata/telegraf/persister" + "github.com/influxdata/telegraf/plugins/aggregators" + "github.com/influxdata/telegraf/plugins/inputs" + "github.com/influxdata/telegraf/plugins/outputs" + "github.com/influxdata/telegraf/plugins/parsers" + "github.com/influxdata/telegraf/plugins/parsers/csv" + "github.com/influxdata/telegraf/plugins/processors" + "github.com/influxdata/telegraf/plugins/secretstores" + "github.com/influxdata/telegraf/plugins/serializers" +) + +var ( + httpLoadConfigRetryInterval = 10 * time.Second + + // fetchURLRe is a regex to determine whether the requested file should + // be fetched from a remote or read from the filesystem. + fetchURLRe = regexp.MustCompile(`^\w+://`) + + // oldVarRe is a regex to reproduce pre v1.27.0 environment variable + // replacement behavior + oldVarRe = regexp.MustCompile(`\$(?i:(?P[_a-z][_a-z0-9]*)|{(?:(?P[_a-z][_a-z0-9]*(?::?[-+?](.*))?)}|(?P)))`) + // OldEnvVarReplacement is a switch to allow going back to pre v1.27.0 + // environment variable replacement behavior + OldEnvVarReplacement = false + + // PrintPluginConfigSource is a switch to enable printing of plugin sources + PrintPluginConfigSource = false + + // Password specified via command-line + Password Secret + + // telegrafVersion contains the parsed semantic Telegraf version + telegrafVersion *semver.Version = semver.New("0.0.0-unknown") +) + +const EmptySourcePath string = "" + +// Config specifies the URL/user/password for the database that telegraf +// will be logging to, as well as all the plugins that the user has +// specified +type Config struct { + toml *toml.Config + errs []error // config load errors. + UnusedFields map[string]bool + unusedFieldsMutex *sync.Mutex + + Tags map[string]string + InputFilters []string + OutputFilters []string + SecretStoreFilters []string + + SecretStores map[string]telegraf.SecretStore + secretStoreSource map[string][]string + + Agent *AgentConfig + Inputs []*models.RunningInput + Outputs []*models.RunningOutput + Aggregators []*models.RunningAggregator + // Processors have a slice wrapper type because they need to be sorted + Processors models.RunningProcessors + AggProcessors models.RunningProcessors + fileProcessors OrderedPlugins + fileAggProcessors OrderedPlugins + + // Parsers are created by their inputs during gather. Config doesn't keep track of them + // like the other plugins because they need to be garbage collected (See issue #11809) + + Deprecations map[string][]int64 + + Persister *persister.Persister + + NumberSecrets uint64 + + seenAgentTable bool + seenAgentTableOnce sync.Once +} + +// Ordered plugins used to keep the order in which they appear in a file +type OrderedPlugin struct { + Line int + plugin any +} +type OrderedPlugins []*OrderedPlugin + +func (op OrderedPlugins) Len() int { return len(op) } +func (op OrderedPlugins) Swap(i, j int) { op[i], op[j] = op[j], op[i] } +func (op OrderedPlugins) Less(i, j int) bool { return op[i].Line < op[j].Line } + +// NewConfig creates a new struct to hold the Telegraf config. +// For historical reasons, It holds the actual instances of the running plugins +// once the configuration is parsed. +func NewConfig() *Config { + c := &Config{ + UnusedFields: make(map[string]bool), + unusedFieldsMutex: &sync.Mutex{}, + + // Agent defaults: + Agent: &AgentConfig{ + Interval: Duration(10 * time.Second), + RoundInterval: true, + FlushInterval: Duration(10 * time.Second), + LogfileRotationMaxArchives: 5, + }, + + Tags: make(map[string]string), + Inputs: make([]*models.RunningInput, 0), + Outputs: make([]*models.RunningOutput, 0), + Processors: make([]*models.RunningProcessor, 0), + AggProcessors: make([]*models.RunningProcessor, 0), + SecretStores: make(map[string]telegraf.SecretStore), + secretStoreSource: make(map[string][]string), + fileProcessors: make([]*OrderedPlugin, 0), + fileAggProcessors: make([]*OrderedPlugin, 0), + InputFilters: make([]string, 0), + OutputFilters: make([]string, 0), + SecretStoreFilters: make([]string, 0), + Deprecations: make(map[string][]int64), + } + + // Handle unknown version + if internal.Version != "" && internal.Version != "unknown" { + telegrafVersion = semver.New(internal.Version) + } + + tomlCfg := &toml.Config{ + NormFieldName: toml.DefaultConfig.NormFieldName, + FieldToKey: toml.DefaultConfig.FieldToKey, + MissingField: c.missingTomlField, + } + c.toml = tomlCfg + + return c +} + +// AgentConfig defines configuration that will be used by the Telegraf agent +type AgentConfig struct { + // Interval at which to gather information + Interval Duration + + // RoundInterval rounds collection interval to 'interval'. + // ie, if Interval=10s then always collect on :00, :10, :20, etc. + RoundInterval bool + + // Collected metrics are rounded to the precision specified. Precision is + // specified as an interval with an integer + unit (e.g. 0s, 10ms, 2us, 4s). + // Valid time units are "ns", "us" (or "µs"), "ms", "s". + // + // By default, or when set to "0s", precision will be set to the same + // timestamp order as the collection interval, with the maximum being 1s: + // ie, when interval = "10s", precision will be "1s" + // when interval = "250ms", precision will be "1ms" + // + // Precision will NOT be used for service inputs. It is up to each individual + // service input to set the timestamp at the appropriate precision. + Precision Duration + + // CollectionJitter is used to jitter the collection by a random amount. + // Each plugin will sleep for a random time within jitter before collecting. + // This can be used to avoid many plugins querying things like sysfs at the + // same time, which can have a measurable effect on the system. + CollectionJitter Duration + + // CollectionOffset is used to shift the collection by the given amount. + // This can be used to avoid many plugins querying constraint devices + // at the same time by manually scheduling them in time. + CollectionOffset Duration + + // FlushInterval is the Interval at which to flush data + FlushInterval Duration + + // FlushJitter Jitters the flush interval by a random amount. + // This is primarily to avoid large write spikes for users running a large + // number of telegraf instances. + // ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s + FlushJitter Duration + + // MetricBatchSize is the maximum number of metrics that is written to an + // output plugin in one call. + MetricBatchSize int + + // MetricBufferLimit is the max number of metrics that each output plugin + // will cache. The buffer is cleared when a successful write occurs. When + // full, the oldest metrics will be overwritten. This number should be a + // multiple of MetricBatchSize. Due to current implementation, this could + // not be less than 2 times MetricBatchSize. + MetricBufferLimit int + + // FlushBufferWhenFull tells Telegraf to flush the metric buffer whenever + // it fills up, regardless of FlushInterval. Setting this option to true + // does _not_ deactivate FlushInterval. + FlushBufferWhenFull bool `toml:"flush_buffer_when_full" deprecated:"0.13.0;1.35.0;option is ignored"` + + // TODO(cam): Remove UTC and parameter, they are no longer + // valid for the agent config. Leaving them here for now for backwards- + // compatibility + UTC bool `toml:"utc" deprecated:"1.0.0;1.35.0;option is ignored"` + + // Debug is the option for running in debug mode + Debug bool `toml:"debug"` + + // Quiet is the option for running in quiet mode + Quiet bool `toml:"quiet"` + + // Log target controls the destination for logs and can be one of "file", + // "stderr" or, on Windows, "eventlog". When set to "file", the output file + // is determined by the "logfile" setting + LogTarget string `toml:"logtarget" deprecated:"1.32.0;1.40.0;use 'logformat' and 'logfile' instead"` + + // Log format controls the way messages are logged and can be one of "text", + // "structured" or, on Windows, "eventlog". + LogFormat string `toml:"logformat"` + + // Name of the file to be logged to or stderr if empty. Ignored for "eventlog" format. + Logfile string `toml:"logfile"` + + // Message key for structured logs, to override the default of "msg". + // Ignored if "logformat" is not "structured". + StructuredLogMessageKey string `toml:"structured_log_message_key"` + + // The file will be rotated after the time interval specified. When set + // to 0 no time based rotation is performed. + LogfileRotationInterval Duration `toml:"logfile_rotation_interval"` + + // The logfile will be rotated when it becomes larger than the specified + // size. When set to 0 no size based rotation is performed. + LogfileRotationMaxSize Size `toml:"logfile_rotation_max_size"` + + // Maximum number of rotated archives to keep, any older logs are deleted. + // If set to -1, no archives are removed. + LogfileRotationMaxArchives int `toml:"logfile_rotation_max_archives"` + + // Pick a timezone to use when logging or type 'local' for local time. + LogWithTimezone string `toml:"log_with_timezone"` + + Hostname string + OmitHostname bool + + // Method for translating SNMP objects. 'netsnmp' to call external programs, + // 'gosmi' to use the built-in library. + SnmpTranslator string `toml:"snmp_translator"` + + // Name of the file to load the state of plugins from and store the state to. + // If uncommented and not empty, this file will be used to save the state of + // stateful plugins on termination of Telegraf. If the file exists on start, + // the state in the file will be restored for the plugins. + Statefile string `toml:"statefile"` + + // Flag to always keep tags explicitly defined in the plugin itself and + // ensure those tags always pass filtering. + AlwaysIncludeLocalTags bool `toml:"always_include_local_tags"` + + // Flag to always keep tags explicitly defined in the global tags section + // and ensure those tags always pass filtering. + AlwaysIncludeGlobalTags bool `toml:"always_include_global_tags"` + + // Flag to skip running processors after aggregators + // By default, processors are run a second time after aggregators. Changing + // this setting to true will skip the second run of processors. + SkipProcessorsAfterAggregators *bool `toml:"skip_processors_after_aggregators"` + + // Number of attempts to obtain a remote configuration via a URL during + // startup. Set to -1 for unlimited attempts. + ConfigURLRetryAttempts int `toml:"config_url_retry_attempts"` + + // BufferStrategy is the metric buffer type to use for a given output plugin. + // Supported types currently are "memory" and "disk". + BufferStrategy string `toml:"buffer_strategy"` + + // BufferDirectory is the directory to store buffer files for serialized + // to disk metrics when using the "disk" buffer strategy. + BufferDirectory string `toml:"buffer_directory"` +} + +// InputNames returns a list of strings of the configured inputs. +func (c *Config) InputNames() []string { + name := make([]string, 0, len(c.Inputs)) + for _, input := range c.Inputs { + name = append(name, input.Config.Name) + } + return PluginNameCounts(name) +} + +// InputNamesWithSources returns a table representation of input names and their sources. +func (c *Config) InputNamesWithSources() string { + plugins := make(pluginNames, 0, len(c.Inputs)) + for _, input := range c.Inputs { + plugins = append(plugins, pluginPrinter{ + name: input.Config.Name, + source: input.Config.Source, + }) + } + return getPluginSourcesTable(plugins) +} + +// AggregatorNames returns a list of strings of the configured aggregators. +func (c *Config) AggregatorNames() []string { + name := make([]string, 0, len(c.Aggregators)) + for _, aggregator := range c.Aggregators { + name = append(name, aggregator.Config.Name) + } + return PluginNameCounts(name) +} + +// AggregatorNamesWithSources returns a table representation of aggregator names and their sources. +func (c *Config) AggregatorNamesWithSources() string { + plugins := make(pluginNames, 0, len(c.Aggregators)) + for _, aggregator := range c.Aggregators { + plugins = append(plugins, pluginPrinter{ + name: aggregator.Config.Name, + source: aggregator.Config.Source, + }) + } + return getPluginSourcesTable(plugins) +} + +// ProcessorNames returns a list of strings of the configured processors. +func (c *Config) ProcessorNames() []string { + name := make([]string, 0, len(c.Processors)) + for _, processor := range c.Processors { + name = append(name, processor.Config.Name) + } + return PluginNameCounts(name) +} + +// ProcessorNamesWithSources returns a table representation of processor names and their sources. +func (c *Config) ProcessorNamesWithSources() string { + plugins := make(pluginNames, 0, len(c.Processors)) + for _, processor := range c.Processors { + plugins = append(plugins, pluginPrinter{ + name: processor.Config.Name, + source: processor.Config.Source, + }) + } + return getPluginSourcesTable(plugins) +} + +// OutputNames returns a list of strings of the configured outputs. +func (c *Config) OutputNames() []string { + name := make([]string, 0, len(c.Outputs)) + for _, output := range c.Outputs { + name = append(name, output.Config.Name) + } + return PluginNameCounts(name) +} + +// OutputNamesWithSources returns a table representation of output names and their sources. +func (c *Config) OutputNamesWithSources() string { + plugins := make(pluginNames, 0, len(c.Outputs)) + for _, output := range c.Outputs { + plugins = append(plugins, pluginPrinter{ + name: output.Config.Name, + source: output.Config.Source, + }) + } + return getPluginSourcesTable(plugins) +} + +// SecretstoreNames returns a list of strings of the configured secret-stores. +func (c *Config) SecretstoreNames() []string { + names := make([]string, 0, len(c.SecretStores)) + for name := range c.SecretStores { + names = append(names, name) + } + return PluginNameCounts(names) +} + +// SecretstoreNamesWithSources returns a table representation of secret store names and their sources. +func (c *Config) SecretstoreNamesWithSources() string { + plugins := make(pluginNames, 0, len(c.SecretStores)) + for name, sources := range c.secretStoreSource { + for _, source := range sources { + plugins = append(plugins, pluginPrinter{ + name: name, + source: source, + }) + } + } + return getPluginSourcesTable(plugins) +} + +// PluginNameCounts returns a string of plugin names and their counts. +// PluginNameCounts returns a list of sorted plugin names and their count +func PluginNameCounts(plugins []string) []string { + names := make(map[string]int) + for _, plugin := range plugins { + names[plugin]++ + } + + var namecount []string + for name, count := range names { + if count == 1 { + namecount = append(namecount, name) + } else { + namecount = append(namecount, fmt.Sprintf("%s (%dx)", name, count)) + } + } + + sort.Strings(namecount) + return namecount +} + +// ListTags returns a string of tags specified in the config, +// line-protocol style +func (c *Config) ListTags() string { + tags := make([]string, 0, len(c.Tags)) + for k, v := range c.Tags { + tags = append(tags, fmt.Sprintf("%s=%s", k, v)) + } + + sort.Strings(tags) + + return strings.Join(tags, " ") +} + +func sliceContains(name string, list []string) bool { + for _, b := range list { + if b == name { + return true + } + } + return false +} + +// WalkDirectory collects all toml files that need to be loaded +func WalkDirectory(path string) ([]string, error) { + var files []string + walkfn := func(thispath string, info os.FileInfo, _ error) error { + if info == nil { + log.Printf("W! Telegraf is not permitted to read %s", thispath) + return nil + } + + if info.IsDir() { + if strings.HasPrefix(info.Name(), "..") { + // skip Kubernetes mounts, preventing loading the same config twice + return filepath.SkipDir + } + + return nil + } + name := info.Name() + if len(name) < 6 || name[len(name)-5:] != ".conf" { + return nil + } + files = append(files, thispath) + return nil + } + return files, filepath.Walk(path, walkfn) +} + +// Try to find a default config file at these locations (in order): +// 1. $TELEGRAF_CONFIG_PATH +// 2. $HOME/.telegraf/telegraf.conf +// 3. /etc/telegraf/telegraf.conf and /etc/telegraf/telegraf.d/*.conf +func GetDefaultConfigPath() ([]string, error) { + envfile := os.Getenv("TELEGRAF_CONFIG_PATH") + homefile := os.ExpandEnv("${HOME}/.telegraf/telegraf.conf") + etcfile := "/etc/telegraf/telegraf.conf" + etcfolder := "/etc/telegraf/telegraf.d" + + if runtime.GOOS == "windows" { + programFiles := os.Getenv("ProgramFiles") + if programFiles == "" { // Should never happen + programFiles = `C:\Program Files` + } + etcfile = programFiles + `\Telegraf\telegraf.conf` + etcfolder = programFiles + `\Telegraf\telegraf.d\` + } + + for _, path := range []string{envfile, homefile} { + if isURL(path) { + return []string{path}, nil + } + if _, err := os.Stat(path); err == nil { + return []string{path}, nil + } + } + + // At this point we need to check if the files under /etc/telegraf are + // populated and return them all. + confFiles := make([]string, 0) + if _, err := os.Stat(etcfile); err == nil { + confFiles = append(confFiles, etcfile) + } + if _, err := os.Stat(etcfolder); err == nil { + files, err := WalkDirectory(etcfolder) + if err != nil { + log.Printf("W! unable walk %q: %s", etcfolder, err) + } + confFiles = append(confFiles, files...) + } + if len(confFiles) > 0 { + return confFiles, nil + } + + // if we got here, we didn't find a file in a default location + return nil, fmt.Errorf("no config file specified, and could not find one"+ + " in $TELEGRAF_CONFIG_PATH, %s, %s, or %s/*.conf", homefile, etcfile, etcfolder) +} + +// isURL checks if string is valid url +func isURL(str string) bool { + u, err := url.Parse(str) + return err == nil && u.Scheme != "" && u.Host != "" +} + +// LoadConfig loads the given config files and applies it to c +func (c *Config) LoadConfig(path string) error { + if !c.Agent.Quiet { + log.Printf("I! Loading config: %s", path) + } + + data, _, err := LoadConfigFileWithRetries(path, c.Agent.ConfigURLRetryAttempts) + if err != nil { + return fmt.Errorf("loading config file %s failed: %w", path, err) + } + + if err = c.LoadConfigData(data, path); err != nil { + return fmt.Errorf("loading config file %s failed: %w", path, err) + } + + return nil +} + +func (c *Config) LoadAll(configFiles ...string) error { + for _, fConfig := range configFiles { + if err := c.LoadConfig(fConfig); err != nil { + return err + } + } + + // Sort the processors according to their `order` setting while + // using a stable sort to keep the file loading / file position order. + sort.Stable(c.Processors) + sort.Stable(c.AggProcessors) + + // Set snmp agent translator default + if c.Agent.SnmpTranslator == "" { + c.Agent.SnmpTranslator = "netsnmp" + } + + // Check if there is enough lockable memory for the secret + count := secretCount.Load() + if count < 0 { + log.Printf("E! Invalid secret count %d, please report this incident including your configuration!", count) + count = 0 + } + c.NumberSecrets = uint64(count) + + // Let's link all secrets to their secret-stores + return c.LinkSecrets() +} + +type cfgDataOptions struct { + sourcePath string +} + +type cfgDataOption func(*cfgDataOptions) + +func WithSourcePath(path string) cfgDataOption { + return func(o *cfgDataOptions) { + o.sourcePath = path + } +} + +// LoadConfigData loads TOML-formatted config data +func (c *Config) LoadConfigData(data []byte, path string) error { + tbl, err := parseConfig(data) + if err != nil { + return fmt.Errorf("error parsing data: %w", err) + } + + // Parse tags tables first: + for _, tableName := range []string{"tags", "global_tags"} { + if val, ok := tbl.Fields[tableName]; ok { + subTable, ok := val.(*ast.Table) + if !ok { + return fmt.Errorf("invalid configuration, bad table name %q", tableName) + } + if err = c.toml.UnmarshalTable(subTable, c.Tags); err != nil { + return fmt.Errorf("error parsing table name %q: %w", tableName, err) + } + } + } + + // Parse agent table: + if val, ok := tbl.Fields["agent"]; ok { + if c.seenAgentTable { + c.seenAgentTableOnce.Do(func() { + log.Printf("W! Overlapping settings in multiple agent tables are not supported: may cause undefined behavior") + }) + } + c.seenAgentTable = true + + subTable, ok := val.(*ast.Table) + if !ok { + return errors.New("invalid configuration, error parsing agent table") + } + if err = c.toml.UnmarshalTable(subTable, c.Agent); err != nil { + return fmt.Errorf("error parsing [agent]: %w", err) + } + } + + if !c.Agent.OmitHostname { + if c.Agent.Hostname == "" { + hostname, err := os.Hostname() + if err != nil { + return err + } + + c.Agent.Hostname = hostname + } + + c.Tags["host"] = c.Agent.Hostname + } + + // Warn when explicitly setting the old snmp translator + if c.Agent.SnmpTranslator == "netsnmp" { + PrintOptionValueDeprecationNotice("agent", "snmp_translator", "netsnmp", telegraf.DeprecationInfo{ + Since: "1.25.0", + RemovalIn: "1.40.0", + Notice: "Use 'gosmi' instead", + }) + } + + // Set up the persister if requested + if c.Agent.Statefile != "" { + c.Persister = &persister.Persister{ + Filename: c.Agent.Statefile, + } + } + + if len(c.UnusedFields) > 0 { + return fmt.Errorf( + "line %d: configuration specified the fields %q, but they were not used; "+ + "this is either a typo or this config option does not exist in this version", + tbl.Line, keys(c.UnusedFields)) + } + + // Initialize the file-sorting slices + c.fileProcessors = make(OrderedPlugins, 0) + c.fileAggProcessors = make(OrderedPlugins, 0) + + // Parse all the rest of the plugins: + for name, val := range tbl.Fields { + subTable, ok := val.(*ast.Table) + if !ok { + return fmt.Errorf("invalid configuration, error parsing field %q as table", name) + } + + switch name { + case "agent", "global_tags", "tags": + case "outputs": + for pluginName, pluginVal := range subTable.Fields { + switch pluginSubTable := pluginVal.(type) { + // legacy [outputs.influxdb] support + case *ast.Table: + if err = c.addOutput(pluginName, path, pluginSubTable); err != nil { + return fmt.Errorf("error parsing %s, %w", pluginName, err) + } + case []*ast.Table: + for _, t := range pluginSubTable { + if err = c.addOutput(pluginName, path, t); err != nil { + return fmt.Errorf("error parsing %s array, %w", pluginName, err) + } + } + default: + return fmt.Errorf("unsupported config format: %s", + pluginName) + } + if len(c.UnusedFields) > 0 { + return fmt.Errorf( + "plugin %s.%s: line %d: configuration specified the fields %q, but they were not used; "+ + "this is either a typo or this config option does not exist in this version", + name, pluginName, subTable.Line, keys(c.UnusedFields)) + } + } + case "inputs", "plugins": + for pluginName, pluginVal := range subTable.Fields { + switch pluginSubTable := pluginVal.(type) { + // legacy [inputs.cpu] support + case *ast.Table: + if err = c.addInput(pluginName, path, pluginSubTable); err != nil { + return fmt.Errorf("error parsing %s, %w", pluginName, err) + } + case []*ast.Table: + for _, t := range pluginSubTable { + if err = c.addInput(pluginName, path, t); err != nil { + return fmt.Errorf("error parsing %s, %w", pluginName, err) + } + } + default: + return fmt.Errorf("unsupported config format: %s", + pluginName) + } + if len(c.UnusedFields) > 0 { + return fmt.Errorf( + "plugin %s.%s: line %d: configuration specified the fields %q, but they were not used; "+ + "this is either a typo or this config option does not exist in this version", + name, pluginName, subTable.Line, keys(c.UnusedFields)) + } + } + case "processors": + for pluginName, pluginVal := range subTable.Fields { + switch pluginSubTable := pluginVal.(type) { + case []*ast.Table: + for _, t := range pluginSubTable { + if err = c.addProcessor(pluginName, path, t); err != nil { + return fmt.Errorf("error parsing %s, %w", pluginName, err) + } + } + default: + return fmt.Errorf("unsupported config format: %s", + pluginName) + } + if len(c.UnusedFields) > 0 { + return fmt.Errorf( + "plugin %s.%s: line %d: configuration specified the fields %q, but they were not used; "+ + "this is either a typo or this config option does not exist in this version", + name, + pluginName, + subTable.Line, + keys(c.UnusedFields), + ) + } + } + case "aggregators": + for pluginName, pluginVal := range subTable.Fields { + switch pluginSubTable := pluginVal.(type) { + case []*ast.Table: + for _, t := range pluginSubTable { + if err = c.addAggregator(pluginName, path, t); err != nil { + return fmt.Errorf("error parsing %s, %w", pluginName, err) + } + } + default: + return fmt.Errorf("unsupported config format: %s", + pluginName) + } + if len(c.UnusedFields) > 0 { + return fmt.Errorf( + "plugin %s.%s: line %d: configuration specified the fields %q, but they were not used; "+ + "this is either a typo or this config option does not exist in this version", + name, pluginName, subTable.Line, keys(c.UnusedFields)) + } + } + case "secretstores": + for pluginName, pluginVal := range subTable.Fields { + switch pluginSubTable := pluginVal.(type) { + case []*ast.Table: + for _, t := range pluginSubTable { + if err = c.addSecretStore(pluginName, path, t); err != nil { + return fmt.Errorf("error parsing %s, %w", pluginName, err) + } + } + default: + return fmt.Errorf("unsupported config format: %s", pluginName) + } + if len(c.UnusedFields) > 0 { + msg := "plugin %s.%s: line %d: configuration specified the fields %q, but they were not used; " + + "this is either a typo or this config option does not exist in this version" + return fmt.Errorf(msg, name, pluginName, subTable.Line, keys(c.UnusedFields)) + } + } + + // Assume it's an input for legacy config file support if no other + // identifiers are present + default: + if err = c.addInput(name, path, subTable); err != nil { + return fmt.Errorf("error parsing %s, %w", name, err) + } + } + } + + // Sort the processor according to the order they appeared in this file + // In a later stage, we sort them using the `order` option. + sort.Sort(c.fileProcessors) + for _, op := range c.fileProcessors { + c.Processors = append(c.Processors, op.plugin.(*models.RunningProcessor)) + } + + sort.Sort(c.fileAggProcessors) + for _, op := range c.fileAggProcessors { + c.AggProcessors = append(c.AggProcessors, op.plugin.(*models.RunningProcessor)) + } + + return nil +} + +// trimBOM trims the Byte-Order-Marks from the beginning of the file. +// this is for Windows compatibility only. +// see https://github.com/influxdata/telegraf/issues/1378 +func trimBOM(f []byte) []byte { + return bytes.TrimPrefix(f, []byte("\xef\xbb\xbf")) +} + +// LoadConfigFile loads the content of a configuration file and returns it +// together with a flag denoting if the file is from a remote location such +// as a web server. +func LoadConfigFile(config string) ([]byte, bool, error) { + return LoadConfigFileWithRetries(config, 0) +} + +func LoadConfigFileWithRetries(config string, urlRetryAttempts int) ([]byte, bool, error) { + if fetchURLRe.MatchString(config) { + u, err := url.Parse(config) + if err != nil { + return nil, true, err + } + + switch u.Scheme { + case "https", "http": + data, err := fetchConfig(u, urlRetryAttempts) + return data, true, err + default: + return nil, true, fmt.Errorf("scheme %q not supported", u.Scheme) + } + } + + // If it isn't a https scheme, try it as a file + buffer, err := os.ReadFile(config) + if err != nil { + return nil, false, err + } + + mimeType := http.DetectContentType(buffer) + if !strings.Contains(mimeType, "text/plain") { + return nil, false, fmt.Errorf("provided config is not a TOML file: %s", config) + } + + return buffer, false, nil +} + +func fetchConfig(u *url.URL, urlRetryAttempts int) ([]byte, error) { + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return nil, err + } + + if v, exists := os.LookupEnv("INFLUX_TOKEN"); exists { + req.Header.Add("Authorization", "Token "+v) + } + req.Header.Add("Accept", "application/toml") + req.Header.Set("User-Agent", internal.ProductToken()) + + var totalAttempts int + if urlRetryAttempts == -1 { + totalAttempts = -1 + log.Printf("Using unlimited number of attempts to fetch HTTP config") + } else if urlRetryAttempts == 0 { + totalAttempts = 3 + } else if urlRetryAttempts > 0 { + totalAttempts = urlRetryAttempts + } else { + return nil, fmt.Errorf("invalid number of attempts: %d", urlRetryAttempts) + } + + attempt := 0 + for { + body, err := requestURLConfig(req) + if err == nil { + return body, nil + } + + log.Printf("Error getting HTTP config (attempt %d of %d): %s", attempt, totalAttempts, err) + if urlRetryAttempts != -1 && attempt >= totalAttempts { + return nil, err + } + + time.Sleep(httpLoadConfigRetryInterval) + attempt++ + } +} + +func requestURLConfig(req *http.Request) ([]byte, error) { + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, fmt.Errorf("failed to connect to HTTP config server: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("failed to fetch HTTP config: %s", resp.Status) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to read response body: %w", err) + } + + return body, nil +} + +// parseConfig loads a TOML configuration from a provided path and +// returns the AST produced from the TOML parser. When loading the file, it +// will find environment variables and replace them. +func parseConfig(contents []byte) (*ast.Table, error) { + contents = trimBOM(contents) + var err error + contents, err = removeComments(contents) + if err != nil { + return nil, err + } + outputBytes, err := substituteEnvironment(contents, OldEnvVarReplacement) + if err != nil { + return nil, err + } + return toml.Parse(outputBytes) +} + +func (c *Config) addAggregator(name, source string, table *ast.Table) error { + creator, ok := aggregators.Aggregators[name] + if !ok { + // Handle removed, deprecated plugins + if di, deprecated := aggregators.Deprecations[name]; deprecated { + printHistoricPluginDeprecationNotice("aggregators", name, di) + return errors.New("plugin deprecated") + } + return fmt.Errorf("undefined but requested aggregator: %s", name) + } + aggregator := creator() + + conf, err := c.buildAggregator(name, source, table) + if err != nil { + return err + } + + if err := c.toml.UnmarshalTable(table, aggregator); err != nil { + return err + } + + if err := c.printUserDeprecation("aggregators", name, aggregator); err != nil { + return err + } + + c.Aggregators = append(c.Aggregators, models.NewRunningAggregator(aggregator, conf)) + return nil +} + +func (c *Config) addSecretStore(name, source string, table *ast.Table) error { + if len(c.SecretStoreFilters) > 0 && !sliceContains(name, c.SecretStoreFilters) { + return nil + } + + storeID := c.getFieldString(table, "id") + if storeID == "" { + return fmt.Errorf("%q secret-store without ID", name) + } + if !secretStorePattern.MatchString(storeID) { + return fmt.Errorf("invalid secret-store ID %q, must only contain letters, numbers or underscore", storeID) + } + + creator, ok := secretstores.SecretStores[name] + if !ok { + // Handle removed, deprecated plugins + if di, deprecated := secretstores.Deprecations[name]; deprecated { + printHistoricPluginDeprecationNotice("secretstores", name, di) + return errors.New("plugin deprecated") + } + return fmt.Errorf("undefined but requested secretstores: %s", name) + } + store := creator(storeID) + + if err := c.toml.UnmarshalTable(table, store); err != nil { + return err + } + + if err := c.printUserDeprecation("secretstores", name, store); err != nil { + return err + } + + logger := logging.New("secretstores", name, "") + models.SetLoggerOnPlugin(store, logger) + + if err := store.Init(); err != nil { + return fmt.Errorf("error initializing secret-store %q: %w", storeID, err) + } + + if _, found := c.SecretStores[storeID]; found { + return fmt.Errorf("duplicate ID %q for secretstore %q", storeID, name) + } + c.SecretStores[storeID] = store + if _, found := c.secretStoreSource[name]; !found { + c.secretStoreSource[name] = make([]string, 0) + } + c.secretStoreSource[name] = append(c.secretStoreSource[name], source) + return nil +} + +func (c *Config) LinkSecrets() error { + for _, s := range unlinkedSecrets { + resolvers := make(map[string]telegraf.ResolveFunc) + for _, ref := range s.GetUnlinked() { + // Split the reference and lookup the resolver + storeID, key := splitLink(ref) + store, found := c.SecretStores[storeID] + if !found { + return fmt.Errorf("unknown secret-store for %q", ref) + } + resolver, err := store.GetResolver(key) + if err != nil { + return fmt.Errorf("retrieving resolver for %q failed: %w", ref, err) + } + resolvers[ref] = resolver + } + // Inject the resolver list into the secret + if err := s.Link(resolvers); err != nil { + return fmt.Errorf("retrieving resolver failed: %w", err) + } + } + return nil +} + +func (c *Config) probeParser(parentCategory, parentName string, table *ast.Table) bool { + dataFormat := c.getFieldString(table, "data_format") + if dataFormat == "" { + dataFormat = setDefaultParser(parentCategory, parentName) + } + + creator, ok := parsers.Parsers[dataFormat] + if !ok { + return false + } + + // Try to parse the options to detect if any of them is misspelled + parser := creator("") + //nolint:errcheck // We don't actually use the parser, so no need to check the error. + c.toml.UnmarshalTable(table, parser) + + return true +} + +func (c *Config) addParser(parentcategory, parentname string, table *ast.Table) (*models.RunningParser, error) { + conf := &models.ParserConfig{ + Parent: parentname, + } + + conf.DataFormat = c.getFieldString(table, "data_format") + if conf.DataFormat == "" { + conf.DataFormat = setDefaultParser(parentcategory, parentname) + } else if conf.DataFormat == "influx" { + influxParserType := c.getFieldString(table, "influx_parser_type") + if influxParserType == "upstream" { + conf.DataFormat = "influx_upstream" + } + } + conf.LogLevel = c.getFieldString(table, "log_level") + + creator, ok := parsers.Parsers[conf.DataFormat] + if !ok { + return nil, fmt.Errorf("undefined but requested parser: %s", conf.DataFormat) + } + parser := creator(parentname) + + // Handle reset-mode of CSV parsers to stay backward compatible (see issue #12022) + if conf.DataFormat == "csv" && parentcategory == "inputs" { + if parentname == "exec" { + csvParser := parser.(*csv.Parser) + csvParser.ResetMode = "always" + } + } + + if err := c.toml.UnmarshalTable(table, parser); err != nil { + return nil, err + } + + running := models.NewRunningParser(parser, conf) + err := running.Init() + return running, err +} + +func (c *Config) probeSerializer(table *ast.Table) bool { + dataFormat := c.getFieldString(table, "data_format") + if dataFormat == "" { + dataFormat = "influx" + } + + creator, ok := serializers.Serializers[dataFormat] + if !ok { + return false + } + + // Try to parse the options to detect if any of them is misspelled + serializer := creator() + //nolint:errcheck // We don't actually use the parser, so no need to check the error. + c.toml.UnmarshalTable(table, serializer) + + return true +} + +func (c *Config) addSerializer(parentname string, table *ast.Table) (*models.RunningSerializer, error) { + conf := &models.SerializerConfig{ + Parent: parentname, + } + conf.DataFormat = c.getFieldString(table, "data_format") + if conf.DataFormat == "" { + conf.DataFormat = "influx" + } + conf.LogLevel = c.getFieldString(table, "log_level") + + creator, ok := serializers.Serializers[conf.DataFormat] + if !ok { + return nil, fmt.Errorf("undefined but requested serializer: %s", conf.DataFormat) + } + serializer := creator() + + if err := c.toml.UnmarshalTable(table, serializer); err != nil { + return nil, err + } + + running := models.NewRunningSerializer(serializer, conf) + err := running.Init() + return running, err +} + +func (c *Config) addProcessor(name, source string, table *ast.Table) error { + creator, ok := processors.Processors[name] + if !ok { + // Handle removed, deprecated plugins + if di, deprecated := processors.Deprecations[name]; deprecated { + printHistoricPluginDeprecationNotice("processors", name, di) + return errors.New("plugin deprecated") + } + return fmt.Errorf("undefined but requested processor: %s", name) + } + + // For processors with parsers we need to compute the set of + // options that is not covered by both, the parser and the processor. + // We achieve this by keeping a local book of missing entries + // that counts the number of misses. In case we have a parser + // for the input both need to miss the entry. We count the + // missing entries at the end. + missCount := make(map[string]int) + missCountThreshold := 0 + c.setLocalMissingTomlFieldTracker(missCount) + defer c.resetMissingTomlFieldTracker() + + // Set up the processor running before the aggregators + processorBeforeConfig, err := c.buildProcessor("processors", name, source, table) + if err != nil { + return err + } + processorBefore, count, err := c.setupProcessor(processorBeforeConfig.Name, creator, table) + if err != nil { + return err + } + rf := models.NewRunningProcessor(processorBefore, processorBeforeConfig) + c.fileProcessors = append(c.fileProcessors, &OrderedPlugin{table.Line, rf}) + + // Setup another (new) processor instance running after the aggregator + processorAfterConfig, err := c.buildProcessor("aggprocessors", name, source, table) + if err != nil { + return err + } + processorAfter, _, err := c.setupProcessor(processorAfterConfig.Name, creator, table) + if err != nil { + return err + } + rf = models.NewRunningProcessor(processorAfter, processorAfterConfig) + c.fileAggProcessors = append(c.fileAggProcessors, &OrderedPlugin{table.Line, rf}) + + // Check the number of misses against the threshold. We need to double + // the count as the processor setup is executed twice. + missCountThreshold = 2 * count + for key, count := range missCount { + if count <= missCountThreshold { + continue + } + if err := c.missingTomlField(nil, key); err != nil { + return err + } + } + + return nil +} + +func (c *Config) setupProcessor(name string, creator processors.StreamingCreator, table *ast.Table) (telegraf.StreamingProcessor, int, error) { + var optionTestCount int + + streamingProcessor := creator() + + var processor interface{} + if p, ok := streamingProcessor.(processors.HasUnwrap); ok { + processor = p.Unwrap() + } else { + processor = streamingProcessor + } + + // If the (underlying) processor has a SetParser or SetParserFunc function, + // it can accept arbitrary data-formats, so build the requested parser and + // set it. + if t, ok := processor.(telegraf.ParserPlugin); ok { + parser, err := c.addParser("processors", name, table) + if err != nil { + return nil, 0, fmt.Errorf("adding parser failed: %w", err) + } + t.SetParser(parser) + optionTestCount++ + } + + if t, ok := processor.(telegraf.ParserFuncPlugin); ok { + if !c.probeParser("processors", name, table) { + return nil, 0, errors.New("parser not found") + } + t.SetParserFunc(func() (telegraf.Parser, error) { + return c.addParser("processors", name, table) + }) + optionTestCount++ + } + + // If the (underlying) processor has a SetSerializer function it can accept + // arbitrary data-formats, so build the requested serializer and set it. + if t, ok := processor.(telegraf.SerializerPlugin); ok { + serializer, err := c.addSerializer(name, table) + if err != nil { + return nil, 0, fmt.Errorf("adding serializer failed: %w", err) + } + t.SetSerializer(serializer) + optionTestCount++ + } + if t, ok := processor.(telegraf.SerializerFuncPlugin); ok { + if !c.probeSerializer(table) { + return nil, 0, errors.New("serializer not found") + } + t.SetSerializerFunc(func() (telegraf.Serializer, error) { + return c.addSerializer(name, table) + }) + optionTestCount++ + } + + if err := c.toml.UnmarshalTable(table, processor); err != nil { + return nil, 0, fmt.Errorf("unmarshalling failed: %w", err) + } + + err := c.printUserDeprecation("processors", name, processor) + return streamingProcessor, optionTestCount, err +} + +func (c *Config) addOutput(name, source string, table *ast.Table) error { + if len(c.OutputFilters) > 0 && !sliceContains(name, c.OutputFilters) { + return nil + } + + // For outputs with serializers we need to compute the set of + // options that is not covered by both, the serializer and the input. + // We achieve this by keeping a local book of missing entries + // that counts the number of misses. In case we have a parser + // for the input both need to miss the entry. We count the + // missing entries at the end. + missThreshold := 0 + missCount := make(map[string]int) + c.setLocalMissingTomlFieldTracker(missCount) + defer c.resetMissingTomlFieldTracker() + + creator, ok := outputs.Outputs[name] + if !ok { + // Handle removed, deprecated plugins + if di, deprecated := outputs.Deprecations[name]; deprecated { + printHistoricPluginDeprecationNotice("outputs", name, di) + return errors.New("plugin deprecated") + } + return fmt.Errorf("undefined but requested output: %s", name) + } + output := creator() + + // If the output has a SetSerializer function, then this means it can write + // arbitrary types of output, so build the serializer and set it. + if t, ok := output.(telegraf.SerializerPlugin); ok { + missThreshold = 1 + serializer, err := c.addSerializer(name, table) + if err != nil { + return err + } + t.SetSerializer(serializer) + } + + if t, ok := output.(telegraf.SerializerFuncPlugin); ok { + missThreshold = 1 + if !c.probeSerializer(table) { + return errors.New("serializer not found") + } + t.SetSerializerFunc(func() (telegraf.Serializer, error) { + return c.addSerializer(name, table) + }) + } + + outputConfig, err := c.buildOutput(name, source, table) + if err != nil { + return err + } + + if err := c.toml.UnmarshalTable(table, output); err != nil { + return err + } + + if err := c.printUserDeprecation("outputs", name, output); err != nil { + return err + } + + if c, ok := interface{}(output).(interface{ TLSConfig() (*tls.Config, error) }); ok { + if _, err := c.TLSConfig(); err != nil { + return err + } + } + + // Check the number of misses against the threshold + for key, count := range missCount { + if count <= missThreshold { + continue + } + if err := c.missingTomlField(nil, key); err != nil { + return err + } + } + + ro := models.NewRunningOutput(output, outputConfig, c.Agent.MetricBatchSize, c.Agent.MetricBufferLimit) + c.Outputs = append(c.Outputs, ro) + + return nil +} + +func (c *Config) addInput(name, source string, table *ast.Table) error { + if len(c.InputFilters) > 0 && !sliceContains(name, c.InputFilters) { + return nil + } + + // For inputs with parsers we need to compute the set of + // options that is not covered by both, the parser and the input. + // We achieve this by keeping a local book of missing entries + // that counts the number of misses. In case we have a parser + // for the input both need to miss the entry. We count the + // missing entries at the end. + missCount := make(map[string]int) + missCountThreshold := 0 + c.setLocalMissingTomlFieldTracker(missCount) + defer c.resetMissingTomlFieldTracker() + + creator, ok := inputs.Inputs[name] + if !ok { + // Handle removed, deprecated plugins + if di, deprecated := inputs.Deprecations[name]; deprecated { + printHistoricPluginDeprecationNotice("inputs", name, di) + return errors.New("plugin deprecated") + } + + return fmt.Errorf("undefined but requested input: %s", name) + } + input := creator() + + // If the input has a SetParser or SetParserFunc function, it can accept + // arbitrary data-formats, so build the requested parser and set it. + if t, ok := input.(telegraf.ParserPlugin); ok { + missCountThreshold = 1 + parser, err := c.addParser("inputs", name, table) + if err != nil { + return fmt.Errorf("adding parser failed: %w", err) + } + t.SetParser(parser) + } + + if t, ok := input.(telegraf.ParserFuncPlugin); ok { + missCountThreshold = 1 + if !c.probeParser("inputs", name, table) { + return errors.New("parser not found") + } + t.SetParserFunc(func() (telegraf.Parser, error) { + return c.addParser("inputs", name, table) + }) + } + + pluginConfig, err := c.buildInput(name, source, table) + if err != nil { + return err + } + + if err := c.toml.UnmarshalTable(table, input); err != nil { + return err + } + + if err := c.printUserDeprecation("inputs", name, input); err != nil { + return err + } + + if c, ok := interface{}(input).(interface{ TLSConfig() (*tls.Config, error) }); ok { + if _, err := c.TLSConfig(); err != nil { + return err + } + } + + // Check the number of misses against the threshold + for key, count := range missCount { + if count <= missCountThreshold { + continue + } + if err := c.missingTomlField(nil, key); err != nil { + return err + } + } + + rp := models.NewRunningInput(input, pluginConfig) + rp.SetDefaultTags(c.Tags) + c.Inputs = append(c.Inputs, rp) + + return nil +} + +// buildAggregator parses Aggregator specific items from the ast.Table, +// builds the filter and returns a +// models.AggregatorConfig to be inserted into models.RunningAggregator +func (c *Config) buildAggregator(name, source string, tbl *ast.Table) (*models.AggregatorConfig, error) { + conf := &models.AggregatorConfig{ + Name: name, + Source: source, + Delay: time.Millisecond * 100, + Period: time.Second * 30, + Grace: time.Second * 0, + } + + if period, found := c.getFieldDuration(tbl, "period"); found { + conf.Period = period + } + if delay, found := c.getFieldDuration(tbl, "delay"); found { + conf.Delay = delay + } + if grace, found := c.getFieldDuration(tbl, "grace"); found { + conf.Grace = grace + } + + conf.DropOriginal = c.getFieldBool(tbl, "drop_original") + conf.MeasurementPrefix = c.getFieldString(tbl, "name_prefix") + conf.MeasurementSuffix = c.getFieldString(tbl, "name_suffix") + conf.NameOverride = c.getFieldString(tbl, "name_override") + conf.Alias = c.getFieldString(tbl, "alias") + conf.LogLevel = c.getFieldString(tbl, "log_level") + + conf.Tags = make(map[string]string) + if node, ok := tbl.Fields["tags"]; ok { + if subtbl, ok := node.(*ast.Table); ok { + if err := c.toml.UnmarshalTable(subtbl, conf.Tags); err != nil { + return nil, fmt.Errorf("could not parse tags for input %s", name) + } + } + } + + if c.hasErrs() { + return nil, c.firstErr() + } + + var err error + conf.Filter, err = c.buildFilter("aggregators."+name, tbl) + if err != nil { + return conf, err + } + + // Generate an ID for the plugin + conf.ID, err = generatePluginID("aggregators."+name, tbl) + return conf, err +} + +// buildProcessor parses Processor specific items from the ast.Table, +// builds the filter and returns a +// models.ProcessorConfig to be inserted into models.RunningProcessor +func (c *Config) buildProcessor(category, name, source string, tbl *ast.Table) (*models.ProcessorConfig, error) { + conf := &models.ProcessorConfig{ + Name: name, + Source: source, + } + + conf.Order = c.getFieldInt64(tbl, "order") + conf.Alias = c.getFieldString(tbl, "alias") + conf.LogLevel = c.getFieldString(tbl, "log_level") + + if c.hasErrs() { + return nil, c.firstErr() + } + + var err error + conf.Filter, err = c.buildFilter(category+"."+name, tbl) + if err != nil { + return conf, err + } + + // Generate an ID for the plugin + conf.ID, err = generatePluginID(category+"."+name, tbl) + return conf, err +} + +// buildFilter builds a Filter +// (tags, fields, namepass, namedrop, metricpass) to +// be inserted into the models.OutputConfig/models.InputConfig +// to be used for glob filtering on tags and measurements +func (c *Config) buildFilter(plugin string, tbl *ast.Table) (models.Filter, error) { + f := models.Filter{} + + f.NamePass = c.getFieldStringSlice(tbl, "namepass") + f.NamePassSeparators = c.getFieldString(tbl, "namepass_separator") + f.NameDrop = c.getFieldStringSlice(tbl, "namedrop") + f.NameDropSeparators = c.getFieldString(tbl, "namedrop_separator") + + oldPass := c.getFieldStringSlice(tbl, "pass") + if len(oldPass) > 0 { + PrintOptionDeprecationNotice(plugin, "pass", telegraf.DeprecationInfo{ + Since: "0.10.4", + RemovalIn: "1.35.0", + Notice: "use 'fieldinclude' instead", + }) + f.FieldInclude = append(f.FieldInclude, oldPass...) + } + + oldFieldPass := c.getFieldStringSlice(tbl, "fieldpass") + if len(oldFieldPass) > 0 { + PrintOptionDeprecationNotice(plugin, "fieldpass", telegraf.DeprecationInfo{ + Since: "1.29.0", + RemovalIn: "1.40.0", + Notice: "use 'fieldinclude' instead", + }) + f.FieldInclude = append(f.FieldInclude, oldFieldPass...) + } + + fieldInclude := c.getFieldStringSlice(tbl, "fieldinclude") + if len(fieldInclude) > 0 { + f.FieldInclude = append(f.FieldInclude, fieldInclude...) + } + + oldDrop := c.getFieldStringSlice(tbl, "drop") + if len(oldDrop) > 0 { + PrintOptionDeprecationNotice(plugin, "drop", telegraf.DeprecationInfo{ + Since: "0.10.4", + RemovalIn: "1.35.0", + Notice: "use 'fieldexclude' instead", + }) + f.FieldExclude = append(f.FieldExclude, oldDrop...) + } + + oldFieldDrop := c.getFieldStringSlice(tbl, "fielddrop") + if len(oldFieldDrop) > 0 { + PrintOptionDeprecationNotice(plugin, "fielddrop", telegraf.DeprecationInfo{ + Since: "1.29.0", + RemovalIn: "1.40.0", + Notice: "use 'fieldexclude' instead", + }) + f.FieldExclude = append(f.FieldExclude, oldFieldDrop...) + } + + fieldExclude := c.getFieldStringSlice(tbl, "fieldexclude") + if len(fieldExclude) > 0 { + f.FieldExclude = append(f.FieldExclude, fieldExclude...) + } + + f.TagPassFilters = c.getFieldTagFilter(tbl, "tagpass") + f.TagDropFilters = c.getFieldTagFilter(tbl, "tagdrop") + + f.TagExclude = c.getFieldStringSlice(tbl, "tagexclude") + f.TagInclude = c.getFieldStringSlice(tbl, "taginclude") + + f.MetricPass = c.getFieldString(tbl, "metricpass") + + if c.hasErrs() { + return f, c.firstErr() + } + + if err := f.Compile(); err != nil { + return f, err + } + + return f, nil +} + +// buildInput parses input specific items from the ast.Table, +// builds the filter and returns a +// models.InputConfig to be inserted into models.RunningInput +func (c *Config) buildInput(name, source string, tbl *ast.Table) (*models.InputConfig, error) { + cp := &models.InputConfig{ + Name: name, + Source: source, + AlwaysIncludeLocalTags: c.Agent.AlwaysIncludeLocalTags, + AlwaysIncludeGlobalTags: c.Agent.AlwaysIncludeGlobalTags, + } + cp.Interval, _ = c.getFieldDuration(tbl, "interval") + cp.Precision, _ = c.getFieldDuration(tbl, "precision") + cp.CollectionJitter, _ = c.getFieldDuration(tbl, "collection_jitter") + cp.CollectionOffset, _ = c.getFieldDuration(tbl, "collection_offset") + cp.StartupErrorBehavior = c.getFieldString(tbl, "startup_error_behavior") + cp.TimeSource = c.getFieldString(tbl, "time_source") + + cp.MeasurementPrefix = c.getFieldString(tbl, "name_prefix") + cp.MeasurementSuffix = c.getFieldString(tbl, "name_suffix") + cp.NameOverride = c.getFieldString(tbl, "name_override") + cp.Alias = c.getFieldString(tbl, "alias") + cp.LogLevel = c.getFieldString(tbl, "log_level") + + cp.Tags = make(map[string]string) + if node, ok := tbl.Fields["tags"]; ok { + if subtbl, ok := node.(*ast.Table); ok { + if err := c.toml.UnmarshalTable(subtbl, cp.Tags); err != nil { + return nil, fmt.Errorf("could not parse tags for input %s", name) + } + } + } + + if c.hasErrs() { + return nil, c.firstErr() + } + + var err error + cp.Filter, err = c.buildFilter("inputs."+name, tbl) + if err != nil { + return cp, err + } + + // Generate an ID for the plugin + cp.ID, err = generatePluginID("inputs."+name, tbl) + return cp, err +} + +// buildOutput parses output specific items from the ast.Table, +// builds the filter and returns a +// models.OutputConfig to be inserted into models.RunningInput +// Note: error exists in the return for future calls that might require error +func (c *Config) buildOutput(name, source string, tbl *ast.Table) (*models.OutputConfig, error) { + filter, err := c.buildFilter("outputs."+name, tbl) + if err != nil { + return nil, err + } + oc := &models.OutputConfig{ + Name: name, + Source: source, + Filter: filter, + BufferStrategy: c.Agent.BufferStrategy, + BufferDirectory: c.Agent.BufferDirectory, + } + + // TODO: support FieldPass/FieldDrop on outputs + + oc.FlushInterval, _ = c.getFieldDuration(tbl, "flush_interval") + oc.FlushJitter, _ = c.getFieldDuration(tbl, "flush_jitter") + oc.MetricBufferLimit = c.getFieldInt(tbl, "metric_buffer_limit") + oc.MetricBatchSize = c.getFieldInt(tbl, "metric_batch_size") + oc.Alias = c.getFieldString(tbl, "alias") + oc.NameOverride = c.getFieldString(tbl, "name_override") + oc.NameSuffix = c.getFieldString(tbl, "name_suffix") + oc.NamePrefix = c.getFieldString(tbl, "name_prefix") + oc.StartupErrorBehavior = c.getFieldString(tbl, "startup_error_behavior") + oc.LogLevel = c.getFieldString(tbl, "log_level") + + if c.hasErrs() { + return nil, c.firstErr() + } + + if oc.BufferStrategy == "disk" { + log.Printf("W! Using disk buffer strategy for plugin outputs.%s, this is an experimental feature", name) + } + + // Generate an ID for the plugin + oc.ID, err = generatePluginID("outputs."+name, tbl) + return oc, err +} + +func (c *Config) missingTomlField(_ reflect.Type, key string) error { + switch key { + // General options to ignore + case "alias", "always_include_local_tags", + "buffer_strategy", "buffer_directory", + "collection_jitter", "collection_offset", + "data_format", "delay", "drop", "drop_original", + "fielddrop", "fieldexclude", "fieldinclude", "fieldpass", "flush_interval", "flush_jitter", + "grace", + "interval", + "log_level", "lvm", // What is this used for? + "metric_batch_size", "metric_buffer_limit", "metricpass", + "name_override", "name_prefix", "name_suffix", "namedrop", "namedrop_separator", "namepass", "namepass_separator", + "order", + "pass", "period", "precision", + "tagdrop", "tagexclude", "taginclude", "tagpass", "tags", "startup_error_behavior": + + // Secret-store options to ignore + case "id": + + // Parser and serializer options to ignore + case "data_type", "influx_parser_type": + + default: + c.unusedFieldsMutex.Lock() + c.UnusedFields[key] = true + c.unusedFieldsMutex.Unlock() + } + return nil +} + +func (c *Config) setLocalMissingTomlFieldTracker(counter map[string]int) { + f := func(t reflect.Type, key string) error { + // Check if we are in a root element that might share options among + // each other. Those root elements are plugins of all types. + // All other elements are subtables of their respective plugin and + // should just be hit once anyway. Therefore, we mark them with a + // high number to handle them correctly later. + pt := reflect.PointerTo(t) + root := pt.Implements(reflect.TypeOf((*telegraf.Input)(nil)).Elem()) + root = root || pt.Implements(reflect.TypeOf((*telegraf.ServiceInput)(nil)).Elem()) + root = root || pt.Implements(reflect.TypeOf((*telegraf.Output)(nil)).Elem()) + root = root || pt.Implements(reflect.TypeOf((*telegraf.Aggregator)(nil)).Elem()) + root = root || pt.Implements(reflect.TypeOf((*telegraf.Processor)(nil)).Elem()) + root = root || pt.Implements(reflect.TypeOf((*telegraf.StreamingProcessor)(nil)).Elem()) + root = root || pt.Implements(reflect.TypeOf((*telegraf.Parser)(nil)).Elem()) + root = root || pt.Implements(reflect.TypeOf((*telegraf.Serializer)(nil)).Elem()) + + c, ok := counter[key] + if !root { + counter[key] = 100 + } else if !ok { + counter[key] = 1 + } else { + counter[key] = c + 1 + } + return nil + } + c.toml.MissingField = f +} + +func (c *Config) resetMissingTomlFieldTracker() { + c.toml.MissingField = c.missingTomlField +} + +func (*Config) getFieldString(tbl *ast.Table, fieldName string) string { + if node, ok := tbl.Fields[fieldName]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + return str.Value + } + } + } + + return "" +} + +func (c *Config) getFieldDuration(tbl *ast.Table, fieldName string) (time.Duration, bool) { + if node, ok := tbl.Fields[fieldName]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + d, err := time.ParseDuration(str.Value) + if err != nil { + c.addError(tbl, fmt.Errorf("error parsing duration: %w", err)) + return 0, false + } + return d, true + } + } + } + + return 0, false +} + +func (c *Config) getFieldBool(tbl *ast.Table, fieldName string) bool { + if node, ok := tbl.Fields[fieldName]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + switch t := kv.Value.(type) { + case *ast.Boolean: + target, err := t.Boolean() + if err != nil { + c.addError(tbl, fmt.Errorf("unknown boolean value type %q, expecting boolean", kv.Value)) + return false + } + return target + case *ast.String: + target, err := strconv.ParseBool(t.Value) + if err != nil { + c.addError(tbl, fmt.Errorf("unknown boolean value type %q, expecting boolean", kv.Value)) + return false + } + return target + default: + c.addError(tbl, fmt.Errorf("unknown boolean value type %q, expecting boolean", kv.Value.Source())) + return false + } + } + } + + return false +} + +func (c *Config) getFieldInt(tbl *ast.Table, fieldName string) int { + if node, ok := tbl.Fields[fieldName]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if iAst, ok := kv.Value.(*ast.Integer); ok { + i, err := iAst.Int() + if err != nil { + c.addError(tbl, fmt.Errorf("unexpected int type %q, expecting int", iAst.Value)) + return 0 + } + return int(i) + } + } + } + + return 0 +} + +func (c *Config) getFieldInt64(tbl *ast.Table, fieldName string) int64 { + if node, ok := tbl.Fields[fieldName]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if iAst, ok := kv.Value.(*ast.Integer); ok { + i, err := iAst.Int() + if err != nil { + c.addError(tbl, fmt.Errorf("unexpected int type %q, expecting int", iAst.Value)) + return 0 + } + return i + } + c.addError(tbl, fmt.Errorf("found unexpected format while parsing %q, expecting int", fieldName)) + return 0 + } + } + + return 0 +} + +func (c *Config) getFieldStringSlice(tbl *ast.Table, fieldName string) []string { + var target []string + if node, ok := tbl.Fields[fieldName]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + ary, ok := kv.Value.(*ast.Array) + if !ok { + c.addError(tbl, fmt.Errorf("found unexpected format while parsing %q, expecting string array/slice format", fieldName)) + return target + } + for _, elem := range ary.Value { + if str, ok := elem.(*ast.String); ok { + target = append(target, str.Value) + } + } + } + } + + return target +} + +func (c *Config) getFieldTagFilter(tbl *ast.Table, fieldName string) []models.TagFilter { + var target []models.TagFilter + if node, ok := tbl.Fields[fieldName]; ok { + if subTbl, ok := node.(*ast.Table); ok { + for name, val := range subTbl.Fields { + if kv, ok := val.(*ast.KeyValue); ok { + ary, ok := kv.Value.(*ast.Array) + if !ok { + c.addError(tbl, fmt.Errorf("found unexpected format while parsing %q, expecting string array/slice format on each entry", fieldName)) + return nil + } + + tagFilter := models.TagFilter{Name: name} + for _, elem := range ary.Value { + if str, ok := elem.(*ast.String); ok { + tagFilter.Values = append(tagFilter.Values, str.Value) + } + } + target = append(target, tagFilter) + } + } + } + } + + return target +} + +func keys(m map[string]bool) []string { + result := make([]string, 0, len(m)) + for k := range m { + result = append(result, k) + } + return result +} + +func setDefaultParser(category, name string) string { + // Legacy support, exec plugin originally parsed JSON by default. + if category == "inputs" && name == "exec" { + return "json" + } + + return "influx" +} + +func (c *Config) hasErrs() bool { + return len(c.errs) > 0 +} + +func (c *Config) firstErr() error { + if len(c.errs) == 0 { + return nil + } + return c.errs[0] +} + +func (c *Config) addError(tbl *ast.Table, err error) { + c.errs = append(c.errs, fmt.Errorf("line %d:%d: %w", tbl.Line, tbl.Position, err)) +} diff --git a/config/config_test.go b/config/config_test.go new file mode 100644 index 0000000..5921ba2 --- /dev/null +++ b/config/config_test.go @@ -0,0 +1,1540 @@ +package config_test + +import ( + "bytes" + "fmt" + "net/http" + "net/http/httptest" + "os" + "os/exec" + "path/filepath" + "reflect" + "regexp" + "runtime" + "strings" + "sync" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/stretchr/testify/require" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/config" + logging "github.com/influxdata/telegraf/logger" + "github.com/influxdata/telegraf/metric" + "github.com/influxdata/telegraf/models" + "github.com/influxdata/telegraf/persister" + "github.com/influxdata/telegraf/plugins/common/tls" + "github.com/influxdata/telegraf/plugins/inputs" + "github.com/influxdata/telegraf/plugins/outputs" + "github.com/influxdata/telegraf/plugins/parsers" + _ "github.com/influxdata/telegraf/plugins/parsers/all" // Blank import to have all parsers for testing + "github.com/influxdata/telegraf/plugins/parsers/json" + "github.com/influxdata/telegraf/plugins/parsers/json_v2" + "github.com/influxdata/telegraf/plugins/processors" + "github.com/influxdata/telegraf/plugins/serializers" + _ "github.com/influxdata/telegraf/plugins/serializers/all" // Blank import to have all serializers for testing + serializers_prometheus "github.com/influxdata/telegraf/plugins/serializers/prometheus" + "github.com/influxdata/telegraf/testutil" +) + +func TestReadBinaryFile(t *testing.T) { + // Create a temporary binary file using the Telegraf tool custom_builder to pass as a config + t.Chdir("..") + tmpdir := t.TempDir() + binaryFile := filepath.Join(tmpdir, "custom_builder") + cmd := exec.Command("go", "build", "-o", binaryFile, "./tools/custom_builder") + + var outb, errb bytes.Buffer + cmd.Stdout = &outb + cmd.Stderr = &errb + require.NoErrorf(t, cmd.Run(), "stdout: %s, stderr: %s", outb.String(), errb.String()) + + c := config.NewConfig() + require.ErrorContains(t, c.LoadConfig(binaryFile), "provided config is not a TOML file") +} + +func TestConfig_LoadSingleInputWithEnvVars(t *testing.T) { + c := config.NewConfig() + t.Setenv("MY_TEST_SERVER", "192.168.1.1") + t.Setenv("TEST_INTERVAL", "10s") + confFile := filepath.Join("testdata", "single_plugin_env_vars.toml") + require.NoError(t, c.LoadConfig(confFile)) + + input := inputs.Inputs["memcached"]().(*MockupInputPlugin) + input.Servers = []string{"192.168.1.1"} + input.Command = `Raw command which may or may not contain # in it +# is unique` + + filter := models.Filter{ + NameDrop: []string{"metricname2"}, + NamePass: []string{"metricname1", "ip_192.168.1.1_name"}, + FieldExclude: []string{"other", "stuff"}, + FieldInclude: []string{"some", "strings"}, + TagDropFilters: []models.TagFilter{ + { + Name: "badtag", + Values: []string{"othertag"}, + }, + }, + TagPassFilters: []models.TagFilter{ + { + Name: "goodtag", + Values: []string{"mytag", "tagwith#value", "TagWithMultilineSyntax"}, + }, + }, + } + require.NoError(t, filter.Compile()) + inputConfig := &models.InputConfig{ + Name: "memcached", + Source: confFile, + Filter: filter, + Interval: 10 * time.Second, + } + inputConfig.Tags = make(map[string]string) + + // Ignore Log, Parser and ID + c.Inputs[0].Input.(*MockupInputPlugin).Log = nil + c.Inputs[0].Input.(*MockupInputPlugin).parser = nil + c.Inputs[0].Config.ID = "" + require.Equal(t, input, c.Inputs[0].Input, "Testdata did not produce a correct mockup struct.") + require.Equal(t, inputConfig, c.Inputs[0].Config, "Testdata did not produce correct input metadata.") +} + +func TestConfig_LoadSingleInput(t *testing.T) { + c := config.NewConfig() + confFile := filepath.Join("testdata", "single_plugin.toml") + require.NoError(t, c.LoadConfig(confFile)) + + input := inputs.Inputs["memcached"]().(*MockupInputPlugin) + input.Servers = []string{"localhost"} + + filter := models.Filter{ + NameDrop: []string{"metricname2"}, + NamePass: []string{"metricname1"}, + FieldExclude: []string{"other", "stuff"}, + FieldInclude: []string{"some", "strings"}, + TagDropFilters: []models.TagFilter{ + { + Name: "badtag", + Values: []string{"othertag"}, + }, + }, + TagPassFilters: []models.TagFilter{ + { + Name: "goodtag", + Values: []string{"mytag"}, + }, + }, + } + require.NoError(t, filter.Compile()) + inputConfig := &models.InputConfig{ + Name: "memcached", + Source: confFile, + Filter: filter, + Interval: 5 * time.Second, + } + inputConfig.Tags = make(map[string]string) + + // Ignore Log, Parser and ID + c.Inputs[0].Input.(*MockupInputPlugin).Log = nil + c.Inputs[0].Input.(*MockupInputPlugin).parser = nil + c.Inputs[0].Config.ID = "" + require.Equal(t, input, c.Inputs[0].Input, "Testdata did not produce a correct memcached struct.") + require.Equal(t, inputConfig, c.Inputs[0].Config, "Testdata did not produce correct memcached metadata.") +} + +func TestConfig_LoadSingleInput_WithSeparators(t *testing.T) { + c := config.NewConfig() + confFile := filepath.Join("testdata", "single_plugin_with_separators.toml") + require.NoError(t, c.LoadConfig(confFile)) + + input := inputs.Inputs["memcached"]().(*MockupInputPlugin) + input.Servers = []string{"localhost"} + + filter := models.Filter{ + NameDrop: []string{"metricname2"}, + NameDropSeparators: ".", + NamePass: []string{"metricname1"}, + NamePassSeparators: ".", + FieldExclude: []string{"other", "stuff"}, + FieldInclude: []string{"some", "strings"}, + TagDropFilters: []models.TagFilter{ + { + Name: "badtag", + Values: []string{"othertag"}, + }, + }, + TagPassFilters: []models.TagFilter{ + { + Name: "goodtag", + Values: []string{"mytag"}, + }, + }, + } + require.NoError(t, filter.Compile()) + inputConfig := &models.InputConfig{ + Name: "memcached", + Source: confFile, + Filter: filter, + Interval: 5 * time.Second, + } + inputConfig.Tags = make(map[string]string) + + // Ignore Log, Parser and ID + c.Inputs[0].Input.(*MockupInputPlugin).Log = nil + c.Inputs[0].Input.(*MockupInputPlugin).parser = nil + c.Inputs[0].Config.ID = "" + require.Equal(t, input, c.Inputs[0].Input, "Testdata did not produce a correct memcached struct.") + require.Equal(t, inputConfig, c.Inputs[0].Config, "Testdata did not produce correct memcached metadata.") +} + +func TestConfig_LoadSingleInput_WithCommentInArray(t *testing.T) { + c := config.NewConfig() + require.NoError(t, c.LoadConfig("./testdata/single_plugin_with_comment_in_array.toml")) + require.Len(t, c.Inputs, 1) + + input := c.Inputs[0].Input.(*MockupInputPlugin) + require.ElementsMatch(t, input.Servers, []string{"localhost"}) +} + +func TestConfig_LoadDirectory(t *testing.T) { + c := config.NewConfig() + + files, err := config.WalkDirectory("./testdata/subconfig") + confFile := filepath.Join("testdata", "single_plugin.toml") + files = append([]string{confFile}, files...) + require.NoError(t, err) + require.NoError(t, c.LoadAll(files...)) + + // Create the expected data + expectedPlugins := make([]*MockupInputPlugin, 4) + expectedConfigs := make([]*models.InputConfig, 4) + + expectedPlugins[0] = inputs.Inputs["memcached"]().(*MockupInputPlugin) + expectedPlugins[0].Servers = []string{"localhost"} + + filterMockup := models.Filter{ + NameDrop: []string{"metricname2"}, + NamePass: []string{"metricname1"}, + FieldExclude: []string{"other", "stuff"}, + FieldInclude: []string{"some", "strings"}, + TagDropFilters: []models.TagFilter{ + { + Name: "badtag", + Values: []string{"othertag"}, + }, + }, + TagPassFilters: []models.TagFilter{ + { + Name: "goodtag", + Values: []string{"mytag"}, + }, + }, + } + require.NoError(t, filterMockup.Compile()) + expectedConfigs[0] = &models.InputConfig{ + Name: "memcached", + Source: confFile, + Filter: filterMockup, + Interval: 5 * time.Second, + } + expectedConfigs[0].Tags = make(map[string]string) + + expectedPlugins[1] = inputs.Inputs["exec"]().(*MockupInputPlugin) + parser := &json.Parser{ + MetricName: "exec", + Strict: true, + } + require.NoError(t, parser.Init()) + + expectedPlugins[1].SetParser(parser) + expectedPlugins[1].Command = "/usr/bin/myothercollector --foo=bar" + expectedConfigs[1] = &models.InputConfig{ + Name: "exec", + Source: filepath.Join("testdata", "subconfig", "exec.conf"), // This is the source of the input + MeasurementSuffix: "_myothercollector", + } + expectedConfigs[1].Tags = make(map[string]string) + + expectedPlugins[2] = inputs.Inputs["memcached"]().(*MockupInputPlugin) + expectedPlugins[2].Servers = []string{"192.168.1.1"} + + filterMemcached := models.Filter{ + NameDrop: []string{"metricname2"}, + NamePass: []string{"metricname1"}, + FieldExclude: []string{"other", "stuff"}, + FieldInclude: []string{"some", "strings"}, + TagDropFilters: []models.TagFilter{ + { + Name: "badtag", + Values: []string{"othertag"}, + }, + }, + TagPassFilters: []models.TagFilter{ + { + Name: "goodtag", + Values: []string{"mytag"}, + }, + }, + } + require.NoError(t, filterMemcached.Compile()) + expectedConfigs[2] = &models.InputConfig{ + Name: "memcached", + Source: filepath.Join("testdata", "subconfig", "memcached.conf"), // This is the source of the input + Filter: filterMemcached, + Interval: 5 * time.Second, + } + expectedConfigs[2].Tags = make(map[string]string) + + expectedPlugins[3] = inputs.Inputs["procstat"]().(*MockupInputPlugin) + expectedPlugins[3].PidFile = "/var/run/grafana-server.pid" + expectedConfigs[3] = &models.InputConfig{ + Name: "procstat", + Source: filepath.Join("testdata", "subconfig", "procstat.conf"), // This is the source of the input + } + expectedConfigs[3].Tags = make(map[string]string) + + // Check the generated plugins + require.Len(t, c.Inputs, len(expectedPlugins)) + require.Len(t, c.Inputs, len(expectedConfigs)) + for i, plugin := range c.Inputs { + input := plugin.Input.(*MockupInputPlugin) + // Check the logger and ignore it for comparison + require.NotNil(t, input.Log) + input.Log = nil + + // Check the parsers if any + if expectedPlugins[i].parser != nil { + runningParser, ok := input.parser.(*models.RunningParser) + require.True(t, ok) + + // We only use the JSON parser here + parser, ok := runningParser.Parser.(*json.Parser) + require.True(t, ok) + + // Prepare parser for comparison + require.NoError(t, parser.Init()) + parser.Log = nil + + // Compare the parser + require.Equalf(t, expectedPlugins[i].parser, parser, "Plugin %d: incorrect parser produced", i) + } + + // Ignore the parsers for further comparisons + input.parser = nil + expectedPlugins[i].parser = nil + + // Ignore the ID + plugin.Config.ID = "" + + require.Equalf(t, expectedPlugins[i], plugin.Input, "Plugin %d: incorrect struct produced", i) + require.Equalf(t, expectedConfigs[i], plugin.Config, "Plugin %d: incorrect config produced", i) + } +} + +func TestConfig_WrongCertPath(t *testing.T) { + c := config.NewConfig() + require.Error(t, c.LoadConfig("./testdata/wrong_cert_path.toml")) +} + +func TestConfig_DefaultParser(t *testing.T) { + c := config.NewConfig() + require.NoError(t, c.LoadConfig("./testdata/default_parser.toml")) +} + +func TestConfig_DefaultExecParser(t *testing.T) { + c := config.NewConfig() + require.NoError(t, c.LoadConfig("./testdata/default_parser_exec.toml")) +} + +func TestConfig_LoadSpecialTypes(t *testing.T) { + c := config.NewConfig() + require.NoError(t, c.LoadConfig("./testdata/special_types.toml")) + require.Len(t, c.Inputs, 1) + + input, ok := c.Inputs[0].Input.(*MockupInputPlugin) + require.True(t, ok) + // Tests telegraf config.Duration parsing. + require.Equal(t, config.Duration(time.Second), input.WriteTimeout) + // Tests telegraf size parsing. + require.Equal(t, config.Size(1024*1024), input.MaxBodySize) + // Tests toml multiline basic strings on single line. + require.Equal(t, "./testdata/special_types.pem", input.TLSCert) + // Tests toml multiline basic strings on single line. + require.Equal(t, "./testdata/special_types.key", input.TLSKey) + // Tests toml multiline basic strings on multiple lines. + require.Equal(t, "/path/", strings.TrimRight(input.Paths[0], "\r\n")) +} + +func TestConfig_DeprecatedFilters(t *testing.T) { + c := config.NewConfig() + require.NoError(t, c.LoadConfig("./testdata/deprecated_field_filter.toml")) + + require.Len(t, c.Inputs, 1) + require.Equal(t, []string{"foo", "bar", "baz"}, c.Inputs[0].Config.Filter.FieldInclude) + require.Equal(t, []string{"foo", "bar", "baz"}, c.Inputs[0].Config.Filter.FieldExclude) +} + +func TestConfig_FieldNotDefined(t *testing.T) { + tests := []struct { + name string + filename string + expected string + }{ + { + name: "in input plugin without parser", + filename: "./testdata/invalid_field.toml", + expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used; " + + "this is either a typo or this config option does not exist in this version", + }, + { + name: "in input plugin with parser", + filename: "./testdata/invalid_field_with_parser.toml", + expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used; " + + "this is either a typo or this config option does not exist in this version", + }, + { + name: "in input plugin with parser func", + filename: "./testdata/invalid_field_with_parserfunc.toml", + expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used; " + + "this is either a typo or this config option does not exist in this version", + }, + { + name: "in parser of input plugin", + filename: "./testdata/invalid_field_in_parser_table.toml", + expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used; " + + "this is either a typo or this config option does not exist in this version", + }, + { + name: "in parser of input plugin with parser-func", + filename: "./testdata/invalid_field_in_parserfunc_table.toml", + expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used; " + + "this is either a typo or this config option does not exist in this version", + }, + { + name: "in processor plugin without parser", + filename: "./testdata/invalid_field_processor.toml", + expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used; " + + "this is either a typo or this config option does not exist in this version", + }, + { + name: "in processor plugin with parser", + filename: "./testdata/invalid_field_processor_with_parser.toml", + expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used; " + + "this is either a typo or this config option does not exist in this version", + }, + { + name: "in processor plugin with parser func", + filename: "./testdata/invalid_field_processor_with_parserfunc.toml", + expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used; " + + "this is either a typo or this config option does not exist in this version", + }, + { + name: "in parser of processor plugin", + filename: "./testdata/invalid_field_processor_in_parser_table.toml", + expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used; " + + "this is either a typo or this config option does not exist in this version", + }, + { + name: "in parser of processor plugin with parser-func", + filename: "./testdata/invalid_field_processor_in_parserfunc_table.toml", + expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used; " + + "this is either a typo or this config option does not exist in this version", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := config.NewConfig() + err := c.LoadConfig(tt.filename) + require.ErrorContains(t, err, tt.expected) + }) + } +} + +func TestConfig_WrongFieldType(t *testing.T) { + c := config.NewConfig() + err := c.LoadConfig("./testdata/wrong_field_type.toml") + require.Error(t, err, "invalid field type") + require.ErrorContains(t, err, "cannot unmarshal TOML string into int") + + c = config.NewConfig() + err = c.LoadConfig("./testdata/wrong_field_type2.toml") + require.Error(t, err, "invalid field type2") + require.ErrorContains(t, err, "cannot unmarshal TOML string into []string") +} + +func TestConfig_InlineTables(t *testing.T) { + // #4098 + t.Setenv("TOKEN", "test") + + c := config.NewConfig() + require.NoError(t, c.LoadConfig("./testdata/inline_table.toml")) + require.Len(t, c.Outputs, 2) + + output, ok := c.Outputs[1].Output.(*MockupOutputPlugin) + require.True(t, ok) + require.Equal(t, map[string]string{"Authorization": "Token test", "Content-Type": "application/json"}, output.Headers) + require.Equal(t, []string{"org_id"}, c.Outputs[0].Config.Filter.TagInclude) +} + +func TestConfig_SliceComment(t *testing.T) { + c := config.NewConfig() + require.NoError(t, c.LoadConfig("./testdata/slice_comment.toml")) + require.Len(t, c.Outputs, 1) + + output, ok := c.Outputs[0].Output.(*MockupOutputPlugin) + require.True(t, ok) + require.Equal(t, []string{"test"}, output.Scopes) +} + +func TestConfig_BadOrdering(t *testing.T) { + // #3444: when not using inline tables, care has to be taken so subsequent configuration + // doesn't become part of the table. This is not a bug, but TOML syntax. + c := config.NewConfig() + err := c.LoadConfig("./testdata/non_slice_slice.toml") + require.Error(t, err, "bad ordering") + require.Equal( + t, + "loading config file ./testdata/non_slice_slice.toml failed: error parsing http array, line 4: cannot unmarshal TOML array into string (need slice)", + err.Error(), + ) +} + +func TestConfig_AzureMonitorNamespacePrefix(t *testing.T) { + // #8256 Cannot use empty string as the namespace prefix + c := config.NewConfig() + require.NoError(t, c.LoadConfig("./testdata/azure_monitor.toml")) + require.Len(t, c.Outputs, 2) + + expectedPrefix := []string{"Telegraf/", ""} + for i, plugin := range c.Outputs { + output, ok := plugin.Output.(*MockupOutputPlugin) + require.True(t, ok) + require.Equal(t, expectedPrefix[i], output.NamespacePrefix) + } +} + +func TestGetDefaultConfigPathFromEnvURL(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := w.Write([]byte("[agent]\ndebug = true")); err != nil { + w.WriteHeader(http.StatusInternalServerError) + t.Error(err) + return + } + })) + defer ts.Close() + + c := config.NewConfig() + t.Setenv("TELEGRAF_CONFIG_PATH", ts.URL) + configPath, err := config.GetDefaultConfigPath() + require.NoError(t, err) + require.Equal(t, []string{ts.URL}, configPath) + require.NoError(t, c.LoadConfig(configPath[0])) +} + +func TestConfig_URLLikeFileName(t *testing.T) { + c := config.NewConfig() + err := c.LoadConfig("http:##www.example.com.conf") + require.Error(t, err) + + if runtime.GOOS == "windows" { + // The error file not found error message is different on Windows + require.Equal( + t, + "loading config file http:##www.example.com.conf failed: open http:##www.example.com.conf: The system cannot find the file specified.", + err.Error(), + ) + } else { + require.Equal(t, "loading config file http:##www.example.com.conf failed: open http:##www.example.com.conf: no such file or directory", err.Error()) + } +} + +func TestConfig_Filtering(t *testing.T) { + c := config.NewConfig() + require.NoError(t, c.LoadAll("./testdata/filter_metricpass.toml")) + require.Len(t, c.Processors, 1) + + in := []telegraf.Metric{ + metric.New( + "machine", + map[string]string{"state": "on"}, + map[string]interface{}{"value": 42.0}, + time.Date(2023, time.April, 23, 01, 15, 30, 0, time.UTC), + ), + metric.New( + "machine", + map[string]string{"state": "off"}, + map[string]interface{}{"value": 23.0}, + time.Date(2023, time.April, 23, 23, 59, 01, 0, time.UTC), + ), + metric.New( + "temperature", + map[string]string{}, + map[string]interface{}{"value": 23.5}, + time.Date(2023, time.April, 24, 02, 15, 30, 0, time.UTC), + ), + } + expected := []telegraf.Metric{ + metric.New( + "machine", + map[string]string{ + "state": "on", + "processed": "yes", + }, + map[string]interface{}{"value": 42.0}, + time.Date(2023, time.April, 23, 01, 15, 30, 0, time.UTC), + ), + metric.New( + "machine", + map[string]string{"state": "off"}, + map[string]interface{}{"value": 23.0}, + time.Date(2023, time.April, 23, 23, 59, 01, 0, time.UTC), + ), + metric.New( + "temperature", + map[string]string{ + "processed": "yes", + }, + map[string]interface{}{"value": 23.5}, + time.Date(2023, time.April, 24, 02, 15, 30, 0, time.UTC), + ), + } + + plugin := c.Processors[0] + var acc testutil.Accumulator + for _, m := range in { + require.NoError(t, plugin.Add(m, &acc)) + } + actual := acc.GetTelegrafMetrics() + testutil.RequireMetricsEqual(t, expected, actual, testutil.SortMetrics()) +} + +func TestConfig_SerializerInterfaceNewFormat(t *testing.T) { + formats := []string{ + "carbon2", + "csv", + "graphite", + "influx", + "json", + "msgpack", + "nowmetric", + "prometheus", + "prometheusremotewrite", + "splunkmetric", + "wavefront", + } + + c := config.NewConfig() + require.NoError(t, c.LoadConfig("./testdata/serializers_new.toml")) + require.Len(t, c.Outputs, len(formats)) + + override := map[string]struct { + param map[string]interface{} + mask []string + }{} + + expected := make([]telegraf.Serializer, 0, len(formats)) + for _, format := range formats { + logger := logging.New("serializers", format, "test") + + var serializer telegraf.Serializer + if creator, found := serializers.Serializers[format]; found { + t.Logf("new-style %q", format) + serializer = creator() + } + + if settings, found := override[format]; found { + s := reflect.Indirect(reflect.ValueOf(serializer)) + for key, value := range settings.param { + v := reflect.ValueOf(value) + s.FieldByName(key).Set(v) + } + } + models.SetLoggerOnPlugin(serializer, logger) + if s, ok := serializer.(telegraf.Initializer); ok { + require.NoError(t, s.Init()) + } + expected = append(expected, serializer) + } + require.Len(t, expected, len(formats)) + + actual := make([]interface{}, 0) + for _, plugin := range c.Outputs { + output, ok := plugin.Output.(*MockupOutputPluginSerializerNew) + require.True(t, ok) + // Get the parser set with 'SetParser()' + if p, ok := output.Serializer.(*models.RunningSerializer); ok { + actual = append(actual, p.Serializer) + } else { + actual = append(actual, output.Serializer) + } + } + require.Len(t, actual, len(formats)) + + for i, format := range formats { + // Determine the underlying type of the serializer + stype := reflect.Indirect(reflect.ValueOf(expected[i])).Interface() + // Ignore all unexported fields and fields not relevant for functionality + options := []cmp.Option{ + cmpopts.IgnoreUnexported(stype), + cmpopts.IgnoreUnexported(reflect.Indirect(reflect.ValueOf(serializers_prometheus.MetricTypes{})).Interface()), + cmpopts.IgnoreTypes(sync.Mutex{}, regexp.Regexp{}), + cmpopts.IgnoreInterfaces(struct{ telegraf.Logger }{}), + } + if settings, found := override[format]; found { + options = append(options, cmpopts.IgnoreFields(stype, settings.mask...)) + } + + // Do a manual comparison as require.EqualValues will also work on unexported fields + // that cannot be cleared or ignored. + diff := cmp.Diff(expected[i], actual[i], options...) + require.Emptyf(t, diff, "Difference in SetSerializer() for %q", format) + } +} + +func TestConfig_ParserInterface(t *testing.T) { + formats := []string{ + "collectd", + "csv", + "dropwizard", + "form_urlencoded", + "graphite", + "grok", + "influx", + "json", + "json_v2", + "logfmt", + "nagios", + "prometheus", + "prometheusremotewrite", + "value", + "wavefront", + "xml", "xpath_json", "xpath_msgpack", "xpath_protobuf", + } + + c := config.NewConfig() + require.NoError(t, c.LoadConfig("./testdata/parsers_new.toml")) + require.Len(t, c.Inputs, len(formats)) + + override := map[string]struct { + param map[string]interface{} + mask []string + }{ + "csv": { + param: map[string]interface{}{ + "HeaderRowCount": 42, + }, + mask: []string{"TimeFunc", "ResetMode"}, + }, + "xpath_protobuf": { + param: map[string]interface{}{ + "ProtobufMessageDef": "testdata/addressbook.proto", + "ProtobufMessageType": "addressbook.AddressBook", + }, + }, + "json_v2": { + param: map[string]interface{}{ + "Configs": []json_v2.Config{{ + Fields: []json_v2.DataSet{{ + Path: "", + Type: "int", + Rename: "", + Optional: false, + }}, + }}, + }, + }, + } + + expected := make([]telegraf.Parser, 0, len(formats)) + for _, format := range formats { + logger := logging.New("parsers", format, "parser_test_new") + + creator, found := parsers.Parsers[format] + require.Truef(t, found, "No parser for format %q", format) + + parser := creator("parser_test_new") + if settings, found := override[format]; found { + s := reflect.Indirect(reflect.ValueOf(parser)) + for key, value := range settings.param { + v := reflect.ValueOf(value) + s.FieldByName(key).Set(v) + } + } + models.SetLoggerOnPlugin(parser, logger) + if p, ok := parser.(telegraf.Initializer); ok { + require.NoError(t, p.Init()) + } + expected = append(expected, parser) + } + require.Len(t, expected, len(formats)) + + actual := make([]interface{}, 0) + generated := make([]interface{}, 0) + for _, plugin := range c.Inputs { + input, ok := plugin.Input.(*MockupInputPluginParserNew) + require.True(t, ok) + // Get the parser set with 'SetParser()' + if p, ok := input.Parser.(*models.RunningParser); ok { + actual = append(actual, p.Parser) + } else { + actual = append(actual, input.Parser) + } + // Get the parser set with 'SetParserFunc()' + g, err := input.ParserFunc() + require.NoError(t, err) + if rp, ok := g.(*models.RunningParser); ok { + generated = append(generated, rp.Parser) + } else { + generated = append(generated, g) + } + } + require.Len(t, actual, len(formats)) + + for i, format := range formats { + // Determine the underlying type of the parser + stype := reflect.Indirect(reflect.ValueOf(expected[i])).Interface() + // Ignore all unexported fields and fields not relevant for functionality + options := []cmp.Option{ + cmpopts.IgnoreUnexported(stype), + cmpopts.IgnoreTypes(sync.Mutex{}), + cmpopts.IgnoreInterfaces(struct{ telegraf.Logger }{}), + } + if settings, found := override[format]; found { + options = append(options, cmpopts.IgnoreFields(stype, settings.mask...)) + } + + // Do a manual comparison as require.EqualValues will also work on unexported fields + // that cannot be cleared or ignored. + diff := cmp.Diff(expected[i], actual[i], options...) + require.Emptyf(t, diff, "Difference in SetParser() for %q", format) + diff = cmp.Diff(expected[i], generated[i], options...) + require.Emptyf(t, diff, "Difference in SetParserFunc() for %q", format) + } +} + +func TestConfig_MultipleProcessorsOrder(t *testing.T) { + tests := []struct { + name string + filename []string + expectedOrder []string + }{ + { + name: "Test the order of multiple unique processosr", + filename: []string{"multiple_processors.toml"}, + expectedOrder: []string{ + "processor", + "parser_test", + "processor_parser", + "processor_parserfunc", + }, + }, + { + name: "Test using a single 'order' configuration", + filename: []string{"multiple_processors_simple_order.toml"}, + expectedOrder: []string{ + "parser_test", + "processor_parser", + "processor_parserfunc", + "processor", + }, + }, + { + name: "Test using multiple 'order' configurations", + filename: []string{"multiple_processors_messy_order.toml"}, + expectedOrder: []string{ + "parser_test", + "processor_parserfunc", + "processor", + "processor_parser", + "processor_parser", + "processor_parserfunc", + }, + }, + { + name: "Test loading multiple configuration files", + filename: []string{ + "multiple_processors.toml", + "multiple_processors_simple_order.toml", + }, + expectedOrder: []string{ + "processor", + "parser_test", + "processor_parser", + "processor_parserfunc", + "parser_test", + "processor_parser", + "processor_parserfunc", + "processor", + }, + }, + { + name: "Test loading multiple configuration files both with order", + filename: []string{ + "multiple_processors_simple_order.toml", + "multiple_processors_messy_order.toml", + }, + expectedOrder: []string{ + "parser_test", + "processor_parser", + "processor_parserfunc", + "parser_test", + "processor_parserfunc", + "processor", + "processor", + "processor_parser", + "processor_parser", + "processor_parserfunc", + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + c := config.NewConfig() + filenames := make([]string, 0, len(test.filename)) + for _, fn := range test.filename { + filenames = append(filenames, filepath.Join(".", "testdata", "processor_order", fn)) + } + require.NoError(t, c.LoadAll(filenames...)) + + require.Len(t, c.Processors, len(test.expectedOrder)) + + var order []string + for _, p := range c.Processors { + order = append(order, p.Config.Name) + } + + require.Equal(t, test.expectedOrder, order) + }) + } +} + +func TestConfig_ProcessorsWithParsers(t *testing.T) { + formats := []string{ + "collectd", + "csv", + "dropwizard", + "form_urlencoded", + "graphite", + "grok", + "influx", + "json", + "json_v2", + "logfmt", + "nagios", + "prometheus", + "prometheusremotewrite", + "value", + "wavefront", + "xml", "xpath_json", "xpath_msgpack", "xpath_protobuf", + } + + c := config.NewConfig() + require.NoError(t, c.LoadAll("./testdata/processors_with_parsers.toml")) + require.Len(t, c.Processors, len(formats)) + + override := map[string]struct { + param map[string]interface{} + mask []string + }{ + "csv": { + param: map[string]interface{}{ + "HeaderRowCount": 42, + }, + mask: []string{"TimeFunc", "ResetMode"}, + }, + "xpath_protobuf": { + param: map[string]interface{}{ + "ProtobufMessageDef": "testdata/addressbook.proto", + "ProtobufMessageType": "addressbook.AddressBook", + }, + }, + "json_v2": { + param: map[string]interface{}{ + "Configs": []json_v2.Config{{ + Fields: []json_v2.DataSet{{ + Path: "", + Type: "int", + Rename: "", + Optional: false, + }}, + }}, + }, + }, + } + + expected := make([]telegraf.Parser, 0, len(formats)) + for _, format := range formats { + logger := logging.New("parsers", format, "processors_with_parsers") + + creator, found := parsers.Parsers[format] + require.Truef(t, found, "No parser for format %q", format) + + parser := creator("parser_test") + if settings, found := override[format]; found { + s := reflect.Indirect(reflect.ValueOf(parser)) + for key, value := range settings.param { + v := reflect.ValueOf(value) + s.FieldByName(key).Set(v) + } + } + models.SetLoggerOnPlugin(parser, logger) + if p, ok := parser.(telegraf.Initializer); ok { + require.NoError(t, p.Init()) + } + expected = append(expected, parser) + } + require.Len(t, expected, len(formats)) + + actual := make([]interface{}, 0) + generated := make([]interface{}, 0) + for _, plugin := range c.Processors { + var processorIF telegraf.Processor + if p, ok := plugin.Processor.(processors.HasUnwrap); ok { + processorIF = p.Unwrap() + } else { + processorIF = plugin.Processor.(telegraf.Processor) + } + require.NotNil(t, processorIF) + + processor, ok := processorIF.(*MockupProcessorPluginParser) + require.True(t, ok) + + // Get the parser set with 'SetParser()' + if p, ok := processor.Parser.(*models.RunningParser); ok { + actual = append(actual, p.Parser) + } else { + actual = append(actual, processor.Parser) + } + // Get the parser set with 'SetParserFunc()' + if processor.ParserFunc != nil { + g, err := processor.ParserFunc() + require.NoError(t, err) + if rp, ok := g.(*models.RunningParser); ok { + generated = append(generated, rp.Parser) + } else { + generated = append(generated, g) + } + } else { + generated = append(generated, nil) + } + } + require.Len(t, actual, len(formats)) + + for i, format := range formats { + // Determine the underlying type of the parser + stype := reflect.Indirect(reflect.ValueOf(expected[i])).Interface() + // Ignore all unexported fields and fields not relevant for functionality + options := []cmp.Option{ + cmpopts.IgnoreUnexported(stype), + cmpopts.IgnoreTypes(sync.Mutex{}), + cmpopts.IgnoreInterfaces(struct{ telegraf.Logger }{}), + } + if settings, found := override[format]; found { + options = append(options, cmpopts.IgnoreFields(stype, settings.mask...)) + } + + // Do a manual comparison as require.EqualValues will also work on unexported fields + // that cannot be cleared or ignored. + diff := cmp.Diff(expected[i], actual[i], options...) + require.Emptyf(t, diff, "Difference in SetParser() for %q", format) + diff = cmp.Diff(expected[i], generated[i], options...) + require.Emptyf(t, diff, "Difference in SetParserFunc() for %q", format) + } +} + +func TestConfigPluginIDsDifferent(t *testing.T) { + c := config.NewConfig() + c.Agent.Statefile = "/dev/null" + require.NoError(t, c.LoadConfig("./testdata/state_persistence_input_all_different.toml")) + require.NotEmpty(t, c.Inputs) + + // Compare generated IDs + for i, pi := range c.Inputs { + refid := pi.Config.ID + require.NotEmpty(t, refid) + + // Cross-comparison + for j, pj := range c.Inputs { + testid := pj.Config.ID + if i == j { + require.Equal(t, refid, testid) + continue + } + require.NotEqualf(t, refid, testid, "equal for %d, %d", i, j) + } + } +} + +func TestConfigPluginIDsSame(t *testing.T) { + c := config.NewConfig() + c.Agent.Statefile = "/dev/null" + require.NoError(t, c.LoadConfig("./testdata/state_persistence_input_all_same.toml")) + require.NotEmpty(t, c.Inputs) + + // Compare generated IDs + for i, pi := range c.Inputs { + refid := pi.Config.ID + require.NotEmpty(t, refid) + + // Cross-comparison + for j, pj := range c.Inputs { + testid := pj.Config.ID + require.Equal(t, refid, testid, "not equal for %d, %d", i, j) + } + } +} + +func TestPersisterInputStoreLoad(t *testing.T) { + // Reserve a temporary state file + file, err := os.CreateTemp(t.TempDir(), "telegraf_state-*.json") + require.NoError(t, err) + filename := file.Name() + require.NoError(t, file.Close()) + + // Load the plugins + cstore := config.NewConfig() + require.NoError(t, cstore.LoadConfig("testdata/state_persistence_input_store_load.toml")) + + // Initialize the persister for storing the state + persisterStore := persister.Persister{ + Filename: filename, + } + require.NoError(t, persisterStore.Init()) + + expected := make(map[string]interface{}) + for i, plugin := range cstore.Inputs { + require.NoError(t, plugin.Init()) + + // Register + p := plugin.Input.(*MockupStatePlugin) + require.NoError(t, persisterStore.Register(plugin.ID(), p)) + + // Change the state + p.state.Name += "_" + strings.Repeat("a", i+1) + p.state.Version++ + p.state.Offset += uint64(i + 1) + p.state.Bits = append(p.state.Bits, len(p.state.Bits)) + p.state.Modified, err = time.Parse(time.RFC3339, "2022-11-03T16:49:00+02:00") + require.NoError(t, err) + + // Store the state for later comparison + expected[plugin.ID()] = p.GetState() + } + + // Write state + require.NoError(t, persisterStore.Store()) + + // Load the plugins + cload := config.NewConfig() + require.NoError(t, cload.LoadConfig("testdata/state_persistence_input_store_load.toml")) + require.Len(t, cload.Inputs, len(expected)) + + // Initialize the persister for loading the state + persisterLoad := persister.Persister{ + Filename: filename, + } + require.NoError(t, persisterLoad.Init()) + + for _, plugin := range cload.Inputs { + require.NoError(t, plugin.Init()) + + // Register + p := plugin.Input.(*MockupStatePlugin) + require.NoError(t, persisterLoad.Register(plugin.ID(), p)) + + // Check that the states are not yet restored + require.NotNil(t, expected[plugin.ID()]) + require.NotEqual(t, expected[plugin.ID()], p.GetState()) + } + + // Restore states + require.NoError(t, persisterLoad.Load()) + + // Check we got what we saved. + for _, plugin := range cload.Inputs { + p := plugin.Input.(*MockupStatePlugin) + require.Equal(t, expected[plugin.ID()], p.GetState()) + } +} + +func TestPersisterProcessorRegistration(t *testing.T) { + // Load the plugins + c := config.NewConfig() + require.NoError(t, c.LoadConfig("testdata/state_persistence_processors.toml")) + require.NotEmpty(t, c.Processors) + require.NotEmpty(t, c.AggProcessors) + + // Initialize the persister for test + dut := persister.Persister{ + Filename: "/tmp/doesn_t_matter.json", + } + require.NoError(t, dut.Init()) + + // Register the processors + for _, plugin := range c.Processors { + unwrapped := plugin.Processor.(processors.HasUnwrap).Unwrap() + + p := unwrapped.(*MockupProcessorPlugin) + require.NoError(t, dut.Register(plugin.ID(), p)) + } + + // Register the after-aggregator processors + for _, plugin := range c.AggProcessors { + unwrapped := plugin.Processor.(processors.HasUnwrap).Unwrap() + + p := unwrapped.(*MockupProcessorPlugin) + require.NoError(t, dut.Register(plugin.ID(), p)) + } +} + +// Mockup INPUT plugin for (new) parser testing to avoid cyclic dependencies +type MockupInputPluginParserNew struct { + Parser telegraf.Parser + ParserFunc telegraf.ParserFunc +} + +func (*MockupInputPluginParserNew) SampleConfig() string { + return "Mockup old parser test plugin" +} +func (*MockupInputPluginParserNew) Gather(telegraf.Accumulator) error { + return nil +} +func (m *MockupInputPluginParserNew) SetParser(parser telegraf.Parser) { + m.Parser = parser +} +func (m *MockupInputPluginParserNew) SetParserFunc(f telegraf.ParserFunc) { + m.ParserFunc = f +} + +// Mockup INPUT plugin for testing to avoid cyclic dependencies +type MockupInputPlugin struct { + Servers []string `toml:"servers"` + Methods []string `toml:"methods"` + Timeout config.Duration `toml:"timeout"` + ReadTimeout config.Duration `toml:"read_timeout"` + WriteTimeout config.Duration `toml:"write_timeout"` + MaxBodySize config.Size `toml:"max_body_size"` + Paths []string `toml:"paths"` + Port int `toml:"port"` + Password config.Secret `toml:"password"` + Command string + Files []string + PidFile string + Log telegraf.Logger `toml:"-"` + tls.ServerConfig + + parser telegraf.Parser +} + +func (*MockupInputPlugin) SampleConfig() string { + return "Mockup test input plugin" +} +func (*MockupInputPlugin) Gather(telegraf.Accumulator) error { + return nil +} +func (m *MockupInputPlugin) SetParser(parser telegraf.Parser) { + m.parser = parser +} + +// Mockup INPUT plugin with ParserFunc interface +type MockupInputPluginParserFunc struct { + parserFunc telegraf.ParserFunc +} + +func (*MockupInputPluginParserFunc) SampleConfig() string { + return "Mockup test input plugin" +} +func (*MockupInputPluginParserFunc) Gather(telegraf.Accumulator) error { + return nil +} +func (m *MockupInputPluginParserFunc) SetParserFunc(pf telegraf.ParserFunc) { + m.parserFunc = pf +} + +// Mockup INPUT plugin without ParserFunc interface +type MockupInputPluginParserOnly struct { + parser telegraf.Parser +} + +func (*MockupInputPluginParserOnly) SampleConfig() string { + return "Mockup test input plugin" +} +func (*MockupInputPluginParserOnly) Gather(telegraf.Accumulator) error { + return nil +} +func (m *MockupInputPluginParserOnly) SetParser(p telegraf.Parser) { + m.parser = p +} + +// Mockup PROCESSOR plugin for testing to avoid cyclic dependencies +type MockupProcessorPluginParser struct { + Parser telegraf.Parser + ParserFunc telegraf.ParserFunc +} + +func (*MockupProcessorPluginParser) Start(telegraf.Accumulator) error { + return nil +} +func (*MockupProcessorPluginParser) Stop() { +} +func (*MockupProcessorPluginParser) SampleConfig() string { + return "Mockup test processor plugin with parser" +} +func (*MockupProcessorPluginParser) Apply(...telegraf.Metric) []telegraf.Metric { + return nil +} +func (*MockupProcessorPluginParser) Add(telegraf.Metric, telegraf.Accumulator) error { + return nil +} +func (m *MockupProcessorPluginParser) SetParser(parser telegraf.Parser) { + m.Parser = parser +} +func (m *MockupProcessorPluginParser) SetParserFunc(f telegraf.ParserFunc) { + m.ParserFunc = f +} + +// Mockup PROCESSOR plugin without parser +type MockupProcessorPlugin struct { + Option string `toml:"option"` + state []uint64 +} + +func (*MockupProcessorPlugin) SampleConfig() string { + return "Mockup test processor plugin with parser" +} +func (*MockupProcessorPlugin) Apply(in ...telegraf.Metric) []telegraf.Metric { + out := make([]telegraf.Metric, 0, len(in)) + for _, m := range in { + m.AddTag("processed", "yes") + out = append(out, m) + } + return out +} +func (m *MockupProcessorPlugin) GetState() interface{} { + return m.state +} +func (m *MockupProcessorPlugin) SetState(state interface{}) error { + s, ok := state.([]uint64) + if !ok { + return fmt.Errorf("invalid state type %T", state) + } + m.state = s + + return nil +} + +// Mockup PROCESSOR plugin with parser +type MockupProcessorPluginParserOnly struct { + Parser telegraf.Parser +} + +func (*MockupProcessorPluginParserOnly) Start(telegraf.Accumulator) error { + return nil +} +func (*MockupProcessorPluginParserOnly) Stop() { +} +func (*MockupProcessorPluginParserOnly) SampleConfig() string { + return "Mockup test processor plugin with parser" +} +func (*MockupProcessorPluginParserOnly) Apply(...telegraf.Metric) []telegraf.Metric { + return nil +} +func (*MockupProcessorPluginParserOnly) Add(telegraf.Metric, telegraf.Accumulator) error { + return nil +} +func (m *MockupProcessorPluginParserOnly) SetParser(parser telegraf.Parser) { + m.Parser = parser +} + +// Mockup PROCESSOR plugin with parser-function +type MockupProcessorPluginParserFunc struct { + Parser telegraf.ParserFunc +} + +func (*MockupProcessorPluginParserFunc) Start(telegraf.Accumulator) error { + return nil +} +func (*MockupProcessorPluginParserFunc) Stop() { +} +func (*MockupProcessorPluginParserFunc) SampleConfig() string { + return "Mockup test processor plugin with parser" +} +func (*MockupProcessorPluginParserFunc) Apply(...telegraf.Metric) []telegraf.Metric { + return nil +} +func (*MockupProcessorPluginParserFunc) Add(telegraf.Metric, telegraf.Accumulator) error { + return nil +} +func (m *MockupProcessorPluginParserFunc) SetParserFunc(pf telegraf.ParserFunc) { + m.Parser = pf +} + +// Mockup OUTPUT plugin for testing to avoid cyclic dependencies +type MockupOutputPlugin struct { + URL string `toml:"url"` + Headers map[string]string `toml:"headers"` + Scopes []string `toml:"scopes"` + NamespacePrefix string `toml:"namespace_prefix"` + Log telegraf.Logger `toml:"-"` + tls.ClientConfig +} + +func (*MockupOutputPlugin) Connect() error { + return nil +} +func (*MockupOutputPlugin) Close() error { + return nil +} +func (*MockupOutputPlugin) SampleConfig() string { + return "Mockup test output plugin" +} +func (*MockupOutputPlugin) Write([]telegraf.Metric) error { + return nil +} + +type MockupOutputPluginSerializerNew struct { + Serializer telegraf.Serializer +} + +func (m *MockupOutputPluginSerializerNew) SetSerializer(s telegraf.Serializer) { + m.Serializer = s +} +func (*MockupOutputPluginSerializerNew) Connect() error { + return nil +} +func (*MockupOutputPluginSerializerNew) Close() error { + return nil +} +func (*MockupOutputPluginSerializerNew) SampleConfig() string { + return "Mockup test output plugin" +} +func (*MockupOutputPluginSerializerNew) Write(_ []telegraf.Metric) error { + return nil +} + +// Mockup INPUT plugin with state for testing to avoid cyclic dependencies +type MockupState struct { + Name string + Version uint64 + Offset uint64 + Bits []int + Modified time.Time +} + +type MockupStatePluginSettings struct { + Name string `toml:"name"` + Factor float64 `toml:"factor"` + Enabled bool `toml:"enabled"` + BitField []int `toml:"bits"` +} + +type MockupStatePlugin struct { + Servers []string `toml:"servers"` + Method string `toml:"method"` + Settings map[string]string `toml:"params"` + Port int `toml:"port"` + Setups []MockupStatePluginSettings `toml:"setup"` + state MockupState +} + +func (m *MockupStatePlugin) Init() error { + t0, err := time.Parse(time.RFC3339, "2021-04-24T23:42:00+02:00") + if err != nil { + return err + } + m.state = MockupState{ + Name: "mockup", + Modified: t0, + } + + return nil +} + +func (m *MockupStatePlugin) GetState() interface{} { + return m.state +} + +func (m *MockupStatePlugin) SetState(state interface{}) error { + s, ok := state.(MockupState) + if !ok { + return fmt.Errorf("invalid state type %T", state) + } + m.state = s + + return nil +} + +func (*MockupStatePlugin) SampleConfig() string { + return "Mockup test plugin" +} + +func (*MockupStatePlugin) Gather(telegraf.Accumulator) error { + return nil +} + +// Register the mockup plugin on loading +func init() { + // Register the mockup input plugin for the required names + inputs.Add("parser_test_new", func() telegraf.Input { + return &MockupInputPluginParserNew{} + }) + inputs.Add("parser", func() telegraf.Input { + return &MockupInputPluginParserOnly{} + }) + inputs.Add("parser_func", func() telegraf.Input { + return &MockupInputPluginParserFunc{} + }) + inputs.Add("exec", func() telegraf.Input { + return &MockupInputPlugin{Timeout: config.Duration(time.Second * 5)} + }) + inputs.Add("file", func() telegraf.Input { + return &MockupInputPlugin{} + }) + inputs.Add("http_listener_v2", func() telegraf.Input { + return &MockupInputPlugin{} + }) + inputs.Add("memcached", func() telegraf.Input { + return &MockupInputPlugin{} + }) + inputs.Add("procstat", func() telegraf.Input { + return &MockupInputPlugin{} + }) + inputs.Add("statetest", func() telegraf.Input { + return &MockupStatePlugin{} + }) + + // Register the mockup processor plugin for the required names + processors.Add("parser_test", func() telegraf.Processor { + return &MockupProcessorPluginParser{} + }) + processors.Add("processor", func() telegraf.Processor { + return &MockupProcessorPlugin{} + }) + processors.Add("processor_parser", func() telegraf.Processor { + return &MockupProcessorPluginParserOnly{} + }) + processors.Add("processor_parserfunc", func() telegraf.Processor { + return &MockupProcessorPluginParserFunc{} + }) + processors.Add("statetest", func() telegraf.Processor { + return &MockupProcessorPlugin{} + }) + + // Register the mockup output plugin for the required names + outputs.Add("azure_monitor", func() telegraf.Output { + return &MockupOutputPlugin{NamespacePrefix: "Telegraf/"} + }) + outputs.Add("http", func() telegraf.Output { + return &MockupOutputPlugin{} + }) + outputs.Add("serializer_test_new", func() telegraf.Output { + return &MockupOutputPluginSerializerNew{} + }) +} diff --git a/config/deprecation.go b/config/deprecation.go new file mode 100644 index 0000000..2035d5a --- /dev/null +++ b/config/deprecation.go @@ -0,0 +1,393 @@ +package config + +import ( + "errors" + "fmt" + "log" + "reflect" + "sort" + "strings" + + "github.com/coreos/go-semver/semver" + "github.com/fatih/color" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/aggregators" + "github.com/influxdata/telegraf/plugins/inputs" + "github.com/influxdata/telegraf/plugins/outputs" + "github.com/influxdata/telegraf/plugins/processors" +) + +// DeprecationInfo contains all important information to describe a deprecated entity +type DeprecationInfo struct { + // Name of the plugin or plugin option + Name string + // LogLevel is the level of deprecation which currently corresponds to a log-level + logLevel telegraf.LogLevel + info telegraf.DeprecationInfo +} + +func (di *DeprecationInfo) determineEscalation() error { + di.logLevel = telegraf.None + if di.info.Since == "" { + return nil + } + + since, err := semver.NewVersion(di.info.Since) + if err != nil { + return fmt.Errorf("cannot parse 'since' version %q: %w", di.info.Since, err) + } + + var removal *semver.Version + if di.info.RemovalIn != "" { + removal, err = semver.NewVersion(di.info.RemovalIn) + if err != nil { + return fmt.Errorf("cannot parse 'removal' version %q: %w", di.info.RemovalIn, err) + } + } else { + removal = &semver.Version{Major: since.Major} + removal.BumpMajor() + di.info.RemovalIn = removal.String() + } + + // Drop potential pre-release tags + version := semver.Version{ + Major: telegrafVersion.Major, + Minor: telegrafVersion.Minor, + Patch: telegrafVersion.Patch, + } + if !version.LessThan(*removal) { + di.logLevel = telegraf.Error + } else if !version.LessThan(*since) { + di.logLevel = telegraf.Warn + } + return nil +} + +// PluginDeprecationInfo holds all information about a deprecated plugin or it's options +type PluginDeprecationInfo struct { + DeprecationInfo + + // Options deprecated for this plugin + Options []DeprecationInfo +} + +func (c *Config) incrementPluginDeprecations(category string) { + newcounts := []int64{1, 0} + if counts, found := c.Deprecations[category]; found { + newcounts = []int64{counts[0] + 1, counts[1]} + } + c.Deprecations[category] = newcounts +} + +func (c *Config) incrementPluginOptionDeprecations(category string) { + newcounts := []int64{0, 1} + if counts, found := c.Deprecations[category]; found { + newcounts = []int64{counts[0], counts[1] + 1} + } + c.Deprecations[category] = newcounts +} + +func (c *Config) collectDeprecationInfo(category, name string, plugin interface{}, all bool) PluginDeprecationInfo { + info := PluginDeprecationInfo{ + DeprecationInfo: DeprecationInfo{ + Name: category + "." + name, + logLevel: telegraf.None, + }, + } + + // First check if the whole plugin is deprecated + switch category { + case "aggregators": + if pi, deprecated := aggregators.Deprecations[name]; deprecated { + info.DeprecationInfo.info = pi + } + case "inputs": + if pi, deprecated := inputs.Deprecations[name]; deprecated { + info.DeprecationInfo.info = pi + } + case "outputs": + if pi, deprecated := outputs.Deprecations[name]; deprecated { + info.DeprecationInfo.info = pi + } + case "processors": + if pi, deprecated := processors.Deprecations[name]; deprecated { + info.DeprecationInfo.info = pi + } + } + if err := info.determineEscalation(); err != nil { + panic(fmt.Errorf("plugin %q: %w", info.Name, err)) + } + if info.logLevel != telegraf.None { + c.incrementPluginDeprecations(category) + } + + // Allow checking for names only. + if plugin == nil { + return info + } + + // Check for deprecated options + walkPluginStruct(reflect.ValueOf(plugin), func(field reflect.StructField, value reflect.Value) { + // Try to report only those fields that are set + if !all && value.IsZero() { + return + } + + tags := strings.SplitN(field.Tag.Get("deprecated"), ";", 3) + if len(tags) < 1 || tags[0] == "" { + return + } + optionInfo := DeprecationInfo{Name: field.Name} + optionInfo.info.Since = tags[0] + + if len(tags) > 1 { + optionInfo.info.Notice = tags[len(tags)-1] + } + if len(tags) > 2 { + optionInfo.info.RemovalIn = tags[1] + } + if err := optionInfo.determineEscalation(); err != nil { + panic(fmt.Errorf("plugin %q option %q: %w", info.Name, field.Name, err)) + } + + if optionInfo.logLevel != telegraf.None { + c.incrementPluginOptionDeprecations(category) + } + + // Get the toml field name + option := field.Tag.Get("toml") + if option != "" { + optionInfo.Name = option + } + info.Options = append(info.Options, optionInfo) + }) + + return info +} + +func (c *Config) printUserDeprecation(category, name string, plugin interface{}) error { + info := c.collectDeprecationInfo(category, name, plugin, false) + printPluginDeprecationNotice(info.logLevel, info.Name, info.info) + + if info.logLevel == telegraf.Error { + return errors.New("plugin deprecated") + } + + // Print deprecated options + deprecatedOptions := make([]string, 0) + for _, option := range info.Options { + PrintOptionDeprecationNotice(info.Name, option.Name, option.info) + if option.logLevel == telegraf.Error { + deprecatedOptions = append(deprecatedOptions, option.Name) + } + } + + if len(deprecatedOptions) > 0 { + return fmt.Errorf("plugin options %q deprecated", strings.Join(deprecatedOptions, ",")) + } + + return nil +} + +func (c *Config) CollectDeprecationInfos(inFilter, outFilter, aggFilter, procFilter []string) map[string][]PluginDeprecationInfo { + infos := make(map[string][]PluginDeprecationInfo) + + infos["inputs"] = make([]PluginDeprecationInfo, 0) + for name, creator := range inputs.Inputs { + if len(inFilter) > 0 && !sliceContains(name, inFilter) { + continue + } + + plugin := creator() + info := c.collectDeprecationInfo("inputs", name, plugin, true) + + if info.logLevel != telegraf.None || len(info.Options) > 0 { + infos["inputs"] = append(infos["inputs"], info) + } + } + + infos["outputs"] = make([]PluginDeprecationInfo, 0) + for name, creator := range outputs.Outputs { + if len(outFilter) > 0 && !sliceContains(name, outFilter) { + continue + } + + plugin := creator() + info := c.collectDeprecationInfo("outputs", name, plugin, true) + + if info.logLevel != telegraf.None || len(info.Options) > 0 { + infos["outputs"] = append(infos["outputs"], info) + } + } + + infos["processors"] = make([]PluginDeprecationInfo, 0) + for name, creator := range processors.Processors { + if len(procFilter) > 0 && !sliceContains(name, procFilter) { + continue + } + + plugin := creator() + info := c.collectDeprecationInfo("processors", name, plugin, true) + + if info.logLevel != telegraf.None || len(info.Options) > 0 { + infos["processors"] = append(infos["processors"], info) + } + } + + infos["aggregators"] = make([]PluginDeprecationInfo, 0) + for name, creator := range aggregators.Aggregators { + if len(aggFilter) > 0 && !sliceContains(name, aggFilter) { + continue + } + + plugin := creator() + info := c.collectDeprecationInfo("aggregators", name, plugin, true) + + if info.logLevel != telegraf.None || len(info.Options) > 0 { + infos["aggregators"] = append(infos["aggregators"], info) + } + } + + return infos +} + +func (*Config) PrintDeprecationList(plugins []PluginDeprecationInfo) { + sort.Slice(plugins, func(i, j int) bool { return plugins[i].Name < plugins[j].Name }) + + for _, plugin := range plugins { + switch plugin.logLevel { + case telegraf.Warn, telegraf.Error: + fmt.Printf( + " %-40s %-5s since %-5s removal in %-5s %s\n", + plugin.Name, plugin.logLevel, plugin.info.Since, plugin.info.RemovalIn, plugin.info.Notice, + ) + } + + if len(plugin.Options) < 1 { + continue + } + sort.Slice(plugin.Options, func(i, j int) bool { return plugin.Options[i].Name < plugin.Options[j].Name }) + for _, option := range plugin.Options { + fmt.Printf( + " %-40s %-5s since %-5s removal in %-5s %s\n", + plugin.Name+"/"+option.Name, option.logLevel, option.info.Since, option.info.RemovalIn, option.info.Notice, + ) + } + } +} + +func printHistoricPluginDeprecationNotice(category, name string, info telegraf.DeprecationInfo) { + prefix := "E! " + color.RedString("DeprecationError") + log.Printf( + "%s: Plugin %q deprecated since version %s and removed: %s", + prefix, category+"."+name, info.Since, info.Notice, + ) +} + +// walkPluginStruct iterates over the fields of a structure in depth-first search (to cover nested structures) +// and calls the given function for every visited field. +func walkPluginStruct(value reflect.Value, fn func(f reflect.StructField, fv reflect.Value)) { + v := reflect.Indirect(value) + t := v.Type() + + // Only works on structs + if t.Kind() != reflect.Struct { + return + } + + // Walk over the struct fields and call the given function. If we encounter more complex embedded + // elements (structs, slices/arrays, maps) we need to descend into those elements as they might + // contain structures nested in the current structure. + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + fieldValue := v.Field(i) + + if field.PkgPath != "" { + continue + } + switch field.Type.Kind() { + case reflect.Struct: + walkPluginStruct(fieldValue, fn) + case reflect.Array, reflect.Slice: + for j := 0; j < fieldValue.Len(); j++ { + element := fieldValue.Index(j) + // The array might contain structs + walkPluginStruct(element, fn) + fn(field, element) + } + case reflect.Map: + iter := fieldValue.MapRange() + for iter.Next() { + element := iter.Value() + // The map might contain structs + walkPluginStruct(element, fn) + fn(field, element) + } + } + fn(field, fieldValue) + } +} + +func deprecationPrefix(level telegraf.LogLevel) string { + switch level { + case telegraf.Warn: + return "W! " + color.YellowString("DeprecationWarning") + case telegraf.Error: + return "E! " + color.RedString("DeprecationError") + } + return "" +} + +func printPluginDeprecationNotice(level telegraf.LogLevel, name string, info telegraf.DeprecationInfo) { + switch level { + case telegraf.Warn, telegraf.Error: + prefix := deprecationPrefix(level) + log.Printf( + "%s: Plugin %q deprecated since version %s and will be removed in %s: %s", + prefix, name, info.Since, info.RemovalIn, info.Notice, + ) + } +} + +func PrintOptionDeprecationNotice(plugin, option string, info telegraf.DeprecationInfo) { + // Determine the log-level + di := &DeprecationInfo{ + Name: plugin, + info: info, + } + if err := di.determineEscalation(); err != nil { + log.Printf("E! Determining log-level for option %s in plugin %s failed: %v", option, plugin, err) + return + } + + switch di.logLevel { + case telegraf.Warn, telegraf.Error: + prefix := deprecationPrefix(di.logLevel) + log.Printf( + "%s: Option %q of plugin %q deprecated since version %s and will be removed in %s: %s", + prefix, option, plugin, di.info.Since, di.info.RemovalIn, di.info.Notice, + ) + } +} + +func PrintOptionValueDeprecationNotice(plugin, option string, value interface{}, info telegraf.DeprecationInfo) { + // Determine the log-level + di := &DeprecationInfo{ + Name: plugin, + info: info, + } + if err := di.determineEscalation(); err != nil { + log.Printf("E! Determining log-level for option %s in plugin %s failed: %v", option, plugin, err) + return + } + + switch di.logLevel { + case telegraf.Warn, telegraf.Error: + prefix := deprecationPrefix(di.logLevel) + log.Printf( + `%s: Value "%+v" for option %q of plugin %q deprecated since version %s and will be removed in %s: %s`, + prefix, value, option, plugin, di.info.Since, di.info.RemovalIn, di.info.Notice, + ) + } +} diff --git a/config/deprecation_test.go b/config/deprecation_test.go new file mode 100644 index 0000000..23f73c5 --- /dev/null +++ b/config/deprecation_test.go @@ -0,0 +1,277 @@ +package config + +import ( + "bufio" + "bytes" + "log" + "strings" + "testing" + "time" + + "github.com/coreos/go-semver/semver" + "github.com/stretchr/testify/require" + + "github.com/influxdata/telegraf" +) + +func TestPluginDeprecation(t *testing.T) { + info := telegraf.DeprecationInfo{ + Since: "1.23.0", + RemovalIn: "2.0.0", + Notice: "please check", + } + var tests = []struct { + name string + level telegraf.LogLevel + expected string + }{ + { + name: "Error level", + level: telegraf.Error, + expected: `Plugin "test" deprecated since version 1.23.0 and will be removed in 2.0.0: please check`, + }, + { + name: "Warn level", + level: telegraf.Warn, + expected: `Plugin "test" deprecated since version 1.23.0 and will be removed in 2.0.0: please check`, + }, + { + name: "None", + level: telegraf.None, + expected: ``, + }, + } + + // Switch the logger to log to a buffer + var buf bytes.Buffer + scanner := bufio.NewScanner(&buf) + + previous := log.Writer() + log.SetOutput(&buf) + defer log.SetOutput(previous) + + msg := make(chan string, 1) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + buf.Reset() + printPluginDeprecationNotice(tt.level, "test", info) + + // Wait for a newline to arrive and timeout for cases where + // we don't see a message. + go func() { + scanner.Scan() + msg <- scanner.Text() + }() + + // Reduce the timeout if we do not expect a message + timeout := 1 * time.Second + if tt.expected == "" { + timeout = 100 * time.Microsecond + } + + var actual string + select { + case actual = <-msg: + case <-time.After(timeout): + } + + if tt.expected != "" { + expected := deprecationPrefix(tt.level) + ": " + tt.expected + require.Equal(t, expected, actual) + } else { + require.Empty(t, actual) + } + }) + } +} + +func TestPluginOptionDeprecation(t *testing.T) { + var tests = []struct { + name string + since string + removal string + expected string + expectedLevel telegraf.LogLevel + }{ + { + name: "Error level", + since: "1.23.0", + removal: "1.29.0", + expectedLevel: telegraf.Error, + expected: `Option "option" of plugin "test" deprecated since version 1.23.0 and will be removed in 1.29.0: please check`, + }, + { + name: "Warn level", + since: "1.23.0", + removal: "2.0.0", + expectedLevel: telegraf.Warn, + expected: `Option "option" of plugin "test" deprecated since version 1.23.0 and will be removed in 2.0.0: please check`, + }, + { + name: "No removal info", + since: "1.23.0", + expectedLevel: telegraf.Warn, + expected: `Option "option" of plugin "test" deprecated since version 1.23.0 and will be removed in 2.0.0: please check`, + }, + { + name: "None", + expectedLevel: telegraf.None, + expected: ``, + }, + } + + // Fake telegraf's version + version, err := semver.NewVersion("1.30.0") + require.NoError(t, err) + telegrafVersion = version + + // Switch the logger to log to a buffer + var buf bytes.Buffer + scanner := bufio.NewScanner(&buf) + + previous := log.Writer() + log.SetOutput(&buf) + defer log.SetOutput(previous) + + msg := make(chan string, 1) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + buf.Reset() + info := telegraf.DeprecationInfo{ + Since: tt.since, + RemovalIn: tt.removal, + Notice: "please check", + } + PrintOptionDeprecationNotice("test", "option", info) + // Wait for a newline to arrive and timeout for cases where + // we don't see a message. + go func() { + scanner.Scan() + msg <- scanner.Text() + }() + + // Reduce the timeout if we do not expect a message + timeout := 1 * time.Second + if tt.expected == "" { + timeout = 100 * time.Microsecond + } + + var actual string + select { + case actual = <-msg: + case <-time.After(timeout): + } + + if tt.expected != "" { + expected := deprecationPrefix(tt.expectedLevel) + ": " + tt.expected + require.Equal(t, expected, actual) + } else { + require.Empty(t, actual) + } + }) + } +} + +func TestPluginOptionValueDeprecation(t *testing.T) { + var tests = []struct { + name string + since string + removal string + value interface{} + expected string + expectedLevel telegraf.LogLevel + }{ + { + name: "Error level", + since: "1.25.0", + removal: "1.29.0", + value: "foobar", + expected: `Value "foobar" for option "option" of plugin "test" deprecated since version 1.25.0 and will be removed in 1.29.0: please check`, + expectedLevel: telegraf.Error, + }, + { + name: "Warn level", + since: "1.25.0", + removal: "2.0.0", + value: "foobar", + expected: `Value "foobar" for option "option" of plugin "test" deprecated since version 1.25.0 and will be removed in 2.0.0: please check`, + expectedLevel: telegraf.Warn, + }, + { + name: "No removal info", + since: "1.25.0", + value: "foobar", + expected: `Value "foobar" for option "option" of plugin "test" deprecated since version 1.25.0 and will be removed in 2.0.0: please check`, + expectedLevel: telegraf.Warn, + }, + { + name: "None", + expected: ``, + expectedLevel: telegraf.None, + }, + { + name: "nil value", + since: "1.25.0", + removal: "1.29.0", + value: nil, + expected: `Value "" for option "option" of plugin "test" deprecated since version 1.25.0 and will be removed in 1.29.0: please check`, + expectedLevel: telegraf.Error, + }, + { + name: "Boolean value", + since: "1.25.0", + removal: "1.29.0", + value: true, + expected: `Value "true" for option "option" of plugin "test" deprecated since version 1.25.0 and will be removed in 1.29.0: please check`, + expectedLevel: telegraf.Error, + }, + { + name: "Integer value", + since: "1.25.0", + removal: "1.29.0", + value: 123, + expected: `Value "123" for option "option" of plugin "test" deprecated since version 1.25.0 and will be removed in 1.29.0: please check`, + expectedLevel: telegraf.Error, + }, + } + + // Fake telegraf's version + version, err := semver.NewVersion("1.30.0") + require.NoError(t, err) + telegrafVersion = version + + // Switch the logger to log to a buffer + var buf bytes.Buffer + previous := log.Writer() + log.SetOutput(&buf) + defer log.SetOutput(previous) + + timeout := 1 * time.Second + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + buf.Reset() + + info := telegraf.DeprecationInfo{ + Since: tt.since, + RemovalIn: tt.removal, + Notice: "please check", + } + PrintOptionValueDeprecationNotice("test", "option", tt.value, info) + + if tt.expected != "" { + require.Eventually(t, func() bool { + return strings.HasSuffix(buf.String(), "\n") + }, timeout, 100*time.Millisecond) + + // Remove the time for comparison + actual := strings.TrimSpace(buf.String()) + expected := deprecationPrefix(tt.expectedLevel) + ": " + tt.expected + require.Equal(t, expected, actual) + } else { + time.Sleep(timeout) + require.Empty(t, buf.String()) + } + }) + } +} diff --git a/config/envvar.go b/config/envvar.go new file mode 100644 index 0000000..981c822 --- /dev/null +++ b/config/envvar.go @@ -0,0 +1,252 @@ +package config + +import ( + "bytes" + "errors" + "io" + "os" + "strings" + + "github.com/compose-spec/compose-go/template" + "github.com/compose-spec/compose-go/utils" +) + +type trimmer struct { + input *bytes.Reader + output bytes.Buffer +} + +func removeComments(buf []byte) ([]byte, error) { + t := &trimmer{ + input: bytes.NewReader(buf), + output: bytes.Buffer{}, + } + err := t.process() + return t.output.Bytes(), err +} + +func (t *trimmer) process() error { + for { + // Read the next byte until EOF + c, err := t.input.ReadByte() + if err != nil { + if errors.Is(err, io.EOF) { + break + } + return err + } + + // Switch states if we need to + switch c { + case '\\': + //nolint:errcheck // next byte is known + t.input.UnreadByte() + err = t.escape() + case '\'': + //nolint:errcheck // next byte is known + t.input.UnreadByte() + if t.hasNQuotes(c, 3) { + err = t.tripleSingleQuote() + } else { + err = t.singleQuote() + } + case '"': + //nolint:errcheck // next byte is known + t.input.UnreadByte() + if t.hasNQuotes(c, 3) { + err = t.tripleDoubleQuote() + } else { + err = t.doubleQuote() + } + case '#': + err = t.comment() + default: + t.output.WriteByte(c) + continue + } + if err != nil { + if errors.Is(err, io.EOF) { + break + } + return err + } + } + return nil +} + +func (t *trimmer) hasNQuotes(ref byte, limit int64) bool { + var count int64 + // Look ahead check if the next characters are what we expect + for count = 0; count < limit; count++ { + c, err := t.input.ReadByte() + if err != nil || c != ref { + break + } + } + // We also need to unread the non-matching character + offset := -count + if count < limit { + offset-- + } + //nolint:errcheck // Unread the already matched characters + t.input.Seek(offset, io.SeekCurrent) + return count >= limit +} + +func (t *trimmer) readWriteByte() (byte, error) { + c, err := t.input.ReadByte() + if err != nil { + return 0, err + } + return c, t.output.WriteByte(c) +} + +func (t *trimmer) escape() error { + //nolint:errcheck // Consume the known starting backslash and quote + t.readWriteByte() + + // Read the next character which is the escaped one and exit + _, err := t.readWriteByte() + return err +} + +func (t *trimmer) singleQuote() error { + //nolint:errcheck // Consume the known starting quote + t.readWriteByte() + + // Read bytes until EOF, line end or another single quote + for { + if c, err := t.readWriteByte(); err != nil || c == '\'' || c == '\n' { + return err + } + } +} + +func (t *trimmer) tripleSingleQuote() error { + for i := 0; i < 3; i++ { + //nolint:errcheck // Consume the known starting quotes + t.readWriteByte() + } + + // Read bytes until EOF or another set of triple single quotes + for { + c, err := t.readWriteByte() + if err != nil { + return err + } + + if c == '\'' && t.hasNQuotes('\'', 2) { + //nolint:errcheck // Consume the two additional ending quotes + t.readWriteByte() + //nolint:errcheck // Consume the two additional ending quotes + t.readWriteByte() + return nil + } + } +} + +func (t *trimmer) doubleQuote() error { + //nolint:errcheck // Consume the known starting quote + t.readWriteByte() + + // Read bytes until EOF, line end or another double quote + for { + c, err := t.input.ReadByte() + if err != nil { + return err + } + switch c { + case '\\': + //nolint:errcheck // Consume the found escaped character + t.input.UnreadByte() + if err := t.escape(); err != nil { + return err + } + continue + case '"', '\n': + // Found terminator + return t.output.WriteByte(c) + } + t.output.WriteByte(c) + } +} + +func (t *trimmer) tripleDoubleQuote() error { + for i := 0; i < 3; i++ { + //nolint:errcheck // Consume the known starting quotes + t.readWriteByte() + } + + // Read bytes until EOF or another set of triple double quotes + for { + c, err := t.input.ReadByte() + if err != nil { + return err + } + switch c { + case '\\': + //nolint:errcheck // Consume the found escape character + t.input.UnreadByte() + if err := t.escape(); err != nil { + return err + } + continue + case '"': + t.output.WriteByte(c) + if t.hasNQuotes('"', 2) { + //nolint:errcheck // Consume the two additional ending quotes + t.readWriteByte() + //nolint:errcheck // Consume the two additional ending quotes + t.readWriteByte() + return nil + } + continue + } + t.output.WriteByte(c) + } +} + +func (t *trimmer) comment() error { + // Read bytes until EOF or a line break + for { + c, err := t.input.ReadByte() + if err != nil { + return err + } + if c == '\n' { + return t.output.WriteByte(c) + } + } +} + +func substituteEnvironment(contents []byte, oldReplacementBehavior bool) ([]byte, error) { + options := []template.Option{ + template.WithReplacementFunction(func(s string, m template.Mapping, cfg *template.Config) (string, error) { + result, applied, err := template.DefaultReplacementAppliedFunc(s, m, cfg) + if err == nil && !applied { + // Keep undeclared environment-variable patterns to reproduce + // pre-v1.27 behavior + return s, nil + } + if err != nil && strings.HasPrefix(err.Error(), "Invalid template:") { + // Keep invalid template patterns to ignore regexp substitutions + // like ${1} + return s, nil + } + return result, err + }), + template.WithoutLogging, + } + if oldReplacementBehavior { + options = append(options, template.WithPattern(oldVarRe)) + } + + envMap := utils.GetAsEqualsMap(os.Environ()) + retVal, err := template.SubstituteWithOptions(string(contents), func(k string) (string, bool) { + if v, ok := envMap[k]; ok { + return v, ok + } + return "", false + }, options...) + return []byte(retVal), err +} diff --git a/config/internal_test.go b/config/internal_test.go new file mode 100644 index 0000000..9a507d1 --- /dev/null +++ b/config/internal_test.go @@ -0,0 +1,411 @@ +package config + +import ( + "bytes" + "fmt" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestEnvironmentSubstitution(t *testing.T) { + tests := []struct { + name string + setEnv func(*testing.T) + contents string + expected string + wantErr bool + errSubstring string + }{ + { + name: "Legacy with ${} and without {}", + setEnv: func(t *testing.T) { + t.Setenv("TEST_ENV1", "VALUE1") + t.Setenv("TEST_ENV2", "VALUE2") + }, + contents: "A string with ${TEST_ENV1}, $TEST_ENV2 and $TEST_ENV1 as repeated", + expected: "A string with VALUE1, VALUE2 and VALUE1 as repeated", + }, + { + name: "Env not set", + contents: "Env variable ${NOT_SET} will be empty", + expected: "Env variable ${NOT_SET} will be empty", + }, + { + name: "Env not set, fallback to default", + contents: "Env variable ${THIS_IS_ABSENT:-Fallback}", + expected: "Env variable Fallback", + }, + { + name: "No fallback", + setEnv: func(t *testing.T) { + t.Setenv("MY_ENV1", "VALUE1") + }, + contents: "Env variable ${MY_ENV1:-Fallback}", + expected: "Env variable VALUE1", + }, + { + name: "Mix and match", + setEnv: func(t *testing.T) { + t.Setenv("MY_VAR", "VALUE") + t.Setenv("MY_VAR2", "VALUE2") + }, + contents: "Env var ${MY_VAR} is set, with $MY_VAR syntax and default on this ${MY_VAR1:-Substituted}, no default on this ${MY_VAR2:-NoDefault}", + expected: "Env var VALUE is set, with VALUE syntax and default on this Substituted, no default on this VALUE2", + }, + { + name: "empty but set", + setEnv: func(t *testing.T) { + t.Setenv("EMPTY", "") + }, + contents: "Contains ${EMPTY} nothing", + expected: "Contains nothing", + }, + { + name: "Default has special chars", + contents: `Not recommended but supported ${MY_VAR:-Default with special chars Supported#$\"}`, + expected: `Not recommended but supported Default with special chars Supported#$\"`, // values are escaped + }, + { + name: "unset error", + contents: "Contains ${THIS_IS_NOT_SET?unset-error}", + wantErr: true, + errSubstring: "unset-error", + }, + { + name: "env empty error", + setEnv: func(t *testing.T) { + t.Setenv("ENV_EMPTY", "") + }, + contents: "Contains ${ENV_EMPTY:?empty-error}", + wantErr: true, + errSubstring: "empty-error", + }, + { + name: "Fallback as env variable", + setEnv: func(t *testing.T) { + t.Setenv("FALLBACK", "my-fallback") + }, + contents: "Should output ${NOT_SET:-${FALLBACK}}", + expected: "Should output my-fallback", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setEnv != nil { + tt.setEnv(t) + } + actual, err := substituteEnvironment([]byte(tt.contents), false) + if tt.wantErr { + require.ErrorContains(t, err, tt.errSubstring) + return + } + require.EqualValues(t, tt.expected, string(actual)) + }) + } +} + +func TestEnvironmentSubstitutionOldBehavior(t *testing.T) { + tests := []struct { + name string + contents string + expected string + }{ + { + name: "not defined no brackets", + contents: `my-da$tabase`, + expected: `my-da$tabase`, + }, + { + name: "not defined brackets", + contents: `my-da${ta}base`, + expected: `my-da${ta}base`, + }, + { + name: "not defined no brackets double dollar", + contents: `my-da$$tabase`, + expected: `my-da$$tabase`, + }, + { + name: "not defined no brackets backslash", + contents: `my-da\$tabase`, + expected: `my-da\$tabase`, + }, + { + name: "not defined brackets backslash", + contents: `my-da\${ta}base`, + expected: `my-da\${ta}base`, + }, + { + name: "no brackets and suffix", + contents: `my-da$VARbase`, + expected: `my-da$VARbase`, + }, + { + name: "no brackets", + contents: `my-da$VAR`, + expected: `my-dafoobar`, + }, + { + name: "brackets", + contents: `my-da${VAR}base`, + expected: `my-dafoobarbase`, + }, + { + name: "no brackets double dollar", + contents: `my-da$$VAR`, + expected: `my-da$foobar`, + }, + { + name: "brackets double dollar", + contents: `my-da$${VAR}`, + expected: `my-da$foobar`, + }, + { + name: "no brackets backslash", + contents: `my-da\$VAR`, + expected: `my-da\foobar`, + }, + { + name: "brackets backslash", + contents: `my-da\${VAR}base`, + expected: `my-da\foobarbase`, + }, + { + name: "fallback", + contents: `my-da${ta:-omg}base`, + expected: `my-daomgbase`, + }, + { + name: "fallback env", + contents: `my-da${ta:-${FALLBACK}}base`, + expected: `my-dadefaultbase`, + }, + { + name: "regex substitution", + contents: `${1}`, + expected: `${1}`, + }, + { + name: "empty but set", + contents: "Contains ${EMPTY} nothing", + expected: "Contains nothing", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Setenv("VAR", "foobar") + t.Setenv("FALLBACK", "default") + t.Setenv("EMPTY", "") + actual, err := substituteEnvironment([]byte(tt.contents), true) + require.NoError(t, err) + require.EqualValues(t, tt.expected, string(actual)) + }) + } +} + +func TestEnvironmentSubstitutionNewBehavior(t *testing.T) { + tests := []struct { + name string + contents string + expected string + }{ + { + name: "not defined no brackets", + contents: `my-da$tabase`, + expected: `my-da$tabase`, + }, + { + name: "not defined brackets", + contents: `my-da${ta}base`, + expected: `my-da${ta}base`, + }, + { + name: "not defined no brackets double dollar", + contents: `my-da$$tabase`, + expected: `my-da$tabase`, + }, + { + name: "not defined no brackets backslash", + contents: `my-da\$tabase`, + expected: `my-da\$tabase`, + }, + { + name: "not defined brackets backslash", + contents: `my-da\${ta}base`, + expected: `my-da\${ta}base`, + }, + { + name: "no brackets and suffix", + contents: `my-da$VARbase`, + expected: `my-da$VARbase`, + }, + { + name: "no brackets", + contents: `my-da$VAR`, + expected: `my-dafoobar`, + }, + { + name: "brackets", + contents: `my-da${VAR}base`, + expected: `my-dafoobarbase`, + }, + { + name: "no brackets double dollar", + contents: `my-da$$VAR`, + expected: `my-da$VAR`, + }, + { + name: "brackets double dollar", + contents: `my-da$${VAR}`, + expected: `my-da${VAR}`, + }, + { + name: "no brackets backslash", + contents: `my-da\$VAR`, + expected: `my-da\foobar`, + }, + { + name: "brackets backslash", + contents: `my-da\${VAR}base`, + expected: `my-da\foobarbase`, + }, + { + name: "fallback", + contents: `my-da${ta:-omg}base`, + expected: `my-daomgbase`, + }, + { + name: "fallback env", + contents: `my-da${ta:-${FALLBACK}}base`, + expected: `my-dadefaultbase`, + }, + { + name: "regex substitution", + contents: `${1}`, + expected: `${1}`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Setenv("VAR", "foobar") + t.Setenv("FALLBACK", "default") + actual, err := substituteEnvironment([]byte(tt.contents), false) + require.NoError(t, err) + require.EqualValues(t, tt.expected, string(actual)) + }) + } +} + +func TestParseConfig(t *testing.T) { + tests := []struct { + name string + setEnv func(*testing.T) + contents string + expected string + errmsg string + }{ + { + name: "empty var name", + contents: ` +# Environment variables can be used anywhere in this config file, simply surround +# them with ${}. For strings the variable must be within quotes (ie, "${STR_VAR}"), +# for numbers and booleans they should be plain (ie, ${INT_VAR}, ${BOOL_VAR})Should output ${NOT_SET:-${FALLBACK}} +`, + expected: "\n\n\n\n", + }, + { + name: "comment in command (issue #13643)", + contents: ` + [[inputs.exec]] + commands = ["echo \"abc#def\""] + `, + expected: ` + [[inputs.exec]] + commands = ["echo \"abc#def\""] + `, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setEnv != nil { + tt.setEnv(t) + } + tbl, err := parseConfig([]byte(tt.contents)) + if tt.errmsg != "" { + require.ErrorContains(t, err, tt.errmsg) + return + } + + require.NoError(t, err) + if len(tt.expected) > 0 { + require.EqualValues(t, tt.expected, string(tbl.Data)) + } + }) + } +} + +func TestRemoveComments(t *testing.T) { + // Read expectation + expected, err := os.ReadFile(filepath.Join("testdata", "envvar_comments_expected.toml")) + require.NoError(t, err) + + // Read the file and remove the comments + buf, err := os.ReadFile(filepath.Join("testdata", "envvar_comments.toml")) + require.NoError(t, err) + removed, err := removeComments(buf) + require.NoError(t, err) + lines := bytes.Split(removed, []byte{'\n'}) + for i, line := range lines { + lines[i] = bytes.TrimRight(line, " \t") + } + actual := bytes.Join(lines, []byte{'\n'}) + + // Do the comparison + require.Equal(t, string(expected), string(actual)) +} + +func TestURLRetries3Fails(t *testing.T) { + httpLoadConfigRetryInterval = 0 * time.Second + responseCounter := 0 + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNotFound) + responseCounter++ + })) + defer ts.Close() + + expected := fmt.Sprintf("loading config file %s failed: failed to fetch HTTP config: 404 Not Found", ts.URL) + + c := NewConfig() + err := c.LoadConfig(ts.URL) + require.Error(t, err) + require.Equal(t, expected, err.Error()) + require.Equal(t, 4, responseCounter) +} + +func TestURLRetries3FailsThenPasses(t *testing.T) { + httpLoadConfigRetryInterval = 0 * time.Second + responseCounter := 0 + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + if responseCounter <= 2 { + w.WriteHeader(http.StatusNotFound) + } else { + w.WriteHeader(http.StatusOK) + } + responseCounter++ + })) + defer ts.Close() + + c := NewConfig() + require.NoError(t, c.LoadConfig(ts.URL)) + require.Equal(t, 4, responseCounter) +} diff --git a/config/migration.go b/config/migration.go new file mode 100644 index 0000000..837c4b6 --- /dev/null +++ b/config/migration.go @@ -0,0 +1,261 @@ +package config + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "log" + "sort" + "strings" + + "github.com/influxdata/toml" + "github.com/influxdata/toml/ast" + + "github.com/influxdata/telegraf/migrations" + _ "github.com/influxdata/telegraf/migrations/all" // register all migrations +) + +type section struct { + name string + begin int + content *ast.Table + raw *bytes.Buffer +} + +func splitToSections(root *ast.Table) ([]section, error) { + var sections []section + for name, elements := range root.Fields { + switch name { + case "inputs", "outputs", "processors", "aggregators": + category, ok := elements.(*ast.Table) + if !ok { + return nil, fmt.Errorf("%q is not a table (%T)", name, category) + } + + for plugin, elements := range category.Fields { + tbls, ok := elements.([]*ast.Table) + if !ok { + return nil, fmt.Errorf("elements of \"%s.%s\" is not a list of tables (%T)", name, plugin, elements) + } + for _, tbl := range tbls { + s := section{ + name: name + "." + tbl.Name, + begin: tbl.Line, + content: tbl, + raw: &bytes.Buffer{}, + } + sections = append(sections, s) + } + } + default: + tbl, ok := elements.(*ast.Table) + if !ok { + return nil, fmt.Errorf("%q is not a table (%T)", name, elements) + } + s := section{ + name: name, + begin: tbl.Line, + content: tbl, + raw: &bytes.Buffer{}, + } + sections = append(sections, s) + } + } + + // Sort the TOML elements by begin (line-number) + sort.SliceStable(sections, func(i, j int) bool { return sections[i].begin < sections[j].begin }) + + return sections, nil +} + +func assignTextToSections(data []byte, sections []section) ([]section, error) { + // Now assign the raw text to each section + if sections[0].begin > 0 { + sections = append([]section{{ + name: "header", + begin: 0, + raw: &bytes.Buffer{}, + }}, sections...) + } + + var lineno int + scanner := bufio.NewScanner(bytes.NewBuffer(data)) + for idx, next := range sections[1:] { + var buf bytes.Buffer + for lineno < next.begin-1 { + if !scanner.Scan() { + break + } + lineno++ + + line := strings.TrimSpace(scanner.Text()) + if strings.HasPrefix(line, "#") { + buf.Write(scanner.Bytes()) + buf.WriteString("\n") + continue + } else if buf.Len() > 0 { + if _, err := io.Copy(sections[idx].raw, &buf); err != nil { + return nil, fmt.Errorf("copying buffer failed: %w", err) + } + buf.Reset() + } + + sections[idx].raw.Write(scanner.Bytes()) + sections[idx].raw.WriteString("\n") + } + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("splitting by line failed: %w", err) + } + + // If a comment is directly in front of the next section, without + // newline, the comment is assigned to the next section. + if buf.Len() > 0 { + if _, err := io.Copy(sections[idx+1].raw, &buf); err != nil { + return nil, fmt.Errorf("copying buffer failed: %w", err) + } + buf.Reset() + } + } + // Write the remaining to the last section + for scanner.Scan() { + sections[len(sections)-1].raw.Write(scanner.Bytes()) + sections[len(sections)-1].raw.WriteString("\n") + } + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("splitting by line failed: %w", err) + } + return sections, nil +} + +func ApplyMigrations(data []byte) ([]byte, uint64, error) { + root, err := toml.Parse(data) + if err != nil { + return nil, 0, fmt.Errorf("parsing failed: %w", err) + } + + // Split the configuration into sections containing the location + // in the file. + sections, err := splitToSections(root) + if err != nil { + return nil, 0, fmt.Errorf("splitting to sections failed: %w", err) + } + if len(sections) == 0 { + return nil, 0, errors.New("no TOML configuration found") + } + + // Assign the configuration text to the corresponding segments + sections, err = assignTextToSections(data, sections) + if err != nil { + return nil, 0, fmt.Errorf("assigning text failed: %w", err) + } + + var applied uint64 + // Do the actual global section migration(s) + for idx, s := range sections { + if strings.Contains(s.name, ".") { + continue + } + log.Printf("D! applying global migrations to section %q in line %d...", s.name, s.begin) + for _, migrate := range migrations.GlobalMigrations { + result, msg, err := migrate(s.name, s.content) + if err != nil { + if errors.Is(err, migrations.ErrNotApplicable) { + continue + } + return nil, 0, fmt.Errorf("migrating options of %q (line %d) failed: %w", s.name, s.begin, err) + } + if msg != "" { + log.Printf("I! Global section %q in line %d: %s", s.name, s.begin, msg) + } + s.raw = bytes.NewBuffer(result) + applied++ + } + sections[idx] = s + } + + // Do the actual plugin migration(s) + for idx, s := range sections { + migrate, found := migrations.PluginMigrations[s.name] + if !found { + continue + } + + log.Printf("D! migrating plugin %q in line %d...", s.name, s.begin) + result, msg, err := migrate(s.content) + if err != nil { + return nil, 0, fmt.Errorf("migrating %q (line %d) failed: %w", s.name, s.begin, err) + } + if msg != "" { + log.Printf("I! Plugin %q in line %d: %s", s.name, s.begin, msg) + } + s.raw = bytes.NewBuffer(result) + tbl, err := toml.Parse(s.raw.Bytes()) + if err != nil { + return nil, 0, fmt.Errorf("reparsing migrated %q (line %d) failed: %w", s.name, s.begin, err) + } + s.content = tbl + sections[idx] = s + applied++ + } + + // Do the actual plugin option migration(s) + for idx, s := range sections { + migrate, found := migrations.PluginOptionMigrations[s.name] + if !found { + continue + } + + log.Printf("D! migrating options of plugin %q in line %d...", s.name, s.begin) + result, msg, err := migrate(s.content) + if err != nil { + if errors.Is(err, migrations.ErrNotApplicable) { + continue + } + return nil, 0, fmt.Errorf("migrating options of %q (line %d) failed: %w", s.name, s.begin, err) + } + if msg != "" { + log.Printf("I! Plugin %q in line %d: %s", s.name, s.begin, msg) + } + s.raw = bytes.NewBuffer(result) + sections[idx] = s + applied++ + } + + // Do general migrations applying to all plugins + for idx, s := range sections { + parts := strings.Split(s.name, ".") + if len(parts) != 2 { + continue + } + log.Printf("D! applying general migrations to plugin %q in line %d...", s.name, s.begin) + category, name := parts[0], parts[1] + for _, migrate := range migrations.GeneralMigrations { + result, msg, err := migrate(category, name, s.content) + if err != nil { + if errors.Is(err, migrations.ErrNotApplicable) { + continue + } + return nil, 0, fmt.Errorf("migrating options of %q (line %d) failed: %w", s.name, s.begin, err) + } + if msg != "" { + log.Printf("I! Plugin %q in line %d: %s", s.name, s.begin, msg) + } + s.raw = bytes.NewBuffer(result) + applied++ + } + sections[idx] = s + } + + // Reconstruct the config file from the sections + var buf bytes.Buffer + for _, s := range sections { + _, err = s.raw.WriteTo(&buf) + if err != nil { + return nil, applied, fmt.Errorf("joining output failed: %w", err) + } + } + + return buf.Bytes(), applied, nil +} diff --git a/config/plugin_id.go b/config/plugin_id.go new file mode 100644 index 0000000..51f5c21 --- /dev/null +++ b/config/plugin_id.go @@ -0,0 +1,79 @@ +package config + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "sort" + + "github.com/influxdata/toml/ast" +) + +type keyValuePair struct { + Key string + Value string +} + +func processTable(parent string, table *ast.Table) ([]keyValuePair, error) { + var prefix string + var options []keyValuePair + + if parent != "" { + prefix = parent + "." + } + + for k, value := range table.Fields { + switch v := value.(type) { + case *ast.KeyValue: + key := prefix + k + options = append(options, keyValuePair{ + Key: key, + Value: v.Value.Source(), + }) + case *ast.Table: + key := prefix + k + children, err := processTable(key, v) + if err != nil { + return nil, fmt.Errorf("parsing table for %q failed: %w", key, err) + } + options = append(options, children...) + case []*ast.Table: + for i, t := range v { + key := fmt.Sprintf("%s#%d.%s", prefix, i, k) + children, err := processTable(key, t) + if err != nil { + return nil, fmt.Errorf("parsing table for %q #%d failed: %w", key, i, err) + } + options = append(options, children...) + } + default: + return nil, fmt.Errorf("unknown node type %T in key %q", value, prefix+k) + } + } + return options, nil +} + +func generatePluginID(prefix string, table *ast.Table) (string, error) { + // We need to ensure that identically configured plugins _always_ + // result in the same ID no matter which order the options are specified. + // This is even more relevant as Golang does _not_ give any guarantee + // on the ordering of maps. + // So we flatten out the configuration options (also for nested objects) + // and then sort the resulting array by the canonical key-name. + cfg, err := processTable("", table) + if err != nil { + return "", fmt.Errorf("processing AST failed: %w", err) + } + sort.SliceStable(cfg, func(i, j int) bool { return cfg[i].Key < cfg[j].Key }) + + // Hash the config options to get the ID. We also prefix the ID with + // the plugin name to prevent overlap with other plugin types. + hash := sha256.New() + hash.Write(append([]byte(prefix), 0)) + for _, kv := range cfg { + hash.Write([]byte(kv.Key + ":" + kv.Value)) + hash.Write([]byte{0}) + } + + return hex.EncodeToString(hash.Sum(nil)), nil +} diff --git a/config/plugin_printer.go b/config/plugin_printer.go new file mode 100644 index 0000000..2836d94 --- /dev/null +++ b/config/plugin_printer.go @@ -0,0 +1,106 @@ +package config + +import ( + "bytes" + "fmt" + "sort" + "strings" + + "github.com/jedib0t/go-pretty/v6/table" +) + +var headers = []string{"Name", "Source(s)"} + +type pluginPrinter struct { + name string + source string +} + +type pluginNames []pluginPrinter + +func getPluginSourcesTable(pluginNames []pluginPrinter) string { + if !PrintPluginConfigSource { + return "" + } + + if len(pluginNames) == 0 { + return "" + } + + data := make([][]any, 0, len(pluginNames)) + rows := make(map[string][]string) + for _, plugin := range pluginNames { + if _, ok := rows[plugin.name]; !ok { + rows[plugin.name] = make([]string, 0) + } + rows[plugin.name] = append(rows[plugin.name], plugin.source) + } + + for name, sources := range rows { + var nameCountStr string + if len(sources) > 1 { + nameCountStr = fmt.Sprintf("%s (%dx)", name, len(sources)) + } else { + nameCountStr = name + } + data = append(data, []any{nameCountStr, sources}) + } + sort.Slice(data, func(i, j int) bool { + return len(data[i][1].([]string)) > len(data[j][1].([]string)) + }) + return getTableString(headers, data) +} + +func getTableString(headers []string, data [][]any) string { + buff := new(bytes.Buffer) + + t := table.NewWriter() + t.SetOutputMirror(buff) + t.AppendHeader(convertToRow(headers)) + + // Append rows + for _, row := range data { + processedRow := make([]interface{}, len(row)) + for i, col := range row { + switch v := col.(type) { + case []string: // Convert slices to multi-line strings + var source map[string]int + for _, s := range v { + if source == nil { + source = make(map[string]int) + } + source[s]++ + } + // sort the sources according to the count + sources := make([]string, 0, len(source)) + for s := range source { + sources = append(sources, s) + } + sort.Slice(sources, func(i, j int) bool { + return source[sources[i]] > source[sources[j]] + }) + for i, s := range sources { + if source[s] > 1 { + sources[i] = fmt.Sprintf("%s (%dx)", s, source[s]) + } + } + processedRow[i] = strings.Join(sources, "\n") + default: + processedRow[i] = v + } + } + t.AppendRow(processedRow) + } + + t.Style().Options.SeparateRows = true + return t.Render() +} + +// Helper function to convert headers to table.Row +func convertToRow(data []string) table.Row { + row := make(table.Row, len(data)) + for i, val := range data { + row[i] = val + } + return row +} diff --git a/config/secret.go b/config/secret.go new file mode 100644 index 0000000..16d360f --- /dev/null +++ b/config/secret.go @@ -0,0 +1,315 @@ +package config + +import ( + "fmt" + "log" + "regexp" + "strings" + "sync/atomic" + + "github.com/influxdata/telegraf" +) + +// unlinkedSecrets contains the list of secrets that contain +// references not yet linked to their corresponding secret-store. +// Those secrets must later (after reading the config) be linked +// by the config to their respective secret-stores. +// Secrets containing constant strings will not be found in this +// list. +var unlinkedSecrets = make([]*Secret, 0) + +// secretStorePattern is a regex to validate secret-store IDs +var secretStorePattern = regexp.MustCompile(`^\w+$`) + +// secretPattern is a regex to extract references to secrets store in a secret-store +var secretPattern = regexp.MustCompile(`@\{(\w+:\w+)\}`) + +// secretCandidatePattern is a regex to find secret candidates to warn users on invalid characters in references +var secretCandidatePattern = regexp.MustCompile(`@\{.+?:.+?}`) + +// secretCount is the number of secrets use in Telegraf +var secretCount atomic.Int64 + +// selectedImpl is the configured implementation for secrets +var selectedImpl secretImpl = &protectedSecretImpl{} + +// secretImpl represents an abstraction for different implementations of secrets +type secretImpl interface { + Container(secret []byte) secretContainer + EmptyBuffer() SecretBuffer + Wipe(secret []byte) +} + +func EnableSecretProtection() { + selectedImpl = &protectedSecretImpl{} +} + +func DisableSecretProtection() { + selectedImpl = &unprotectedSecretImpl{} +} + +// secretContainer represents an abstraction of the container holding the +// actual secret value +type secretContainer interface { + Destroy() + Equals(ref []byte) (bool, error) + Buffer() (SecretBuffer, error) + AsBuffer(secret []byte) SecretBuffer + Replace(secret []byte) +} + +// SecretBuffer allows to access the content of the secret +type SecretBuffer interface { + // Size returns the length of the buffer content + Size() int + // Grow will grow the capacity of the underlying buffer to the given size + Grow(capacity int) + // Bytes returns the content of the buffer as bytes. + // NOTE: The returned bytes shall NOT be accessed after destroying the + // buffer using 'Destroy()' as the underlying the memory area might be + // wiped and invalid. + Bytes() []byte + // TemporaryString returns the content of the buffer as a string. + // NOTE: The returned String shall NOT be accessed after destroying the + // buffer using 'Destroy()' as the underlying the memory area might be + // wiped and invalid. + TemporaryString() string + // String returns a copy of the underlying buffer's content as string. + // It is safe to use the returned value after destroying the buffer. + String() string + // Destroy will wipe the buffer's content and destroy the underlying + // buffer. Do not access the buffer after destroying it. + Destroy() +} + +// Secret safely stores sensitive data such as a password or token +type Secret struct { + // container is the implementation for holding the secret. It can be + // protected or not depending on the concrete implementation. + container secretContainer + + // resolvers are the functions for resolving a given secret-id (key) + resolvers map[string]telegraf.ResolveFunc + + // unlinked contains all references in the secret that are not yet + // linked to the corresponding secret store. + unlinked []string + + // notempty denotes if the secret is completely empty + notempty bool +} + +// NewSecret creates a new secret from the given bytes +func NewSecret(b []byte) Secret { + s := Secret{} + s.init(b) + return s +} + +// UnmarshalText creates a secret from a toml value following the "string" rule. +func (s *Secret) UnmarshalText(b []byte) error { + // Unmarshal secret from TOML and put it into protected memory + s.init(b) + + // Keep track of secrets that contain references to secret-stores + // for later resolving by the config. + if len(s.unlinked) > 0 && s.notempty { + unlinkedSecrets = append(unlinkedSecrets, s) + } + + return nil +} + +// Initialize the secret content +func (s *Secret) init(secret []byte) { + // Keep track of the number of secrets... + secretCount.Add(1) + + // Remember if the secret is completely empty + s.notempty = len(secret) != 0 + + // Find all secret candidates and check if they are really a valid + // reference. Otherwise issue a warning to let the user know that there is + // a potential issue with their secret instead of silently ignoring it. + candidates := secretCandidatePattern.FindAllString(string(secret), -1) + s.unlinked = make([]string, 0, len(candidates)) + for _, c := range candidates { + if secretPattern.MatchString(c) { + s.unlinked = append(s.unlinked, c) + } else { + log.Printf("W! Secret %q contains invalid character(s), only letters, digits and underscores are allowed.", c) + } + } + s.resolvers = nil + + // Setup the container implementation + s.container = selectedImpl.Container(secret) +} + +// Destroy the secret content +func (s *Secret) Destroy() { + s.resolvers = nil + s.unlinked = nil + s.notempty = false + + if s.container != nil { + s.container.Destroy() + s.container = nil + + // Keep track of the number of used secrets... + secretCount.Add(-1) + } +} + +// Empty return if the secret is completely empty +func (s *Secret) Empty() bool { + return !s.notempty +} + +// EqualTo performs a constant-time comparison of the secret to the given reference +func (s *Secret) EqualTo(ref []byte) (bool, error) { + if s.container == nil { + return false, nil + } + + if len(s.unlinked) > 0 { + return false, fmt.Errorf("unlinked parts in secret: %v", strings.Join(s.unlinked, ";")) + } + + return s.container.Equals(ref) +} + +// Get return the string representation of the secret +func (s *Secret) Get() (SecretBuffer, error) { + if s.container == nil { + return selectedImpl.EmptyBuffer(), nil + } + + if len(s.unlinked) > 0 { + return nil, fmt.Errorf("unlinked parts in secret: %v", strings.Join(s.unlinked, ";")) + } + + // Decrypt the secret so we can return it + buffer, err := s.container.Buffer() + if err != nil { + return nil, err + } + + // We've got a static secret so simply return the buffer + if len(s.resolvers) == 0 { + return buffer, nil + } + defer buffer.Destroy() + + replaceErrs := make([]string, 0) + newsecret := secretPattern.ReplaceAllFunc(buffer.Bytes(), func(match []byte) []byte { + resolver, found := s.resolvers[string(match)] + if !found { + replaceErrs = append(replaceErrs, fmt.Sprintf("no resolver for %q", match)) + return match + } + replacement, _, err := resolver() + if err != nil { + replaceErrs = append(replaceErrs, fmt.Sprintf("resolving %q failed: %v", match, err)) + return match + } + + return replacement + }) + if len(replaceErrs) > 0 { + selectedImpl.Wipe(newsecret) + return nil, fmt.Errorf("replacing secrets failed: %s", strings.Join(replaceErrs, ";")) + } + + return s.container.AsBuffer(newsecret), nil +} + +// Set overwrites the secret's value with a new one. Please note, the secret +// is not linked again, so only references to secret-stores can be used, e.g. by +// adding more clear-text or reordering secrets. +func (s *Secret) Set(value []byte) error { + // Link the new value can be resolved + secret, res, replaceErrs := resolve(value, s.resolvers) + if len(replaceErrs) > 0 { + return fmt.Errorf("linking new secrets failed: %s", strings.Join(replaceErrs, ";")) + } + + // Set the new secret + s.container.Replace(secret) + s.resolvers = res + s.notempty = len(value) > 0 + + return nil +} + +// GetUnlinked return the parts of the secret that is not yet linked to a resolver +func (s *Secret) GetUnlinked() []string { + return s.unlinked +} + +// Link used the given resolver map to link the secret parts to their +// secret-store resolvers. +func (s *Secret) Link(resolvers map[string]telegraf.ResolveFunc) error { + // Decrypt the secret so we can return it + if s.container == nil { + return nil + } + buffer, err := s.container.Buffer() + if err != nil { + return err + } + defer buffer.Destroy() + + // Iterate through the parts and try to resolve them. For static parts + // we directly replace them, while for dynamic ones we store the resolver. + newsecret, res, replaceErrs := resolve(buffer.Bytes(), resolvers) + if len(replaceErrs) > 0 { + return fmt.Errorf("linking secrets failed: %s", strings.Join(replaceErrs, ";")) + } + s.resolvers = res + + // Store the secret if it has changed + if buffer.TemporaryString() != string(newsecret) { + s.container.Replace(newsecret) + } + + // All linked now + s.unlinked = nil + + return nil +} + +func resolve(secret []byte, resolvers map[string]telegraf.ResolveFunc) ([]byte, map[string]telegraf.ResolveFunc, []string) { + // Iterate through the parts and try to resolve them. For static parts + // we directly replace them, while for dynamic ones we store the resolver. + replaceErrs := make([]string, 0) + remaining := make(map[string]telegraf.ResolveFunc) + newsecret := secretPattern.ReplaceAllFunc(secret, func(match []byte) []byte { + resolver, found := resolvers[string(match)] + if !found { + replaceErrs = append(replaceErrs, fmt.Sprintf("unlinked part %q", match)) + return match + } + replacement, dynamic, err := resolver() + if err != nil { + replaceErrs = append(replaceErrs, fmt.Sprintf("resolving %q failed: %v", match, err)) + return match + } + + // Replace static parts right away + if !dynamic { + return replacement + } + + // Keep the resolver for dynamic secrets + remaining[string(match)] = resolver + return match + }) + return newsecret, remaining, replaceErrs +} + +func splitLink(s string) (storeID, key string) { + // There should _ALWAYS_ be two parts due to the regular expression match + parts := strings.SplitN(s[2:len(s)-1], ":", 2) + return parts[0], parts[1] +} diff --git a/config/secret_protected.go b/config/secret_protected.go new file mode 100644 index 0000000..0490940 --- /dev/null +++ b/config/secret_protected.go @@ -0,0 +1,131 @@ +package config + +import ( + "fmt" + + "github.com/awnumar/memguard" +) + +type protectedSecretImpl struct{} + +func (*protectedSecretImpl) Container(secret []byte) secretContainer { + return &protectedSecretContainer{ + enclave: memguard.NewEnclave(secret), + } +} + +func (*protectedSecretImpl) EmptyBuffer() SecretBuffer { + return &lockedBuffer{} +} + +func (*protectedSecretImpl) Wipe(secret []byte) { + memguard.WipeBytes(secret) +} + +type lockedBuffer struct { + buf *memguard.LockedBuffer +} + +func (lb *lockedBuffer) Size() int { + if lb.buf == nil { + return 0 + } + return lb.buf.Size() +} + +func (lb *lockedBuffer) Grow(capacity int) { + size := lb.Size() + if capacity <= size { + return + } + + buf := memguard.NewBuffer(capacity) + if lb.buf != nil { + buf.Copy(lb.buf.Bytes()) + } + lb.buf.Destroy() + lb.buf = buf +} + +func (lb *lockedBuffer) Bytes() []byte { + if lb.buf == nil { + return nil + } + return lb.buf.Bytes() +} + +func (lb *lockedBuffer) TemporaryString() string { + if lb.buf == nil { + return "" + } + return lb.buf.String() +} + +func (lb *lockedBuffer) String() string { + if lb.buf == nil { + return "" + } + return string(lb.buf.Bytes()) +} + +func (lb *lockedBuffer) Destroy() { + if lb.buf == nil { + return + } + lb.buf.Destroy() + lb.buf = nil +} + +type protectedSecretContainer struct { + enclave *memguard.Enclave +} + +func (c *protectedSecretContainer) Destroy() { + if c.enclave == nil { + return + } + + // Wipe the secret from memory + lockbuf, err := c.enclave.Open() + if err == nil { + lockbuf.Destroy() + } + c.enclave = nil +} + +func (c *protectedSecretContainer) Equals(ref []byte) (bool, error) { + if c.enclave == nil { + return false, nil + } + + // Get a locked-buffer of the secret to perform the comparison + lockbuf, err := c.enclave.Open() + if err != nil { + return false, fmt.Errorf("opening enclave failed: %w", err) + } + defer lockbuf.Destroy() + + return lockbuf.EqualTo(ref), nil +} + +func (c *protectedSecretContainer) Buffer() (SecretBuffer, error) { + if c.enclave == nil { + return &lockedBuffer{}, nil + } + + // Get a locked-buffer of the secret to perform the comparison + lockbuf, err := c.enclave.Open() + if err != nil { + return nil, fmt.Errorf("opening enclave failed: %w", err) + } + + return &lockedBuffer{lockbuf}, nil +} + +func (*protectedSecretContainer) AsBuffer(secret []byte) SecretBuffer { + return &lockedBuffer{memguard.NewBufferFromBytes(secret)} +} + +func (c *protectedSecretContainer) Replace(secret []byte) { + c.enclave = memguard.NewEnclave(secret) +} diff --git a/config/secret_test.go b/config/secret_test.go new file mode 100644 index 0000000..ae344f9 --- /dev/null +++ b/config/secret_test.go @@ -0,0 +1,845 @@ +package config + +import ( + "bytes" + "errors" + "fmt" + "log" + "testing" + + "github.com/awnumar/memguard" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/inputs" + "github.com/influxdata/telegraf/plugins/secretstores" +) + +func TestSecretConstantManually(t *testing.T) { + mysecret := "a wonderful test" + s := NewSecret([]byte(mysecret)) + defer s.Destroy() + retrieved, err := s.Get() + require.NoError(t, err) + defer retrieved.Destroy() + require.EqualValues(t, mysecret, retrieved.TemporaryString()) +} + +func TestLinking(t *testing.T) { + mysecret := "a @{referenced:secret}" + resolvers := map[string]telegraf.ResolveFunc{ + "@{referenced:secret}": func() ([]byte, bool, error) { + return []byte("resolved secret"), false, nil + }, + } + s := NewSecret([]byte(mysecret)) + defer s.Destroy() + require.NoError(t, s.Link(resolvers)) + retrieved, err := s.Get() + require.NoError(t, err) + defer retrieved.Destroy() + require.EqualValues(t, "a resolved secret", retrieved.TemporaryString()) +} + +func TestLinkingResolverError(t *testing.T) { + mysecret := "a @{referenced:secret}" + resolvers := map[string]telegraf.ResolveFunc{ + "@{referenced:secret}": func() ([]byte, bool, error) { + return nil, false, errors.New("broken") + }, + } + s := NewSecret([]byte(mysecret)) + defer s.Destroy() + expected := `linking secrets failed: resolving "@{referenced:secret}" failed: broken` + require.EqualError(t, s.Link(resolvers), expected) +} + +func TestGettingUnlinked(t *testing.T) { + mysecret := "a @{referenced:secret}" + s := NewSecret([]byte(mysecret)) + defer s.Destroy() + _, err := s.Get() + require.ErrorContains(t, err, "unlinked parts in secret") +} + +func TestGettingMissingResolver(t *testing.T) { + mysecret := "a @{referenced:secret}" + s := NewSecret([]byte(mysecret)) + defer s.Destroy() + s.unlinked = make([]string, 0) + s.resolvers = map[string]telegraf.ResolveFunc{ + "@{a:dummy}": func() ([]byte, bool, error) { + return nil, false, nil + }, + } + _, err := s.Get() + expected := `replacing secrets failed: no resolver for "@{referenced:secret}"` + require.EqualError(t, err, expected) +} + +func TestGettingResolverError(t *testing.T) { + mysecret := "a @{referenced:secret}" + s := NewSecret([]byte(mysecret)) + defer s.Destroy() + s.unlinked = make([]string, 0) + s.resolvers = map[string]telegraf.ResolveFunc{ + "@{referenced:secret}": func() ([]byte, bool, error) { + return nil, false, errors.New("broken") + }, + } + _, err := s.Get() + expected := `replacing secrets failed: resolving "@{referenced:secret}" failed: broken` + require.EqualError(t, err, expected) +} + +func TestUninitializedEnclave(t *testing.T) { + s := Secret{} + defer s.Destroy() + require.NoError(t, s.Link(map[string]telegraf.ResolveFunc{})) + retrieved, err := s.Get() + require.NoError(t, err) + defer retrieved.Destroy() + require.Empty(t, retrieved.Bytes()) +} + +func TestEnclaveOpenError(t *testing.T) { + mysecret := "a @{referenced:secret}" + s := NewSecret([]byte(mysecret)) + defer s.Destroy() + memguard.Purge() + err := s.Link(map[string]telegraf.ResolveFunc{}) + require.ErrorContains(t, err, "opening enclave failed") + + s.unlinked = make([]string, 0) + _, err = s.Get() + require.ErrorContains(t, err, "opening enclave failed") +} + +func TestMissingResolver(t *testing.T) { + mysecret := "a @{referenced:secret}" + s := NewSecret([]byte(mysecret)) + defer s.Destroy() + err := s.Link(map[string]telegraf.ResolveFunc{}) + require.ErrorContains(t, err, "linking secrets failed: unlinked part") +} + +func TestSecretConstant(t *testing.T) { + tests := []struct { + name string + cfg []byte + expected string + }{ + { + name: "simple string", + cfg: []byte(` + [[inputs.mockup]] + secret = "a secret" + `), + expected: "a secret", + }, + { + name: "mail address", + cfg: []byte(` + [[inputs.mockup]] + secret = "someone@mock.org" + `), + expected: "someone@mock.org", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := NewConfig() + require.NoError(t, c.LoadConfigData(tt.cfg, EmptySourcePath)) + require.Len(t, c.Inputs, 1) + + // Create a mockup secretstore + store := &MockupSecretStore{ + Secrets: map[string][]byte{"mock": []byte("fail")}, + } + require.NoError(t, store.Init()) + c.SecretStores["mock"] = store + require.NoError(t, c.LinkSecrets()) + + plugin := c.Inputs[0].Input.(*MockupSecretPlugin) + secret, err := plugin.Secret.Get() + require.NoError(t, err) + defer secret.Destroy() + + require.EqualValues(t, tt.expected, secret.TemporaryString()) + }) + } +} + +func TestSecretUnquote(t *testing.T) { + tests := []struct { + name string + cfg []byte + }{ + { + name: "single quotes", + cfg: []byte(` + [[inputs.mockup]] + secret = 'a secret' + expected = 'a secret' + `), + }, + { + name: "double quotes", + cfg: []byte(` + [[inputs.mockup]] + secret = "a secret" + expected = "a secret" + `), + }, + { + name: "triple single quotes", + cfg: []byte(` + [[inputs.mockup]] + secret = '''a secret''' + expected = '''a secret''' + `), + }, + { + name: "triple double quotes", + cfg: []byte(` + [[inputs.mockup]] + secret = """a secret""" + expected = """a secret""" + `), + }, + { + name: "escaped double quotes", + cfg: []byte(` + [[inputs.mockup]] + secret = "\"a secret\"" + expected = "\"a secret\"" + `), + }, + { + name: "mix double-single quotes (single)", + cfg: []byte(` + [[inputs.mockup]] + secret = "'a secret'" + expected = "'a secret'" + `), + }, + { + name: "mix single-double quotes (single)", + cfg: []byte(` + [[inputs.mockup]] + secret = '"a secret"' + expected = '"a secret"' + `), + }, + { + name: "mix double-single quotes (triple-single)", + cfg: []byte(` + [[inputs.mockup]] + secret = """'a secret'""" + expected = """'a secret'""" + `), + }, + { + name: "mix single-double quotes (triple-single)", + cfg: []byte(` + [[inputs.mockup]] + secret = '''"a secret"''' + expected = '''"a secret"''' + `), + }, + { + name: "mix double-single quotes (triple)", + cfg: []byte(` + [[inputs.mockup]] + secret = """'''a secret'''""" + expected = """'''a secret'''""" + `), + }, + { + name: "mix single-double quotes (triple)", + cfg: []byte(` + [[inputs.mockup]] + secret = '''"""a secret"""''' + expected = '''"""a secret"""''' + `), + }, + { + name: "single quotes with backslashes", + cfg: []byte(` + [[inputs.mockup]] + secret = 'Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;' + expected = 'Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;' + `), + }, + { + name: "double quotes with backslashes", + cfg: []byte(` + [[inputs.mockup]] + secret = "Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;" + expected = "Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;" + `), + }, + { + name: "triple single quotes with backslashes", + cfg: []byte(` + [[inputs.mockup]] + secret = '''Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;''' + expected = '''Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;''' + `), + }, + { + name: "triple double quotes with backslashes", + cfg: []byte(` + [[inputs.mockup]] + secret = """Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;""" + expected = """Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;""" + `), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := NewConfig() + require.NoError(t, c.LoadConfigData(tt.cfg, EmptySourcePath)) + require.Len(t, c.Inputs, 1) + + // Create a mockup secretstore + store := &MockupSecretStore{ + Secrets: map[string][]byte{}, + } + require.NoError(t, store.Init()) + c.SecretStores["mock"] = store + require.NoError(t, c.LinkSecrets()) + + plugin := c.Inputs[0].Input.(*MockupSecretPlugin) + secret, err := plugin.Secret.Get() + require.NoError(t, err) + defer secret.Destroy() + + require.EqualValues(t, plugin.Expected, secret.TemporaryString()) + }) + } +} + +func TestSecretEnvironmentVariable(t *testing.T) { + cfg := []byte(` +[[inputs.mockup]] + secret = "$SOME_ENV_SECRET" +`) + t.Setenv("SOME_ENV_SECRET", "an env secret") + + c := NewConfig() + err := c.LoadConfigData(cfg, EmptySourcePath) + require.NoError(t, err) + require.Len(t, c.Inputs, 1) + + // Create a mockup secretstore + store := &MockupSecretStore{ + Secrets: map[string][]byte{}, + } + require.NoError(t, store.Init()) + c.SecretStores["mock"] = store + require.NoError(t, c.LinkSecrets()) + + plugin := c.Inputs[0].Input.(*MockupSecretPlugin) + secret, err := plugin.Secret.Get() + require.NoError(t, err) + defer secret.Destroy() + + require.EqualValues(t, "an env secret", secret.TemporaryString()) +} + +func TestSecretCount(t *testing.T) { + secretCount.Store(0) + cfg := []byte(` +[[inputs.mockup]] + +[[inputs.mockup]] + secret = "a secret" + +[[inputs.mockup]] + secret = "another secret" +`) + + c := NewConfig() + require.NoError(t, c.LoadConfigData(cfg, EmptySourcePath)) + require.Len(t, c.Inputs, 3) + require.Equal(t, int64(2), secretCount.Load()) + + // Remove all secrets and check + for _, ri := range c.Inputs { + input := ri.Input.(*MockupSecretPlugin) + input.Secret.Destroy() + } + require.Equal(t, int64(0), secretCount.Load()) +} + +func TestSecretStoreStatic(t *testing.T) { + cfg := []byte( + ` +[[inputs.mockup]] + secret = "@{mock:secret1}" +[[inputs.mockup]] + secret = "@{mock:secret2}" +[[inputs.mockup]] + secret = "@{mock:a_strange_secret}" +[[inputs.mockup]] + secret = "@{mock:a_weird_secret}" +`) + + c := NewConfig() + err := c.LoadConfigData(cfg, EmptySourcePath) + require.NoError(t, err) + require.Len(t, c.Inputs, 4) + + // Create a mockup secretstore + store := &MockupSecretStore{ + Secrets: map[string][]byte{ + "secret1": []byte("Ood Bnar"), + "secret2": []byte("Thon"), + "a_strange_secret": []byte("Obi-Wan Kenobi"), + "a_weird_secret": []byte("Arca Jeth"), + }, + } + require.NoError(t, store.Init()) + c.SecretStores["mock"] = store + require.NoError(t, c.LinkSecrets()) + + expected := []string{"Ood Bnar", "Thon", "Obi-Wan Kenobi", "Arca Jeth"} + for i, input := range c.Inputs { + plugin := input.Input.(*MockupSecretPlugin) + secret, err := plugin.Secret.Get() + require.NoError(t, err) + require.EqualValues(t, expected[i], secret.TemporaryString()) + secret.Destroy() + } +} + +func TestSecretStoreInvalidKeys(t *testing.T) { + cfg := []byte( + ` +[[inputs.mockup]] + secret = "@{mock:}" +[[inputs.mockup]] + secret = "@{mock:wild?%go}" +[[inputs.mockup]] + secret = "@{mock:a-strange-secret}" +[[inputs.mockup]] + secret = "@{mock:a weird secret}" +`) + + c := NewConfig() + err := c.LoadConfigData(cfg, EmptySourcePath) + require.NoError(t, err) + require.Len(t, c.Inputs, 4) + + // Create a mockup secretstore + store := &MockupSecretStore{ + Secrets: map[string][]byte{ + "": []byte("Ood Bnar"), + "wild?%go": []byte("Thon"), + "a-strange-secret": []byte("Obi-Wan Kenobi"), + "a weird secret": []byte("Arca Jeth"), + }, + } + require.NoError(t, store.Init()) + c.SecretStores["mock"] = store + require.NoError(t, c.LinkSecrets()) + + expected := []string{ + "@{mock:}", + "@{mock:wild?%go}", + "@{mock:a-strange-secret}", + "@{mock:a weird secret}", + } + for i, input := range c.Inputs { + plugin := input.Input.(*MockupSecretPlugin) + secret, err := plugin.Secret.Get() + require.NoError(t, err) + require.EqualValues(t, expected[i], secret.TemporaryString()) + secret.Destroy() + } +} + +func TestSecretStoreDeclarationMissingID(t *testing.T) { + defer func() { unlinkedSecrets = make([]*Secret, 0) }() + + cfg := []byte(`[[secretstores.mockup]]`) + + c := NewConfig() + err := c.LoadConfigData(cfg, EmptySourcePath) + require.ErrorContains(t, err, `error parsing mockup, "mockup" secret-store without ID`) +} + +func TestSecretStoreDeclarationInvalidID(t *testing.T) { + defer func() { unlinkedSecrets = make([]*Secret, 0) }() + + invalidIDs := []string{"foo.bar", "dummy-123", "test!", "wohoo+"} + tmpl := ` + [[secretstores.mockup]] + id = %q +` + for _, id := range invalidIDs { + t.Run(id, func(t *testing.T) { + cfg := []byte(fmt.Sprintf(tmpl, id)) + c := NewConfig() + err := c.LoadConfigData(cfg, EmptySourcePath) + require.ErrorContains(t, err, `error parsing mockup, invalid secret-store ID`) + }) + } +} + +func TestSecretStoreDeclarationValidID(t *testing.T) { + defer func() { unlinkedSecrets = make([]*Secret, 0) }() + + validIDs := []string{"foobar", "dummy123", "test_id", "W0Hoo_lala123"} + tmpl := ` + [[secretstores.mockup]] + id = %q +` + for _, id := range validIDs { + t.Run(id, func(t *testing.T) { + cfg := []byte(fmt.Sprintf(tmpl, id)) + c := NewConfig() + err := c.LoadConfigData(cfg, EmptySourcePath) + require.NoError(t, err) + }) + } +} + +type SecretImplTestSuite struct { + suite.Suite + protected bool +} + +func (tsuite *SecretImplTestSuite) SetupSuite() { + if tsuite.protected { + EnableSecretProtection() + } else { + DisableSecretProtection() + } +} + +func (*SecretImplTestSuite) TearDownSuite() { + EnableSecretProtection() +} + +func (*SecretImplTestSuite) TearDownTest() { + unlinkedSecrets = make([]*Secret, 0) +} + +func (tsuite *SecretImplTestSuite) TestSecretEqualTo() { + t := tsuite.T() + mysecret := "a wonderful test" + s := NewSecret([]byte(mysecret)) + defer s.Destroy() + + equal, err := s.EqualTo([]byte(mysecret)) + require.NoError(t, err) + require.True(t, equal) + + equal, err = s.EqualTo([]byte("some random text")) + require.NoError(t, err) + require.False(t, equal) +} + +func (tsuite *SecretImplTestSuite) TestSecretStoreInvalidReference() { + t := tsuite.T() + + cfg := []byte( + ` +[[inputs.mockup]] + secret = "@{mock:test}" +`) + + c := NewConfig() + require.NoError(t, c.LoadConfigData(cfg, EmptySourcePath)) + require.Len(t, c.Inputs, 1) + + // Create a mockup secretstore + store := &MockupSecretStore{ + Secrets: map[string][]byte{"test": []byte("Arca Jeth")}, + } + require.NoError(t, store.Init()) + c.SecretStores["foo"] = store + err := c.LinkSecrets() + require.EqualError(t, err, `unknown secret-store for "@{mock:test}"`) + + for _, input := range c.Inputs { + plugin := input.Input.(*MockupSecretPlugin) + secret, err := plugin.Secret.Get() + require.EqualError(t, err, `unlinked parts in secret: @{mock:test}`) + require.Empty(t, secret) + } +} + +func (tsuite *SecretImplTestSuite) TestSecretStoreStaticChanging() { + t := tsuite.T() + + cfg := []byte( + ` +[[inputs.mockup]] + secret = "@{mock:secret}" +`) + + c := NewConfig() + err := c.LoadConfigData(cfg, EmptySourcePath) + require.NoError(t, err) + require.Len(t, c.Inputs, 1) + + // Create a mockup secretstore + store := &MockupSecretStore{ + Secrets: map[string][]byte{"secret": []byte("Ood Bnar")}, + Dynamic: false, + } + require.NoError(t, store.Init()) + c.SecretStores["mock"] = store + require.NoError(t, c.LinkSecrets()) + + sequence := []string{"Ood Bnar", "Thon", "Obi-Wan Kenobi", "Arca Jeth"} + plugin := c.Inputs[0].Input.(*MockupSecretPlugin) + secret, err := plugin.Secret.Get() + require.NoError(t, err) + defer secret.Destroy() + + require.EqualValues(t, "Ood Bnar", secret.TemporaryString()) + + for _, v := range sequence { + store.Secrets["secret"] = []byte(v) + secret, err := plugin.Secret.Get() + require.NoError(t, err) + + // The secret should not change as the store is marked non-dyamic! + require.EqualValues(t, "Ood Bnar", secret.TemporaryString()) + secret.Destroy() + } +} + +func (tsuite *SecretImplTestSuite) TestSecretStoreDynamic() { + t := tsuite.T() + + cfg := []byte( + ` +[[inputs.mockup]] + secret = "@{mock:secret}" +`) + + c := NewConfig() + err := c.LoadConfigData(cfg, EmptySourcePath) + require.NoError(t, err) + require.Len(t, c.Inputs, 1) + + // Create a mockup secretstore + store := &MockupSecretStore{ + Secrets: map[string][]byte{"secret": []byte("Ood Bnar")}, + Dynamic: true, + } + require.NoError(t, store.Init()) + c.SecretStores["mock"] = store + require.NoError(t, c.LinkSecrets()) + + sequence := []string{"Ood Bnar", "Thon", "Obi-Wan Kenobi", "Arca Jeth"} + plugin := c.Inputs[0].Input.(*MockupSecretPlugin) + for _, v := range sequence { + store.Secrets["secret"] = []byte(v) + secret, err := plugin.Secret.Get() + require.NoError(t, err) + + // The secret should not change as the store is marked non-dynamic! + require.EqualValues(t, v, secret.TemporaryString()) + secret.Destroy() + } +} + +func (tsuite *SecretImplTestSuite) TestSecretSet() { + t := tsuite.T() + + cfg := []byte(` + [[inputs.mockup]] + secret = "a secret" + `) + c := NewConfig() + require.NoError(t, c.LoadConfigData(cfg, EmptySourcePath)) + require.Len(t, c.Inputs, 1) + require.NoError(t, c.LinkSecrets()) + + plugin := c.Inputs[0].Input.(*MockupSecretPlugin) + + secret, err := plugin.Secret.Get() + require.NoError(t, err) + defer secret.Destroy() + require.EqualValues(t, "a secret", secret.TemporaryString()) + + require.NoError(t, plugin.Secret.Set([]byte("another secret"))) + newsecret, err := plugin.Secret.Get() + require.NoError(t, err) + defer newsecret.Destroy() + require.EqualValues(t, "another secret", newsecret.TemporaryString()) +} + +func (tsuite *SecretImplTestSuite) TestSecretSetResolve() { + t := tsuite.T() + cfg := []byte(` + [[inputs.mockup]] + secret = "@{mock:secret}" + `) + c := NewConfig() + require.NoError(t, c.LoadConfigData(cfg, EmptySourcePath)) + require.Len(t, c.Inputs, 1) + + // Create a mockup secretstore + store := &MockupSecretStore{ + Secrets: map[string][]byte{"secret": []byte("Ood Bnar")}, + Dynamic: true, + } + require.NoError(t, store.Init()) + c.SecretStores["mock"] = store + require.NoError(t, c.LinkSecrets()) + + plugin := c.Inputs[0].Input.(*MockupSecretPlugin) + + secret, err := plugin.Secret.Get() + require.NoError(t, err) + defer secret.Destroy() + require.EqualValues(t, "Ood Bnar", secret.TemporaryString()) + + require.NoError(t, plugin.Secret.Set([]byte("@{mock:secret} is cool"))) + newsecret, err := plugin.Secret.Get() + require.NoError(t, err) + defer newsecret.Destroy() + require.EqualValues(t, "Ood Bnar is cool", newsecret.TemporaryString()) +} + +func (tsuite *SecretImplTestSuite) TestSecretSetResolveInvalid() { + t := tsuite.T() + + cfg := []byte(` + [[inputs.mockup]] + secret = "@{mock:secret}" + `) + c := NewConfig() + require.NoError(t, c.LoadConfigData(cfg, EmptySourcePath)) + require.Len(t, c.Inputs, 1) + + // Create a mockup secretstore + store := &MockupSecretStore{ + Secrets: map[string][]byte{"secret": []byte("Ood Bnar")}, + Dynamic: true, + } + require.NoError(t, store.Init()) + c.SecretStores["mock"] = store + require.NoError(t, c.LinkSecrets()) + + plugin := c.Inputs[0].Input.(*MockupSecretPlugin) + + secret, err := plugin.Secret.Get() + require.NoError(t, err) + defer secret.Destroy() + require.EqualValues(t, "Ood Bnar", secret.TemporaryString()) + + err = plugin.Secret.Set([]byte("@{mock:another_secret}")) + require.ErrorContains(t, err, `linking new secrets failed: unlinked part "@{mock:another_secret}"`) +} + +func (tsuite *SecretImplTestSuite) TestSecretInvalidWarn() { + t := tsuite.T() + + // Intercept the log output + var buf bytes.Buffer + backup := log.Writer() + log.SetOutput(&buf) + defer log.SetOutput(backup) + + cfg := []byte(` + [[inputs.mockup]] + secret = "server=a user=@{mock:secret-with-invalid-chars} pass=@{mock:secret_pass}" + `) + c := NewConfig() + require.NoError(t, c.LoadConfigData(cfg, EmptySourcePath)) + require.Len(t, c.Inputs, 1) + + require.Contains(t, buf.String(), `W! Secret "@{mock:secret-with-invalid-chars}" contains invalid character(s)`) + require.NotContains(t, buf.String(), "@{mock:secret_pass}") +} + +func TestSecretImplUnprotected(t *testing.T) { + impl := &unprotectedSecretImpl{} + container := impl.Container([]byte("foobar")) + require.NotNil(t, container) + c, ok := container.(*unprotectedSecretContainer) + require.True(t, ok) + require.Equal(t, "foobar", string(c.buf.content)) + buf, err := container.Buffer() + require.NoError(t, err) + require.NotNil(t, buf) + require.Equal(t, []byte("foobar"), buf.Bytes()) + require.Equal(t, "foobar", buf.TemporaryString()) + require.Equal(t, "foobar", buf.String()) +} + +func TestSecretImplTestSuiteUnprotected(t *testing.T) { + suite.Run(t, &SecretImplTestSuite{protected: false}) +} + +func TestSecretImplTestSuiteProtected(t *testing.T) { + suite.Run(t, &SecretImplTestSuite{protected: true}) +} + +// Mockup (input) plugin for testing to avoid cyclic dependencies +type MockupSecretPlugin struct { + Secret Secret `toml:"secret"` + Expected string `toml:"expected"` +} + +func (*MockupSecretPlugin) SampleConfig() string { return "Mockup test secret plugin" } +func (*MockupSecretPlugin) Gather(_ telegraf.Accumulator) error { return nil } + +type MockupSecretStore struct { + Secrets map[string][]byte + Dynamic bool +} + +func (*MockupSecretStore) Init() error { + return nil +} +func (*MockupSecretStore) SampleConfig() string { + return "Mockup test secret plugin" +} + +func (s *MockupSecretStore) Get(key string) ([]byte, error) { + v, found := s.Secrets[key] + if !found { + return nil, errors.New("not found") + } + return v, nil +} + +func (s *MockupSecretStore) Set(key, value string) error { + s.Secrets[key] = []byte(value) + return nil +} + +func (s *MockupSecretStore) List() ([]string, error) { + keys := make([]string, 0, len(s.Secrets)) + for k := range s.Secrets { + keys = append(keys, k) + } + return keys, nil +} +func (s *MockupSecretStore) GetResolver(key string) (telegraf.ResolveFunc, error) { + return func() ([]byte, bool, error) { + v, err := s.Get(key) + return v, s.Dynamic, err + }, nil +} + +// Register the mockup plugin on loading +func init() { + // Register the mockup input plugin for the required names + inputs.Add("mockup", func() telegraf.Input { return &MockupSecretPlugin{} }) + secretstores.Add("mockup", func(string) telegraf.SecretStore { + return &MockupSecretStore{} + }) +} diff --git a/config/secret_unprotected.go b/config/secret_unprotected.go new file mode 100644 index 0000000..69fcd33 --- /dev/null +++ b/config/secret_unprotected.go @@ -0,0 +1,94 @@ +package config + +import ( + "bytes" + "unsafe" +) + +type unprotectedSecretImpl struct{} + +func (*unprotectedSecretImpl) Container(secret []byte) secretContainer { + return &unprotectedSecretContainer{buf: newUnlockedBuffer(secret)} +} + +func (*unprotectedSecretImpl) EmptyBuffer() SecretBuffer { + return &unlockedBuffer{} +} + +func (*unprotectedSecretImpl) Wipe(secret []byte) { + for i := range secret { + secret[i] = 0 + } +} + +type unlockedBuffer struct { + content []byte +} + +func newUnlockedBuffer(secret []byte) *unlockedBuffer { + return &unlockedBuffer{bytes.Clone(secret)} +} + +func (lb *unlockedBuffer) Size() int { + return len(lb.content) +} + +func (*unlockedBuffer) Grow(int) { + // The underlying byte-buffer will grow dynamically +} + +func (lb *unlockedBuffer) Bytes() []byte { + return lb.content +} + +func (lb *unlockedBuffer) TemporaryString() string { + //nolint:gosec // G103: Valid use of unsafe call to cast underlying bytes to string + return unsafe.String(&lb.content[0], len(lb.content)) +} + +func (lb *unlockedBuffer) String() string { + return string(lb.content) +} + +func (lb *unlockedBuffer) Destroy() { + selectedImpl.Wipe(lb.content) + lb.content = nil +} + +type unprotectedSecretContainer struct { + buf *unlockedBuffer +} + +func (c *unprotectedSecretContainer) Destroy() { + if c.buf == nil { + return + } + + // Wipe the secret from memory + c.buf.Destroy() + c.buf = nil +} + +func (c *unprotectedSecretContainer) Equals(ref []byte) (bool, error) { + if c.buf == nil { + return false, nil + } + + return bytes.Equal(c.buf.content, ref), nil +} + +func (c *unprotectedSecretContainer) Buffer() (SecretBuffer, error) { + if c.buf == nil { + return &unlockedBuffer{}, nil + } + + return newUnlockedBuffer(c.buf.content), nil +} + +func (*unprotectedSecretContainer) AsBuffer(secret []byte) SecretBuffer { + return &unlockedBuffer{secret} +} + +func (c *unprotectedSecretContainer) Replace(secret []byte) { + c.buf = newUnlockedBuffer(secret) +} diff --git a/config/testdata/addressbook.proto b/config/testdata/addressbook.proto new file mode 100644 index 0000000..3ed0eb5 --- /dev/null +++ b/config/testdata/addressbook.proto @@ -0,0 +1,28 @@ +syntax = "proto3"; + +package addressbook; + +message Person { + string name = 1; + int32 id = 2; // Unique ID number for this person. + string email = 3; + uint32 age = 4; + + enum PhoneType { + MOBILE = 0; + HOME = 1; + WORK = 2; + } + + message PhoneNumber { + string number = 1; + PhoneType type = 2; + } + + repeated PhoneNumber phones = 5; +} + +message AddressBook { + repeated Person people = 1; + repeated string tags = 2; +} diff --git a/config/testdata/azure_monitor.toml b/config/testdata/azure_monitor.toml new file mode 100644 index 0000000..6151bea --- /dev/null +++ b/config/testdata/azure_monitor.toml @@ -0,0 +1,4 @@ +[[outputs.azure_monitor]] + +[[outputs.azure_monitor]] + namespace_prefix = "" diff --git a/config/testdata/default_parser.toml b/config/testdata/default_parser.toml new file mode 100644 index 0000000..4568b5e --- /dev/null +++ b/config/testdata/default_parser.toml @@ -0,0 +1,2 @@ +[[inputs.file]] + files = ["metrics"] diff --git a/config/testdata/default_parser_exec.toml b/config/testdata/default_parser_exec.toml new file mode 100644 index 0000000..345343f --- /dev/null +++ b/config/testdata/default_parser_exec.toml @@ -0,0 +1,2 @@ +[[inputs.exec]] + command = '/usr/bin/echo {"value": 42}' diff --git a/config/testdata/deprecated_field_filter.toml b/config/testdata/deprecated_field_filter.toml new file mode 100644 index 0000000..ca36089 --- /dev/null +++ b/config/testdata/deprecated_field_filter.toml @@ -0,0 +1,8 @@ +[[inputs.file]] + pass = ["foo"] + fieldpass = ["bar"] + fieldinclude = ["baz"] + + drop = ["foo"] + fielddrop = ["bar"] + fieldexclude = ["baz"] diff --git a/config/testdata/envvar_comments.toml b/config/testdata/envvar_comments.toml new file mode 100644 index 0000000..5f35f04 --- /dev/null +++ b/config/testdata/envvar_comments.toml @@ -0,0 +1,99 @@ +# Telegraf Configuration +# +# Telegraf is entirely plugin driven. All metrics are gathered from the +# declared inputs, and sent to the declared outputs. +# +# Plugins must be declared in here to be active. +# To deactivate a plugin, comment out the name and any variables. +# +# Use 'telegraf -config telegraf.conf -test' to see what metrics a config +# file would generate. +# +# Environment variables can be used anywhere in this config file, simply surround +# them with ${}. For strings the variable must be within quotes (ie, "${STR_VAR}"), +# for numbers and booleans they should be plain (ie, ${INT_VAR}, ${BOOL_VAR}) + +[global_tags] + +[agent] +interval = "10s" +round_interval = true +metric_batch_size = 1000 +metric_buffer_limit = 10000 +collection_jitter = "0s" +flush_interval = '10s' +flush_jitter = "0s" +precision = "" +hostname = '' +omit_hostname = false + +[[outputs.influxdb]] + setting1 = '#'#test + setting2 = '''#'''#test + setting3 = "#"#test + setting4 = """#"""#test + wicked1 = "\""#test + wicked2 = """\""""#test + +[[inputs.cpu]] + percpu = true + #totalcpu = true + # collect_cpu_time = false + ## report_active = false + +[[a.plugin]] + mylist = [ + "value 1", # a good value + "value 2", # a better value + "value 3", "value 4", + 'value5', """tagwith#value""", + ] # Should work + +[[some.stuff]] + a = 'not a #comment' + b = '''not a #comment''' + c = "not a #comment" + d = """not a #comment""" + e = '''not a #comment containing "quotes"''' + f = '''not a #comment containing 'quotes'?''' + g = """not a #comment containing "quotes"?""" + +# Issue #14237 +[[inputs.myplugin]] +value = '''This isn't a #comment.''' + +[[processors.starlark]] + script = """ +# Drop fields if they contain a string. +# +# Example Input: +# measurement,host=hostname a=1,b="somestring" 1597255410000000000 +# +# Example Output: +# measurement,host=hostname a=1 1597255410000000000 + +def apply(metric): + for k, v in metric.fields.items(): + if type(v) == "string": + metric.fields.pop(k) + + return metric +""" + +[[processors.starlark]] + script = ''' +# Drop fields if they contain a string. +# +# Example Input: +# measurement,host=hostname a=1,b="somestring" 1597255410000000000 +# +# Example Output: +# measurement,host=hostname a=1 1597255410000000000 + +def apply(metric): + for k, v in metric.fields.items(): + if type(v) == "string": + metric.fields.pop(k) + + return metric +''' diff --git a/config/testdata/envvar_comments_expected.toml b/config/testdata/envvar_comments_expected.toml new file mode 100644 index 0000000..3e38656 --- /dev/null +++ b/config/testdata/envvar_comments_expected.toml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + +[global_tags] + +[agent] +interval = "10s" +round_interval = true +metric_batch_size = 1000 +metric_buffer_limit = 10000 +collection_jitter = "0s" +flush_interval = '10s' +flush_jitter = "0s" +precision = "" +hostname = '' +omit_hostname = false + +[[outputs.influxdb]] + setting1 = '#' + setting2 = '''#''' + setting3 = "#" + setting4 = """#""" + wicked1 = "\"" + wicked2 = """\"""" + +[[inputs.cpu]] + percpu = true + + + + +[[a.plugin]] + mylist = [ + "value 1", + "value 2", + "value 3", "value 4", + 'value5', """tagwith#value""", + ] + +[[some.stuff]] + a = 'not a #comment' + b = '''not a #comment''' + c = "not a #comment" + d = """not a #comment""" + e = '''not a #comment containing "quotes"''' + f = '''not a #comment containing 'quotes'?''' + g = """not a #comment containing "quotes"?""" + + +[[inputs.myplugin]] +value = '''This isn't a #comment.''' + +[[processors.starlark]] + script = """ +# Drop fields if they contain a string. +# +# Example Input: +# measurement,host=hostname a=1,b="somestring" 1597255410000000000 +# +# Example Output: +# measurement,host=hostname a=1 1597255410000000000 + +def apply(metric): + for k, v in metric.fields.items(): + if type(v) == "string": + metric.fields.pop(k) + + return metric +""" + +[[processors.starlark]] + script = ''' +# Drop fields if they contain a string. +# +# Example Input: +# measurement,host=hostname a=1,b="somestring" 1597255410000000000 +# +# Example Output: +# measurement,host=hostname a=1 1597255410000000000 + +def apply(metric): + for k, v in metric.fields.items(): + if type(v) == "string": + metric.fields.pop(k) + + return metric +''' diff --git a/config/testdata/filter_metricpass.toml b/config/testdata/filter_metricpass.toml new file mode 100644 index 0000000..a604c8d --- /dev/null +++ b/config/testdata/filter_metricpass.toml @@ -0,0 +1,2 @@ +[[processors.processor]] + metricpass = '("state" in tags && tags.state == "on") || time > timestamp("2023-04-24T00:00:00Z")' diff --git a/config/testdata/inline_table.toml b/config/testdata/inline_table.toml new file mode 100644 index 0000000..525fdce --- /dev/null +++ b/config/testdata/inline_table.toml @@ -0,0 +1,7 @@ +[[outputs.http]] + headers = { Authorization = "Token $TOKEN",Content-Type = "application/json" } + taginclude = ["org_id"] + +[[outputs.http]] + headers = { Authorization = "Token $TOKEN",Content-Type = "application/json" } + taginclude = ["org_id"] diff --git a/config/testdata/invalid_field.toml b/config/testdata/invalid_field.toml new file mode 100644 index 0000000..4c718d7 --- /dev/null +++ b/config/testdata/invalid_field.toml @@ -0,0 +1,2 @@ +[[inputs.http_listener_v2]] + not_a_field = true diff --git a/config/testdata/invalid_field_in_parser_table.toml b/config/testdata/invalid_field_in_parser_table.toml new file mode 100644 index 0000000..b2d7301 --- /dev/null +++ b/config/testdata/invalid_field_in_parser_table.toml @@ -0,0 +1,5 @@ +[[inputs.parser]] + data_format = "xpath_json" + + [[inputs.parser.xpath]] + not_a_field = true diff --git a/config/testdata/invalid_field_in_parserfunc_table.toml b/config/testdata/invalid_field_in_parserfunc_table.toml new file mode 100644 index 0000000..36b2b20 --- /dev/null +++ b/config/testdata/invalid_field_in_parserfunc_table.toml @@ -0,0 +1,5 @@ +[[inputs.parser_func]] + data_format = "xpath_json" + + [[inputs.parser_func.xpath]] + not_a_field = true diff --git a/config/testdata/invalid_field_processor.toml b/config/testdata/invalid_field_processor.toml new file mode 100644 index 0000000..ec72055 --- /dev/null +++ b/config/testdata/invalid_field_processor.toml @@ -0,0 +1,2 @@ +[[processors.processor]] + not_a_field = true diff --git a/config/testdata/invalid_field_processor_in_parser.toml b/config/testdata/invalid_field_processor_in_parser.toml new file mode 100644 index 0000000..39877a7 --- /dev/null +++ b/config/testdata/invalid_field_processor_in_parser.toml @@ -0,0 +1,3 @@ +[[processors.processor_parser]] + not_a_field = true + data_format = "influx" diff --git a/config/testdata/invalid_field_processor_in_parser_table.toml b/config/testdata/invalid_field_processor_in_parser_table.toml new file mode 100644 index 0000000..1a583d9 --- /dev/null +++ b/config/testdata/invalid_field_processor_in_parser_table.toml @@ -0,0 +1,5 @@ +[[processors.processor_parser]] + data_format = "xpath_json" + + [[processors.processor_parser.xpath]] + not_a_field = true diff --git a/config/testdata/invalid_field_processor_in_parserfunc.toml b/config/testdata/invalid_field_processor_in_parserfunc.toml new file mode 100644 index 0000000..f7e6a43 --- /dev/null +++ b/config/testdata/invalid_field_processor_in_parserfunc.toml @@ -0,0 +1,3 @@ +[[processors.processor_parserfunc]] + not_a_field = true + data_format = "influx" diff --git a/config/testdata/invalid_field_processor_in_parserfunc_table.toml b/config/testdata/invalid_field_processor_in_parserfunc_table.toml new file mode 100644 index 0000000..36b2b20 --- /dev/null +++ b/config/testdata/invalid_field_processor_in_parserfunc_table.toml @@ -0,0 +1,5 @@ +[[inputs.parser_func]] + data_format = "xpath_json" + + [[inputs.parser_func.xpath]] + not_a_field = true diff --git a/config/testdata/invalid_field_processor_with_parser.toml b/config/testdata/invalid_field_processor_with_parser.toml new file mode 100644 index 0000000..39877a7 --- /dev/null +++ b/config/testdata/invalid_field_processor_with_parser.toml @@ -0,0 +1,3 @@ +[[processors.processor_parser]] + not_a_field = true + data_format = "influx" diff --git a/config/testdata/invalid_field_processor_with_parserfunc.toml b/config/testdata/invalid_field_processor_with_parserfunc.toml new file mode 100644 index 0000000..f7e6a43 --- /dev/null +++ b/config/testdata/invalid_field_processor_with_parserfunc.toml @@ -0,0 +1,3 @@ +[[processors.processor_parserfunc]] + not_a_field = true + data_format = "influx" diff --git a/config/testdata/invalid_field_with_parser.toml b/config/testdata/invalid_field_with_parser.toml new file mode 100644 index 0000000..bb366c8 --- /dev/null +++ b/config/testdata/invalid_field_with_parser.toml @@ -0,0 +1,3 @@ +[[inputs.parser]] + not_a_field = true + data_format = "influx" diff --git a/config/testdata/invalid_field_with_parserfunc.toml b/config/testdata/invalid_field_with_parserfunc.toml new file mode 100644 index 0000000..dc771da --- /dev/null +++ b/config/testdata/invalid_field_with_parserfunc.toml @@ -0,0 +1,3 @@ +[[inputs.parser_func]] + not_a_field = true + data_format = "influx" diff --git a/config/testdata/non_slice_slice.toml b/config/testdata/non_slice_slice.toml new file mode 100644 index 0000000..f92edcc --- /dev/null +++ b/config/testdata/non_slice_slice.toml @@ -0,0 +1,4 @@ +[[outputs.http]] + [outputs.http.headers] + Content-Type = "application/json" + taginclude = ["org_id"] diff --git a/config/testdata/parsers_new.toml b/config/testdata/parsers_new.toml new file mode 100644 index 0000000..e0e5132 --- /dev/null +++ b/config/testdata/parsers_new.toml @@ -0,0 +1,65 @@ +[[inputs.parser_test_new]] + data_format = "collectd" + +[[inputs.parser_test_new]] + data_format = "csv" + csv_header_row_count = 42 + +[[inputs.parser_test_new]] + data_format = "dropwizard" + +[[inputs.parser_test_new]] + data_format = "form_urlencoded" + +[[inputs.parser_test_new]] + data_format = "graphite" + +[[inputs.parser_test_new]] + data_format = "grok" + grok_patterns = ["%{COMBINED_LOG_FORMAT}"] + +[[inputs.parser_test_new]] + data_format = "influx" + +[[inputs.parser_test_new]] + data_format = "json" + +[[inputs.parser_test_new]] + data_format = "json_v2" +[[inputs.parser_test_new.json_v2]] +[[inputs.parser_test_new.json_v2.field]] + path = "" + rename = "" + type = "int" + +[[inputs.parser_test_new]] + data_format = "logfmt" + +[[inputs.parser_test_new]] + data_format = "nagios" + +[[inputs.parser_test_new]] + data_format = "prometheus" + +[[inputs.parser_test_new]] + data_format = "prometheusremotewrite" + +[[inputs.parser_test_new]] + data_format = "value" + +[[inputs.parser_test_new]] + data_format = "wavefront" + +[[inputs.parser_test_new]] + data_format = "xml" + +[[inputs.parser_test_new]] + data_format = "xpath_json" + +[[inputs.parser_test_new]] + data_format = "xpath_msgpack" + +[[inputs.parser_test_new]] + data_format = "xpath_protobuf" + xpath_protobuf_file = "testdata/addressbook.proto" + xpath_protobuf_type = "addressbook.AddressBook" diff --git a/config/testdata/processor_order/multiple_processors.toml b/config/testdata/processor_order/multiple_processors.toml new file mode 100644 index 0000000..9a16cb7 --- /dev/null +++ b/config/testdata/processor_order/multiple_processors.toml @@ -0,0 +1,7 @@ +[[processors.processor]] + +[[processors.parser_test]] + +[[processors.processor_parser]] + +[[processors.processor_parserfunc]] diff --git a/config/testdata/processor_order/multiple_processors_messy_order.toml b/config/testdata/processor_order/multiple_processors_messy_order.toml new file mode 100644 index 0000000..0abb84c --- /dev/null +++ b/config/testdata/processor_order/multiple_processors_messy_order.toml @@ -0,0 +1,16 @@ +[[processors.parser_test]] + +[[processors.processor_parser]] + order = 2 + +[[processors.processor_parserfunc]] + +[[processors.processor]] + order = 1 + +[[processors.processor_parser]] + order = 3 + +[[processors.processor_parserfunc]] + order = 3 + diff --git a/config/testdata/processor_order/multiple_processors_simple_order.toml b/config/testdata/processor_order/multiple_processors_simple_order.toml new file mode 100644 index 0000000..521c97e --- /dev/null +++ b/config/testdata/processor_order/multiple_processors_simple_order.toml @@ -0,0 +1,9 @@ +[[processors.parser_test]] + +[[processors.processor_parser]] + +[[processors.processor_parserfunc]] + +[[processors.processor]] + order = 1 + diff --git a/config/testdata/processors_with_parsers.toml b/config/testdata/processors_with_parsers.toml new file mode 100644 index 0000000..bdbf826 --- /dev/null +++ b/config/testdata/processors_with_parsers.toml @@ -0,0 +1,65 @@ +[[processors.parser_test]] + data_format = "collectd" + +[[processors.parser_test]] + data_format = "csv" + csv_header_row_count = 42 + +[[processors.parser_test]] + data_format = "dropwizard" + +[[processors.parser_test]] + data_format = "form_urlencoded" + +[[processors.parser_test]] + data_format = "graphite" + +[[processors.parser_test]] + data_format = "grok" + grok_patterns = ["%{COMBINED_LOG_FORMAT}"] + +[[processors.parser_test]] + data_format = "influx" + +[[processors.parser_test]] + data_format = "json" + +[[processors.parser_test]] + data_format = "json_v2" +[[processors.parser_test.json_v2]] +[[processors.parser_test.json_v2.field]] + path = "" + rename = "" + type = "int" + +[[processors.parser_test]] + data_format = "logfmt" + +[[processors.parser_test]] + data_format = "nagios" + +[[processors.parser_test]] + data_format = "prometheus" + +[[processors.parser_test]] + data_format = "prometheusremotewrite" + +[[processors.parser_test]] + data_format = "value" + +[[processors.parser_test]] + data_format = "wavefront" + +[[processors.parser_test]] + data_format = "xml" + +[[processors.parser_test]] + data_format = "xpath_json" + +[[processors.parser_test]] + data_format = "xpath_msgpack" + +[[processors.parser_test]] + data_format = "xpath_protobuf" + xpath_protobuf_file = "testdata/addressbook.proto" + xpath_protobuf_type = "addressbook.AddressBook" diff --git a/config/testdata/serializers_new.toml b/config/testdata/serializers_new.toml new file mode 100644 index 0000000..d11139e --- /dev/null +++ b/config/testdata/serializers_new.toml @@ -0,0 +1,32 @@ +[[outputs.serializer_test_new]] + data_format = "carbon2" + +[[outputs.serializer_test_new]] + data_format = "csv" + +[[outputs.serializer_test_new]] + data_format = "graphite" + +[[outputs.serializer_test_new]] + data_format = "influx" + +[[outputs.serializer_test_new]] + data_format = "json" + +[[outputs.serializer_test_new]] + data_format = "msgpack" + +[[outputs.serializer_test_new]] + data_format = "nowmetric" + +[[outputs.serializer_test_new]] + data_format = "prometheus" + +[[outputs.serializer_test_new]] + data_format = "prometheusremotewrite" + +[[outputs.serializer_test_new]] + data_format = "splunkmetric" + +[[outputs.serializer_test_new]] + data_format = "wavefront" diff --git a/config/testdata/serializers_old.toml b/config/testdata/serializers_old.toml new file mode 100644 index 0000000..6b556ca --- /dev/null +++ b/config/testdata/serializers_old.toml @@ -0,0 +1,32 @@ +[[outputs.serializer_test_old]] + data_format = "carbon2" + +[[outputs.serializer_test_old]] + data_format = "csv" + +[[outputs.serializer_test_old]] + data_format = "graphite" + +[[outputs.serializer_test_old]] + data_format = "influx" + +[[outputs.serializer_test_old]] + data_format = "json" + +[[outputs.serializer_test_old]] + data_format = "msgpack" + +[[outputs.serializer_test_old]] + data_format = "nowmetric" + +[[outputs.serializer_test_old]] + data_format = "prometheus" + +[[outputs.serializer_test_old]] + data_format = "prometheusremotewrite" + +[[outputs.serializer_test_old]] + data_format = "splunkmetric" + +[[outputs.serializer_test_old]] + data_format = "wavefront" diff --git a/config/testdata/single_plugin.toml b/config/testdata/single_plugin.toml new file mode 100644 index 0000000..8d03815 --- /dev/null +++ b/config/testdata/single_plugin.toml @@ -0,0 +1,11 @@ +[[inputs.memcached]] + servers = ["localhost"] + namepass = ["metricname1"] + namedrop = ["metricname2"] + fieldinclude = ["some", "strings"] + fieldexclude = ["other", "stuff"] + interval = "5s" + [inputs.memcached.tagpass] + goodtag = ["mytag"] + [inputs.memcached.tagdrop] + badtag = ["othertag"] diff --git a/config/testdata/single_plugin_env_vars.toml b/config/testdata/single_plugin_env_vars.toml new file mode 100644 index 0000000..d705e61 --- /dev/null +++ b/config/testdata/single_plugin_env_vars.toml @@ -0,0 +1,35 @@ +# Telegraf Configuration +# +# Telegraf is entirely plugin driven. All metrics are gathered from the +# declared inputs, and sent to the declared outputs. +# +# Plugins must be declared in here to be active. +# To deactivate a plugin, comment out the name and any variables. +# +# Use 'telegraf -config telegraf.conf -test' to see what metrics a config +# file would generate. +# +# Environment variables can be used anywhere in this config file, simply surround +# them with ${}. For strings the variable must be within quotes (ie, "${STR_VAR}"), +# for numbers and booleans they should be plain (ie, ${INT_VAR}, ${BOOL_VAR}) + +[[inputs.memcached]] + # this comment line will be ignored by the parser + servers = ["$MY_TEST_SERVER"] + namepass = ["metricname1", "ip_${MY_TEST_SERVER}_name"] # this comment will be ignored as well + namedrop = ["metricname2"] + fieldinclude = ["some", "strings"] + fieldexclude = ["other", "stuff"] + interval = "$TEST_INTERVAL" + ##### this input is provided to test multiline strings + command = """ +Raw command which may or may not contain # in it +# is unique""" # Multiline comment black starting with # + [inputs.memcached.tagpass] + goodtag = ["mytag", """tagwith#value""", + # comment in between array items + # should ignore "quotes" in comments + '''TagWithMultilineSyntax''', ## ignore this comment + ] # hastag + [inputs.memcached.tagdrop] + badtag = ["othertag"] diff --git a/config/testdata/single_plugin_with_comment_in_array.toml b/config/testdata/single_plugin_with_comment_in_array.toml new file mode 100644 index 0000000..d97c6f3 --- /dev/null +++ b/config/testdata/single_plugin_with_comment_in_array.toml @@ -0,0 +1,5 @@ +[[inputs.memcached]] + servers = [ + # A comment in the array + "localhost" + ] diff --git a/config/testdata/single_plugin_with_separators.toml b/config/testdata/single_plugin_with_separators.toml new file mode 100644 index 0000000..708914c --- /dev/null +++ b/config/testdata/single_plugin_with_separators.toml @@ -0,0 +1,13 @@ +[[inputs.memcached]] + servers = ["localhost"] + namepass = ["metricname1"] + namepass_separator = "." + namedrop = ["metricname2"] + namedrop_separator = "." + fieldinclude = ["some", "strings"] + fieldexclude = ["other", "stuff"] + interval = "5s" + [inputs.memcached.tagpass] + goodtag = ["mytag"] + [inputs.memcached.tagdrop] + badtag = ["othertag"] diff --git a/config/testdata/slice_comment.toml b/config/testdata/slice_comment.toml new file mode 100644 index 0000000..1177e5f --- /dev/null +++ b/config/testdata/slice_comment.toml @@ -0,0 +1,5 @@ +[[outputs.http]] + scopes = [ + # comment + "test" # comment + ] diff --git a/config/testdata/special_types.key b/config/testdata/special_types.key new file mode 100644 index 0000000..25db3c9 --- /dev/null +++ b/config/testdata/special_types.key @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIFYI4Hm+jRW3OC3zvoWDaCig6E7X0Ql9l8elHPU3e5+toAoGCCqGSM49 +AwEHoUQDQgAEGOw1XQ84Ai3GTZJ5o5u1yTFgA3VLZTTT0oHol06LRj5Md3oRy0MQ +QO5OhsAGGz16SYcPHf77aZmf2Of6ixYaLQ== +-----END EC PRIVATE KEY----- diff --git a/config/testdata/special_types.pem b/config/testdata/special_types.pem new file mode 100644 index 0000000..8097a52 --- /dev/null +++ b/config/testdata/special_types.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBjTCCATOgAwIBAgIRALJ1hlgDYCh5dWfr6tdrBEYwCgYIKoZIzj0EAwIwFDES +MBAGA1UEAxMJbG9jYWxob3N0MB4XDTIyMDExMjA3NTgyMloXDTIyMDExMzA3NTgy +MlowFDESMBAGA1UEAxMJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD +QgAEGOw1XQ84Ai3GTZJ5o5u1yTFgA3VLZTTT0oHol06LRj5Md3oRy0MQQO5OhsAG +Gz16SYcPHf77aZmf2Of6ixYaLaNmMGQwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQW +MBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUuKpGXAb1DaVSffJ/xuF6 +FE31CC8wFAYDVR0RBA0wC4IJbG9jYWxob3N0MAoGCCqGSM49BAMCA0gAMEUCIHCb +m2phe189gftRke2Mo45lDsEAGaXsjA4lO/IOMo5lAiEA5k2X0bQfFhSfAcZPFtDI +iUwvC9SD3+CnzkP35O0jo+c= +-----END CERTIFICATE----- diff --git a/config/testdata/special_types.toml b/config/testdata/special_types.toml new file mode 100644 index 0000000..b38773f --- /dev/null +++ b/config/testdata/special_types.toml @@ -0,0 +1,8 @@ +[[inputs.http_listener_v2]] + write_timeout = "1s" + max_body_size = "1MiB" + paths = [ """ +/path/ +""" ] + tls_cert = """./testdata/special_types.pem""" + tls_key = '''./testdata/special_types.key''' diff --git a/config/testdata/state_persistence_input_all_different.toml b/config/testdata/state_persistence_input_all_different.toml new file mode 100644 index 0000000..b8b38de --- /dev/null +++ b/config/testdata/state_persistence_input_all_different.toml @@ -0,0 +1,42 @@ +[[inputs.statetest]] + +[[inputs.statetest]] + servers = ["myserver.com", "myserver.org"] + +[[inputs.statetest]] + servers = ["myserver.org", "myserver.com"] + +[[inputs.statetest]] + servers = ["myserver.org", "myserver.com"] + port = 0 + +[[inputs.statetest]] + servers = ["myserver.org", "myserver.com"] + port = 80 + method = "strange" + [inputs.statetest.params] + a = "foo" + b = "bar" + +[[inputs.statetest]] + servers = ["myserver.org", "myserver.com"] + port = 80 + method = "strange" + setup = [ + {name="alpha", factor=3.1415, enabled=true, bits=[1,2,3]} + ] + [inputs.statetest.params] + a = "foo" + b = "bar" + +[[inputs.statetest]] + servers = ["myserver.org", "myserver.com"] + port = 80 + method = "strange" + setup = [ + {name="alpha", factor=3.1415, enabled=true, bits=[1,2,3]}, + {name="beta", factor=2.71828, enabled=true, bits=[1,2,3]} + ] + [inputs.statetest.params] + a = "foo" + b = "bar" diff --git a/config/testdata/state_persistence_input_all_same.toml b/config/testdata/state_persistence_input_all_same.toml new file mode 100644 index 0000000..58fc21b --- /dev/null +++ b/config/testdata/state_persistence_input_all_same.toml @@ -0,0 +1,60 @@ +[[inputs.statetest]] + servers = ["myserver.org", "myserver.com"] + port = 80 + method = "strange" + setup = [ + {name="alpha", factor=3.1415, enabled=true, bits=[1,2,3]}, + {name="beta", factor=2.71828, enabled=true, bits=[1,2,3]} + ] + [inputs.statetest.params] + a = "foo" + b = "bar" + +[[inputs.statetest]] + ## What a wonderful world... + servers = ["myserver.org", "myserver.com"] + port = 80 + method = "strange" + setup = [ + {name="alpha", factor=3.1415, enabled=true, bits=[1,2,3]}, + {name="beta", factor=2.71828, enabled=true, bits=[1,2,3]} + ] + [inputs.statetest.params] + a = "foo" + b = "bar" + +[[inputs.statetest]] + servers = ["myserver.org", "myserver.com"] + method = "strange" + setup = [ + {name="alpha", factor=3.1415, enabled=true, bits=[1,2,3]}, + {name="beta", factor=2.71828, enabled=true, bits=[1,2,3]} + ] + port = 80 + [inputs.statetest.params] + a = "foo" + b = "bar" + +[[inputs.statetest]] + servers = ["myserver.org", "myserver.com"] + port = 80 + method = "strange" + setup = [ + {name="alpha", factor=3.1415, enabled=true, bits=[1,2,3]}, + {name="beta", factor=2.71828, enabled=true, bits=[1,2,3]} + ] + [inputs.statetest.params] + b = "bar" + a = "foo" + +[[inputs.statetest]] + method = "strange" + servers = ["myserver.org", "myserver.com"] + port = 80 + setup = [ + {name="alpha", factor=3.1415, enabled=true, bits=[1,2,3]}, + {name="beta", factor=2.71828, enabled=true, bits=[1,2,3]} + ] + [inputs.statetest.params] + a = "foo" + b = "bar" diff --git a/config/testdata/state_persistence_input_store_load.toml b/config/testdata/state_persistence_input_store_load.toml new file mode 100644 index 0000000..62983af --- /dev/null +++ b/config/testdata/state_persistence_input_store_load.toml @@ -0,0 +1,17 @@ +[[inputs.statetest]] + servers = ["myserverA.org"] + port = 42 + method = "strange" + +[[inputs.statetest]] + servers = ["myserverB.org"] + port = 23 + method = "strange" + +[[inputs.statetest]] + servers = ["myserverC.org"] + port = 80 + method = "strange" + [inputs.statetest.params] + a = "foo" + b = "bar" diff --git a/config/testdata/state_persistence_processors.toml b/config/testdata/state_persistence_processors.toml new file mode 100644 index 0000000..4e9a4f3 --- /dev/null +++ b/config/testdata/state_persistence_processors.toml @@ -0,0 +1,8 @@ +[[processors.statetest]] + option = "foo" + +[[processors.statetest]] + option = "bar" + +[[processors.statetest]] + option = "captain obvious" diff --git a/config/testdata/subconfig/exec.conf b/config/testdata/subconfig/exec.conf new file mode 100644 index 0000000..d621e78 --- /dev/null +++ b/config/testdata/subconfig/exec.conf @@ -0,0 +1,4 @@ +[[inputs.exec]] + # the command to run + command = "/usr/bin/myothercollector --foo=bar" + name_suffix = "_myothercollector" diff --git a/config/testdata/subconfig/memcached.conf b/config/testdata/subconfig/memcached.conf new file mode 100644 index 0000000..2cd07d1 --- /dev/null +++ b/config/testdata/subconfig/memcached.conf @@ -0,0 +1,11 @@ +[[inputs.memcached]] + servers = ["192.168.1.1"] + namepass = ["metricname1"] + namedrop = ["metricname2"] + pass = ["some", "strings"] + drop = ["other", "stuff"] + interval = "5s" + [inputs.memcached.tagpass] + goodtag = ["mytag"] + [inputs.memcached.tagdrop] + badtag = ["othertag"] diff --git a/config/testdata/subconfig/procstat.conf b/config/testdata/subconfig/procstat.conf new file mode 100644 index 0000000..8270866 --- /dev/null +++ b/config/testdata/subconfig/procstat.conf @@ -0,0 +1,2 @@ +[[inputs.procstat]] + pid_file = "/var/run/grafana-server.pid" diff --git a/config/testdata/telegraf-agent.toml b/config/testdata/telegraf-agent.toml new file mode 100644 index 0000000..bac0e45 --- /dev/null +++ b/config/testdata/telegraf-agent.toml @@ -0,0 +1,297 @@ +# Telegraf configuration + +# Telegraf is entirely plugin driven. All metrics are gathered from the +# declared inputs. + +# Even if a plugin has no configuration, it must be declared in here +# to be active. Declaring a plugin means just specifying the name +# as a section with no variables. To deactivate a plugin, comment +# out the name and any variables. + +# Use 'telegraf -config telegraf.toml -test' to see what metrics a config +# file would generate. + +# One rule that plugins conform to is wherever a connection string +# can be passed, the values '' and 'localhost' are treated specially. +# They indicate to the plugin to use their own builtin configuration to +# connect to the local system. + +# NOTE: The configuration has a few required parameters. They are marked +# with 'required'. Be sure to edit those to make this configuration work. + +# Tags can also be specified via a normal map, but only one form at a time: +[global_tags] + dc = "us-east-1" + +# Configuration for telegraf agent +[agent] + # Default data collection interval for all plugins + interval = "10s" + + # run telegraf in debug mode + debug = false + + # Override default hostname, if empty use os.Hostname() + hostname = "" + + +############################################################################### +# OUTPUTS # +############################################################################### + +# Configuration for influxdb server to send metrics to +[[outputs.influxdb]] + # The full HTTP endpoint URL for your InfluxDB instance + # Multiple urls can be specified for InfluxDB cluster support. Server to + # write to will be randomly chosen each interval. + urls = ["http://localhost:8086"] # required. + + # The target database for metrics. This database must already exist + database = "telegraf" # required. + +[[outputs.influxdb]] + urls = ["udp://localhost:8089"] + database = "udp-telegraf" + +# Configuration for the Kafka server to send metrics to +[[outputs.kafka]] + # URLs of kafka brokers + brokers = ["localhost:9092"] + # Kafka topic for producer messages + topic = "telegraf" + # Telegraf tag to use as a routing key + # ie, if this tag exists, its value will be used as the routing key + routing_tag = "host" + + +############################################################################### +# PLUGINS # +############################################################################### + +# Read Apache status information (mod_status) +[[inputs.apache]] + # An array of Apache status URI to gather stats. + urls = ["http://localhost/server-status?auto"] + +# Read metrics about cpu usage +[[inputs.cpu]] + # Whether to report per-cpu stats or not + percpu = true + # Whether to report total system cpu stats or not + totalcpu = true + # Comment this line if you want the raw CPU time metrics + fieldexclude = ["cpu_time"] + +# Read metrics about disk usage by mount point +[[inputs.diskio]] + # no configuration + +# Read metrics from one or many disque servers +[[inputs.disque]] + # An array of URI to gather stats about. Specify an ip or hostname + # with optional port and password. ie disque://localhost, disque://10.10.3.33:18832, + # 10.0.0.1:10000, etc. + # + # If no servers are specified, then localhost is used as the host. + servers = ["localhost"] + +# Read stats from one or more Elasticsearch servers or clusters +[[inputs.elasticsearch]] + # specify a list of one or more Elasticsearch servers + servers = ["http://localhost:9200"] + + # set local to false when you want to read the indices stats from all nodes + # within the cluster + local = true + +# Read flattened metrics from one or more commands that output JSON to stdout +[[inputs.exec]] + # the command to run + command = "/usr/bin/mycollector --foo=bar" + name_suffix = "_mycollector" + +# Read metrics of haproxy, via socket or csv stats page +[[inputs.haproxy]] + # An array of address to gather stats about. Specify an ip on hostname + # with optional port. ie localhost, 10.10.3.33:1936, etc. + # + # If no servers are specified, then default to 127.0.0.1:1936 + servers = ["http://myhaproxy.com:1936", "http://anotherhaproxy.com:1936"] + # Or you can also use local socket(not work yet) + # servers = ["socket:/run/haproxy/admin.sock"] + +# Read flattened metrics from one or more JSON HTTP endpoints +[[inputs.http]] + # a name for the service being polled + name_override = "webserver_stats" + + # URL of each server in the service's cluster + urls = [ + "http://localhost:9999/stats/", + "http://localhost:9998/stats/", + ] + + # HTTP method to use (case-sensitive) + # method = "GET" + + data_format = "json" + +# Read metrics about disk IO by device +[[inputs.diskio]] + # no configuration + +# read metrics from a Kafka 0.9+ topic +[[inputs.kafka_consumer]] + ## kafka brokers + brokers = ["localhost:9092"] + ## topic(s) to consume + topics = ["telegraf"] + ## the name of the consumer group + consumer_group = "telegraf_metrics_consumers" + ## Offset (must be either "oldest" or "newest") + offset = "oldest" + +# Read metrics from a LeoFS Server via SNMP +[[inputs.leofs]] + # An array of URI to gather stats about LeoFS. + # Specify an ip or hostname with port. ie 127.0.0.1:4020 + # + # If no servers are specified, then 127.0.0.1 is used as the host and 4020 as the port. + servers = ["127.0.0.1:4021"] + +# Read metrics about memory usage +[[inputs.mem]] + # no configuration + +# Read metrics from one or many memcached servers +[[inputs.memcached]] + # An array of address to gather stats about. Specify an ip on hostname + # with optional port. ie localhost, 10.0.0.1:11211, etc. + # + # If no servers are specified, then localhost is used as the host. + servers = ["localhost"] + +# Telegraf plugin for gathering metrics from N Mesos masters +[[inputs.mesos]] + # Timeout, in ms. + timeout = 100 + # A list of Mesos masters, default value is localhost:5050. + masters = ["localhost:5050"] + # Metrics groups to be collected, by default, all enabled. + master_collections = ["resources","master","system","slaves","frameworks","messages","evqueue","registrar"] + +# Read metrics from one or many MongoDB servers +[[inputs.mongodb]] + # An array of URI to gather stats about. Specify an ip or hostname + # with optional port add password. ie mongodb://user:auth_key@10.10.3.30:27017, + # mongodb://10.10.3.33:18832, 10.0.0.1:10000, etc. + # + # If no servers are specified, then 127.0.0.1 is used as the host and 27107 as the port. + servers = ["127.0.0.1:27017"] + +# Read metrics from one or many mysql servers +[[inputs.mysql]] + # specify servers via a url matching: + # [username[:password]@][protocol[(address)]]/[?tls=[true|false|skip-verify]] + # e.g. + # servers = ["root:root@http://10.0.0.18/?tls=false"] + # servers = ["root:passwd@tcp(127.0.0.1:3306)/"] + # + # If no servers are specified, then localhost is used as the host. + servers = ["localhost"] + +# Read metrics about network interface usage +[[inputs.net]] + # By default, telegraf gathers stats from any up interface (excluding loopback) + # Setting interfaces will tell it to gather these explicit interfaces, + # regardless of status. + # + # interfaces = ["eth0", ... ] + +# Read Nginx's basic status information (ngx_http_stub_status_module) +[[inputs.nginx]] + # An array of Nginx stub_status URI to gather stats. + urls = ["http://localhost/status"] + +# Ping given url(s) and return statistics +[[inputs.ping]] + # urls to ping + urls = ["www.google.com"] # required + # number of pings to send (ping -c ) + count = 1 # required + # interval, in s, at which to ping. 0 == default (ping -i ) + ping_interval = 0.0 + # ping timeout, in s. 0 == no timeout (ping -t ) + timeout = 0.0 + # interface to send ping from (ping -I ) + interface = "" + +# Read metrics from one or many postgresql servers +[[inputs.postgresql]] + # specify address via a url matching: + # postgres://[pqgotest[:password]]@localhost[/dbname]?sslmode=[disable|verify-ca|verify-full] + # or a simple string: + # host=localhost user=pqgotest password=... sslmode=... dbname=app_production + # + # All connection parameters are optional. By default, the host is localhost + # and the user is the currently running user. For localhost, we default + # to sslmode=disable as well. + # + # Without the dbname parameter, the driver will default to a database + # with the same name as the user. This dbname is just for instantiating a + # connection with the server and doesn't restrict the databases we are trying + # to grab metrics for. + # + + address = "sslmode=disable" + + # A list of databases to pull metrics about. If not specified, metrics for all + # databases are gathered. + + # databases = ["app_production", "blah_testing"] + + # [[postgresql.servers]] + # address = "influx@remoteserver" + +# Read metrics from one or many prometheus clients +[[inputs.prometheus]] + # An array of urls to scrape metrics from. + urls = ["http://localhost:9100/metrics"] + +# Read metrics from one or many RabbitMQ servers via the management API +[[inputs.rabbitmq]] + # Specify servers via an array of tables + # name = "rmq-server-1" # optional tag + # url = "http://localhost:15672" + # username = "guest" + # password = "guest" + + # A list of nodes to pull metrics about. If not specified, metrics for + # all nodes are gathered. + # nodes = ["rabbit@node1", "rabbit@node2"] + +# Read metrics from one or many redis servers +[[inputs.redis]] + # An array of URI to gather stats about. Specify an ip or hostname + # with optional port add password. ie redis://localhost, redis://10.10.3.33:18832, + # 10.0.0.1:10000, etc. + # + # If no servers are specified, then localhost is used as the host. + servers = ["localhost"] + +# Read metrics from one or many RethinkDB servers +[[inputs.rethinkdb]] + # An array of URI to gather stats about. Specify an ip or hostname + # with optional port add password. ie rethinkdb://user:auth_key@10.10.3.30:28105, + # rethinkdb://10.10.3.33:18832, 10.0.0.1:10000, etc. + # + # If no servers are specified, then 127.0.0.1 is used as the host and 28015 as the port. + servers = ["127.0.0.1:28015"] + +# Read metrics about swap memory usage +[[inputs.swap]] + # no configuration + +# Read metrics about system load & uptime +[[inputs.system]] + # no configuration diff --git a/config/testdata/wrong_cert_path.toml b/config/testdata/wrong_cert_path.toml new file mode 100644 index 0000000..99d359f --- /dev/null +++ b/config/testdata/wrong_cert_path.toml @@ -0,0 +1,5 @@ +[[inputs.http_listener_v2]] + write_timeout = "1s" + max_body_size = "1MiB" + tls_cert = "invalid.pem" + tls_key = "invalid.key" diff --git a/config/testdata/wrong_field_type.toml b/config/testdata/wrong_field_type.toml new file mode 100644 index 0000000..237176e --- /dev/null +++ b/config/testdata/wrong_field_type.toml @@ -0,0 +1,2 @@ +[[inputs.http_listener_v2]] + port = "80" diff --git a/config/testdata/wrong_field_type2.toml b/config/testdata/wrong_field_type2.toml new file mode 100644 index 0000000..6f3def7 --- /dev/null +++ b/config/testdata/wrong_field_type2.toml @@ -0,0 +1,2 @@ +[[inputs.http_listener_v2]] + methods = "POST" diff --git a/config/types.go b/config/types.go new file mode 100644 index 0000000..f6a7c00 --- /dev/null +++ b/config/types.go @@ -0,0 +1,85 @@ +package config + +import ( + "fmt" + "regexp" + "strconv" + "strings" + "time" + + "github.com/alecthomas/units" +) + +// Regexp for day specifications in durations +var durationDayRe = regexp.MustCompile(`(\d+(?:\.\d+)?)d`) + +// Duration is a time.Duration +type Duration time.Duration + +// Size is an int64 +type Size int64 + +// UnmarshalText parses the duration from the Text config file +func (d *Duration) UnmarshalText(b []byte) error { + // convert to string + durStr := string(b) + + // Value is a TOML number (e.g. 3, 10, 3.5) + // First try parsing as integer seconds + sI, err := strconv.ParseInt(durStr, 10, 64) + if err == nil { + dur := time.Second * time.Duration(sI) + *d = Duration(dur) + return nil + } + // Second try parsing as float seconds + sF, err := strconv.ParseFloat(durStr, 64) + if err == nil { + dur := float64(time.Second) * sF + *d = Duration(dur) + return nil + } + + // Finally, try value is a TOML string (e.g. "3s", 3s) or literal (e.g. '3s') + if durStr == "" { + *d = Duration(0) + return nil + } + + // Handle "day" intervals and replace them with the "hours" equivalent + for _, m := range durationDayRe.FindAllStringSubmatch(durStr, -1) { + days, err := strconv.ParseFloat(m[1], 64) + if err != nil { + return fmt.Errorf("converting %q to hours failed: %w", durStr, err) + } + hours := strconv.FormatFloat(days*24, 'f', -1, 64) + "h" + durStr = strings.Replace(durStr, m[0], hours, 1) + } + + dur, err := time.ParseDuration(durStr) + if err != nil { + return err + } + + *d = Duration(dur) + return nil +} + +func (s *Size) UnmarshalText(b []byte) error { + if len(b) == 0 { + return nil + } + + str := string(b) + val, err := strconv.ParseInt(str, 10, 64) + if err == nil { + *s = Size(val) + return nil + } + val, err = units.ParseStrictBytes(str) + if err != nil { + return err + } + *s = Size(val) + return nil +} diff --git a/config/types_test.go b/config/types_test.go new file mode 100644 index 0000000..2011abc --- /dev/null +++ b/config/types_test.go @@ -0,0 +1,277 @@ +package config_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/config" + "github.com/influxdata/telegraf/plugins/inputs" + "github.com/influxdata/telegraf/plugins/processors/reverse_dns" +) + +func TestConfigDuration(t *testing.T) { + c := config.NewConfig() + err := c.LoadConfigData([]byte(` +[[processors.reverse_dns]] + cache_ttl = "3h" + lookup_timeout = "17s" + max_parallel_lookups = 13 + ordered = true + [[processors.reverse_dns.lookup]] + field = "source_ip" + dest = "source_name" +`), config.EmptySourcePath) + require.NoError(t, err) + require.Len(t, c.Processors, 1) + p := c.Processors[0].Processor.(*reverse_dns.ReverseDNS) + require.EqualValues(t, 3*time.Hour, p.CacheTTL) + require.EqualValues(t, 17*time.Second, p.LookupTimeout) + require.Equal(t, 13, p.MaxParallelLookups) + require.True(t, p.Ordered) +} + +func TestDuration(t *testing.T) { + var d config.Duration + + d = config.Duration(0) + require.NoError(t, d.UnmarshalText([]byte(`1s`))) + require.Equal(t, time.Second, time.Duration(d)) + + d = config.Duration(0) + require.NoError(t, d.UnmarshalText([]byte(`10`))) + require.Equal(t, 10*time.Second, time.Duration(d)) + + d = config.Duration(0) + require.NoError(t, d.UnmarshalText([]byte(`1.5`))) + require.Equal(t, 1500*time.Millisecond, time.Duration(d)) + + d = config.Duration(0) + require.NoError(t, d.UnmarshalText([]byte(``))) + require.Equal(t, 0*time.Second, time.Duration(d)) + + require.Error(t, d.UnmarshalText([]byte(`"1"`))) // string missing unit + require.Error(t, d.UnmarshalText([]byte(`'2'`))) // string missing unit + require.Error(t, d.UnmarshalText([]byte(`'ns'`))) // string missing time + require.Error(t, d.UnmarshalText([]byte(`'us'`))) // string missing time +} + +func TestSize(t *testing.T) { + var s config.Size + + require.NoError(t, s.UnmarshalText([]byte(`1B`))) + require.Equal(t, int64(1), int64(s)) + + s = config.Size(0) + require.NoError(t, s.UnmarshalText([]byte(`1`))) + require.Equal(t, int64(1), int64(s)) + + s = config.Size(0) + require.NoError(t, s.UnmarshalText([]byte(`1GB`))) + require.Equal(t, int64(1000*1000*1000), int64(s)) + + s = config.Size(0) + require.NoError(t, s.UnmarshalText([]byte(`12GiB`))) + require.Equal(t, int64(12*1024*1024*1024), int64(s)) +} + +func TestTOMLParsingStringDurations(t *testing.T) { + cfg := []byte(` +[[inputs.typesmockup]] + durations = [ + "1s", + '''1s''', + '1s', + "1.5s", + "", + '', + "2h", + "42m", + "100ms", + "100us", + "100ns", + "1d", + "7.5d", + "7d8h15m", + "3d7d", + "15m8h3.5d" + ] +`) + + expected := []time.Duration{ + 1 * time.Second, + 1 * time.Second, + 1 * time.Second, + 1500 * time.Millisecond, + 0, + 0, + 2 * time.Hour, + 42 * time.Minute, + 100 * time.Millisecond, + 100 * time.Microsecond, + 100 * time.Nanosecond, + 24 * time.Hour, + 7*24*time.Hour + 12*time.Hour, + 7*24*time.Hour + 8*time.Hour + 15*time.Minute, + 10 * 24 * time.Hour, + 3*24*time.Hour + 12*time.Hour + 8*time.Hour + 15*time.Minute, + } + + // Load the data + c := config.NewConfig() + err := c.LoadConfigData(cfg, config.EmptySourcePath) + require.NoError(t, err) + require.Len(t, c.Inputs, 1) + plugin := c.Inputs[0].Input.(*MockupTypesPlugin) + + require.Empty(t, plugin.Sizes) + require.Len(t, plugin.Durations, len(expected)) + for i, actual := range plugin.Durations { + require.EqualValuesf(t, expected[i], actual, "case %d failed", i) + } +} + +func TestTOMLParsingIntegerDurations(t *testing.T) { + cfg := []byte(` +[[inputs.typesmockup]] + durations = [ + 1, + 10, + 3601 + ] +`) + + expected := []time.Duration{ + 1 * time.Second, + 10 * time.Second, + 3601 * time.Second, + } + + // Load the data + c := config.NewConfig() + err := c.LoadConfigData(cfg, config.EmptySourcePath) + require.NoError(t, err) + require.Len(t, c.Inputs, 1) + plugin := c.Inputs[0].Input.(*MockupTypesPlugin) + + require.Empty(t, plugin.Sizes) + require.Len(t, plugin.Durations, len(expected)) + for i, actual := range plugin.Durations { + require.EqualValuesf(t, expected[i], actual, "case %d failed", i) + } +} + +func TestTOMLParsingFloatDurations(t *testing.T) { + cfg := []byte(` +[[inputs.typesmockup]] + durations = [ + 42.0, + 1.5 + ] +`) + + expected := []time.Duration{ + 42 * time.Second, + 1500 * time.Millisecond, + } + + // Load the data + c := config.NewConfig() + err := c.LoadConfigData(cfg, config.EmptySourcePath) + require.NoError(t, err) + require.Len(t, c.Inputs, 1) + plugin := c.Inputs[0].Input.(*MockupTypesPlugin) + + require.Empty(t, plugin.Sizes) + require.Len(t, plugin.Durations, len(expected)) + for i, actual := range plugin.Durations { + require.EqualValuesf(t, expected[i], actual, "case %d failed", i) + } +} + +func TestTOMLParsingStringSizes(t *testing.T) { + cfg := []byte(` +[[inputs.typesmockup]] + sizes = [ + "1B", + "1", + '1', + '''15kB''', + """15KiB""", + "1GB", + "12GiB" + ] +`) + + expected := []int64{ + 1, + 1, + 1, + 15 * 1000, + 15 * 1024, + 1000 * 1000 * 1000, + 12 * 1024 * 1024 * 1024, + } + + // Load the data + c := config.NewConfig() + err := c.LoadConfigData(cfg, config.EmptySourcePath) + require.NoError(t, err) + require.Len(t, c.Inputs, 1) + plugin := c.Inputs[0].Input.(*MockupTypesPlugin) + + require.Empty(t, plugin.Durations) + require.Len(t, plugin.Sizes, len(expected)) + for i, actual := range plugin.Sizes { + require.EqualValuesf(t, expected[i], actual, "case %d failed", i) + } +} + +func TestTOMLParsingIntegerSizes(t *testing.T) { + cfg := []byte(` +[[inputs.typesmockup]] + sizes = [ + 0, + 1, + 1000, + 1024 + ] +`) + + expected := []int64{ + 0, + 1, + 1000, + 1024, + } + + // Load the data + c := config.NewConfig() + err := c.LoadConfigData(cfg, config.EmptySourcePath) + require.NoError(t, err) + require.Len(t, c.Inputs, 1) + plugin := c.Inputs[0].Input.(*MockupTypesPlugin) + + require.Empty(t, plugin.Durations) + require.Len(t, plugin.Sizes, len(expected)) + for i, actual := range plugin.Sizes { + require.EqualValuesf(t, expected[i], actual, "case %d failed", i) + } +} + +// Mockup (input) plugin for testing to avoid cyclic dependencies +type MockupTypesPlugin struct { + Durations []config.Duration `toml:"durations"` + Sizes []config.Size `toml:"sizes"` +} + +func (*MockupTypesPlugin) SampleConfig() string { return "Mockup test types plugin" } +func (*MockupTypesPlugin) Gather(_ telegraf.Accumulator) error { return nil } + +// Register the mockup plugin on loading +func init() { + // Register the mockup input plugin for the required names + inputs.Add("typesmockup", func() telegraf.Input { return &MockupTypesPlugin{} }) +} diff --git a/docs/AGGREGATORS.md b/docs/AGGREGATORS.md new file mode 100644 index 0000000..9f4fc81 --- /dev/null +++ b/docs/AGGREGATORS.md @@ -0,0 +1,150 @@ +# Aggregator Plugins + +This section is for developers who want to create a new aggregator plugin. + +## Aggregator Plugin Guidelines + +* A aggregator must conform to the [telegraf.Aggregator][] interface. +* Aggregators should call `aggregators.Add` in their `init` function to + register themselves. See below for a quick example. +* To be available within Telegraf itself, plugins must register themselves + using a file in `github.com/influxdata/telegraf/plugins/aggregators/all` + named according to the plugin name. Make sure you also add build-tags to + conditionally build the plugin. +* Each plugin requires a file called `sample.conf` containing the sample + configuration for the plugin in TOML format. Please consult the + [Sample Config][] page for the latest style guidelines. +* Each plugin `README.md` file should include the `sample.conf` file in a + section describing the configuration by specifying a `toml` section in the + form `toml @sample.conf`. The specified file(s) are then injected + automatically into the Readme. +* The Aggregator plugin will need to keep caches of metrics that have passed + through it. This should be done using the builtin `HashID()` function of + each metric. +* When the `Reset()` function is called, all caches should be cleared. +* Follow the recommended [Code Style][]. + +[telegraf.Aggregator]: https://godoc.org/github.com/influxdata/telegraf#Aggregator +[Sample Config]: /docs/developers/SAMPLE_CONFIG.md +[Code Style]: /docs/developers/CODE_STYLE.md + +### Aggregator Plugin Example + +### Registration + +Registration of the plugin on `plugins/aggregators/all/min.go`: + +```go +//go:build !custom || aggregators || aggregators.min + +package all + +import _ "github.com/influxdata/telegraf/plugins/aggregators/min" // register plugin +``` + +The _build-tags_ in the first line allow to selectively include/exclude your +plugin when customizing Telegraf. + +### Plugin + +Content of your plugin file e.g. `min.go` + +```go +//go:generate ../../../tools/readme_config_includer/generator +package min + +// min.go + +import ( + _ "embed" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/aggregators" +) + +//go:embed sample.conf +var sampleConfig string + +type Min struct { + // caches for metric fields, names, and tags + fieldCache map[uint64]map[string]float64 + nameCache map[uint64]string + tagCache map[uint64]map[string]string +} + +func NewMin() telegraf.Aggregator { + m := &Min{} + m.Reset() + return m +} + +func (*Min) SampleConfig() string { + return sampleConfig +} + +func (m *Min) Init() error { + return nil +} + +func (m *Min) Add(in telegraf.Metric) { + id := in.HashID() + if _, ok := m.nameCache[id]; !ok { + // hit an uncached metric, create caches for first time: + m.nameCache[id] = in.Name() + m.tagCache[id] = in.Tags() + m.fieldCache[id] = make(map[string]float64) + for k, v := range in.Fields() { + if fv, ok := convert(v); ok { + m.fieldCache[id][k] = fv + } + } + } else { + for k, v := range in.Fields() { + if fv, ok := convert(v); ok { + if _, ok := m.fieldCache[id][k]; !ok { + // hit an uncached field of a cached metric + m.fieldCache[id][k] = fv + continue + } + if fv < m.fieldCache[id][k] { + // set new minimum + m.fieldCache[id][k] = fv + } + } + } + } +} + +func (m *Min) Push(acc telegraf.Accumulator) { + for id, _ := range m.nameCache { + fields := map[string]interface{}{} + for k, v := range m.fieldCache[id] { + fields[k+"_min"] = v + } + acc.AddFields(m.nameCache[id], fields, m.tagCache[id]) + } +} + +func (m *Min) Reset() { + m.fieldCache = make(map[uint64]map[string]float64) + m.nameCache = make(map[uint64]string) + m.tagCache = make(map[uint64]map[string]string) +} + +func convert(in interface{}) (float64, bool) { + switch v := in.(type) { + case float64: + return v, true + case int64: + return float64(v), true + default: + return 0, false + } +} + +func init() { + aggregators.Add("min", func() telegraf.Aggregator { + return NewMin() + }) +} +``` diff --git a/docs/AGGREGATORS_AND_PROCESSORS.md b/docs/AGGREGATORS_AND_PROCESSORS.md new file mode 100644 index 0000000..aa39b01 --- /dev/null +++ b/docs/AGGREGATORS_AND_PROCESSORS.md @@ -0,0 +1,93 @@ +# Aggregator & Processor Plugins + +Telegraf has the concept of aggregator and processor plugins, which sit between +inputs and outputs. These plugins allow a user to do additional processing or +aggregation to collected metrics. + +```text +┌───────────┐ +│ │ +│ CPU │───┐ +│ │ │ +└───────────┘ │ + │ +┌───────────┐ │ ┌───────────┐ +│ │ │ │ │ +│ Memory │───┤ ┌──▶│ InfluxDB │ +│ │ │ │ │ │ +└───────────┘ │ ┌─────────────┐ ┌─────────────┐ │ └───────────┘ + │ │ │ │Aggregators │ │ +┌───────────┐ │ │Processors │ │ - mean │ │ ┌───────────┐ +│ │ │ │ - transform │ │ - quantiles │ │ │ │ +│ MySQL │───┼───▶│ - decorate │────▶│ - min/max │───┼──▶│ File │ +│ │ │ │ - filter │ │ - count │ │ │ │ +└───────────┘ │ │ │ │ │ │ └───────────┘ + │ └─────────────┘ └─────────────┘ │ +┌───────────┐ │ │ ┌───────────┐ +│ │ │ │ │ │ +│ SNMP │───┤ └──▶│ Kafka │ +│ │ │ │ │ +└───────────┘ │ └───────────┘ + │ +┌───────────┐ │ +│ │ │ +│ Docker │───┘ +│ │ +└───────────┘ +``` + +## Ordering + +Processors are run first, then aggregators, then processors a second time. + +Allowing processors to run again after aggregators gives users the opportunity +to run a processor on any aggregated metrics. This behavior can be a bit +surprising to new users and may cause weird behavior in metrics. For example, +if the user scales data, it could get scaled twice! + +To disable this behavior set the `skip_processors_after_aggregators` agent +configuration setting to true. Another option is to use metric filtering as +described below. + +## Metric Filtering + +Use [metric filtering][] to control which metrics are passed through a processor +or aggregator. If a metric is filtered out the metric bypasses the plugin and +is passed downstream to the next plugin. + +[metric filtering]: CONFIGURATION.md#measurement-filtering + +## Processor + +Processor plugins process metrics as they pass through and immediately emit +results based on the values they process. For example, this could be printing +all metrics or adding a tag to all metrics that pass through. + +See the [processors][] for a full list of processor plugins available. + +[processors]: https://github.com/influxdata/telegraf/tree/master/plugins/processors + +## Aggregator + +Aggregator plugins, on the other hand, are a bit more complicated. Aggregators +are typically for emitting new _aggregate_ metrics, such as a running mean, +minimum, maximum, or standard deviation. For this reason, all _aggregator_ +plugins are configured with a `period`. The `period` is the size of the window +of metrics that each _aggregate_ represents. In other words, the emitted +_aggregate_ metric will be the aggregated value of the past `period` seconds. + +Since many users will only care about their aggregates and not every single +metric gathered, there is also a `drop_original` argument, which tells Telegraf +to only emit the aggregates and not the original metrics. + +Since aggregates are created for each measurement, field, and unique tag +combination the plugin receives, you can make use of `taginclude` to group +aggregates by specific tags only. + +See the [aggregators][] for a full list of aggregator plugins available. + +**Note:** Aggregator plugins only aggregate metrics within their periods +(i.e. `now() - period`). Data with a timestamp earlier than `now() - period` +cannot be included. + +[aggregators]: https://github.com/influxdata/telegraf/tree/master/plugins/aggregators diff --git a/docs/APPARMOR.md b/docs/APPARMOR.md new file mode 100644 index 0000000..6fc7f68 --- /dev/null +++ b/docs/APPARMOR.md @@ -0,0 +1,26 @@ +# AppArmor + +When running Telegraf under AppArmor users may see denial messages depending on +the Telegraf plugins used and the AppArmor profile applied. Telegraf does not +have control over the AppArmor profiles used. If users wish to address denials, +then they must understand the collections made by their choice of Telegraf +plugins, the denial messages, and the impact of changes to their AppArmor +profiles. + +## Example Denial + +For example, users might see denial messages such as: + +```s +type=AVC msg=audit(1588901740.036:2457789): apparmor="DENIED" operation="ptrace" profile="docker-default" pid=9030 comm="telegraf" requested_mask="read" denied_mask="read" peer="unconfined" +``` + +In this case, Telegraf will also need the ability to ptrace(read). User's will +first need to analyze the denial message for the operation and requested mask. +Then consider if the required changes make sense. There may be additional +denials even after initial changes. + +For more details around AppArmor settings and configuration, users can check out +the `man 5 apparmor.d` man page on their system or the [AppArmor wiki][wiki]. + +[wiki]: https://gitlab.com/apparmor/apparmor/-/wikis/home diff --git a/docs/COMMANDS_AND_FLAGS.md b/docs/COMMANDS_AND_FLAGS.md new file mode 100644 index 0000000..79e04a8 --- /dev/null +++ b/docs/COMMANDS_AND_FLAGS.md @@ -0,0 +1,57 @@ +# Telegraf Commands & Flags + +The following page describes some of the commands and flags available via the +Telegraf command line interface. + +## Usage + +General usage of Telegraf, requires passing in at least one config file with +the plugins the user wishes to use: + +```bash +telegraf --config config.toml +``` + +## Help + +To get the full list of subcommands and flags run: + +```bash +telegraf help +``` + +Here are some commonly used flags that users should be aware of: + +* `--config-directory`: Read all config files from a directory +* `--debug`: Enable additional debug logging +* `--once`: Run one collection and flush interval then exit +* `--test`: Run only inputs, output to stdout, and exit + +Check out the full help out for more available flags and options. + +## Version + +While telegraf will print out the version when running, if a user is uncertain +what version their binary is, run the version subcommand: + +```bash +telegraf version +``` + +## Config + +The config subcommand allows users to print out a sample configuration to +stdout. This subcommand can very quickly print out the default values for all +or any of the plugins available in Telegraf. + +For example to print the example config for all plugins run: + +```bash +telegraf config > telegraf.conf +``` + +If a user only wanted certain inputs or outputs, then the filters can be used: + +```bash +telegraf config --input-filter cpu --output-filter influxdb +``` diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md new file mode 100644 index 0000000..43eb7cd --- /dev/null +++ b/docs/CONFIGURATION.md @@ -0,0 +1,918 @@ + + +# Configuration + +Telegraf's configuration file is written using [TOML][] and is composed of +three sections: [global tags][], [agent][] settings, and [plugins][]. + +## Generating a Configuration File + +A default config file can be generated by telegraf: + +```sh +telegraf config > telegraf.conf +``` + +To generate a file with specific inputs and outputs, you can use the +--input-filter and --output-filter flags: + +```sh +telegraf config --input-filter cpu:mem:net:swap --output-filter influxdb:kafka +``` + +[View the full list][flags] of Telegraf commands and flags or by running +`telegraf --help`. + +### Windows PowerShell v5 Encoding + +In PowerShell 5, the default encoding is UTF-16LE and not UTF-8. Telegraf +expects a valid UTF-8 file. This is not an issue with PowerShell 6 or newer, +as well as the Command Prompt or with using the Git Bash shell. + +As such, users will need to specify the output encoding when generating a full +configuration file: + +```sh +telegraf.exe config | Out-File -Encoding utf8 telegraf.conf +``` + +This will generate a UTF-8 encoded file with a BOM. However, Telegraf can +handle the leading BOM. + +## Configuration Loading + +The location of the configuration file can be set via the `--config` command +line flag. + +When the `--config-directory` command line flag is used files ending with +`.conf` in the specified directory will also be included in the Telegraf +configuration. + +On most systems, the default locations are `/etc/telegraf/telegraf.conf` for +the main configuration file and `/etc/telegraf/telegraf.d` for the directory of +configuration files. + +## Environment Variables + +Environment variables can be used anywhere in the config file, simply surround +them with `${}`. Replacement occurs before file parsing. For strings +the variable must be within quotes, e.g., `"${STR_VAR}"`, for numbers and booleans +they should be unquoted, e.g., `${INT_VAR}`, `${BOOL_VAR}`. + +Users need to keep in mind that when using double quotes the user needs to +escape any backslashes (e.g. `"C:\\Program Files"`) or other special characters. +If using an environment variable with a single backslash, then enclose the +variable in single quotes which signifies a string literal (e.g. +`'C:\Program Files'`). + +In addition to this, Telegraf also supports Shell parameter expansion for +environment variables which allows syntax such as: + +- `${VARIABLE:-default}` evaluates to default if VARIABLE is unset or empty in + the environment. +- `${VARIABLE-default}` evaluates to default only if VARIABLE is unset in the + environment. Similarly, the following syntax allows you + to specify mandatory variables: +- `${VARIABLE:?err}` exits with an error message containing err if VARIABLE is + unset or empty in the environment. +- `${VARIABLE?err}` exits with an error message containing err if VARIABLE is + unset in the environment. + +When using the `.deb` or `.rpm` packages, you can define environment variables +in the `/etc/default/telegraf` file. + +**Example**: + +`/etc/default/telegraf`: + +For InfluxDB 1.x: + +```shell +USER="alice" +INFLUX_URL="http://localhost:8086" +INFLUX_SKIP_DATABASE_CREATION="true" +INFLUX_PASSWORD="monkey123" +``` + +For InfluxDB OSS 2: + +```shell +INFLUX_HOST="http://localhost:8086" # used to be 9999 +INFLUX_TOKEN="replace_with_your_token" +INFLUX_ORG="your_username" +INFLUX_BUCKET="replace_with_your_bucket_name" +``` + +For InfluxDB Cloud 2: + +```shell +# For AWS West (Oregon) +INFLUX_HOST="https://us-west-2-1.aws.cloud2.influxdata.com" +# Other Cloud URLs at https://v2.docs.influxdata.com/v2.0/reference/urls/#influxdb-cloud-urls +INFLUX_TOKEN=”replace_with_your_token” +INFLUX_ORG="yourname@yourcompany.com" +INFLUX_BUCKET="replace_with_your_bucket_name" +``` + +`/etc/telegraf.conf`: + +```toml +[global_tags] + user = "${USER}" + +[[inputs.mem]] + +# For InfluxDB 1.x: +[[outputs.influxdb]] + urls = ["${INFLUX_URL}"] + skip_database_creation = ${INFLUX_SKIP_DATABASE_CREATION} + password = "${INFLUX_PASSWORD}" + +# For InfluxDB OSS 2: +[[outputs.influxdb_v2]] + urls = ["${INFLUX_HOST}"] + token = "${INFLUX_TOKEN}" + organization = "${INFLUX_ORG}" + bucket = "${INFLUX_BUCKET}" + +# For InfluxDB Cloud 2: +[[outputs.influxdb_v2]] + urls = ["${INFLUX_HOST}"] + token = "${INFLUX_TOKEN}" + organization = "${INFLUX_ORG}" + bucket = "${INFLUX_BUCKET}" +``` + +The above files will produce the following effective configuration file to be +parsed: + +```toml +[global_tags] + user = "alice" + +[[inputs.mem]] + +# For InfluxDB 1.x: +[[outputs.influxdb]] + urls = "http://localhost:8086" + skip_database_creation = true + password = "monkey123" + +# For InfluxDB OSS 2: +[[outputs.influxdb_v2]] + urls = ["http://127.0.0.1:8086"] # double check the port. could be 9999 if using OSS Beta + token = "replace_with_your_token" + organization = "your_username" + bucket = "replace_with_your_bucket_name" + +# For InfluxDB Cloud 2: +[[outputs.influxdb_v2]] + # For AWS West (Oregon) + INFLUX_HOST="https://us-west-2-1.aws.cloud2.influxdata.com" + # Other Cloud URLs at https://v2.docs.influxdata.com/v2.0/reference/urls/#influxdb-cloud-urls + token = "replace_with_your_token" + organization = "yourname@yourcompany.com" + bucket = "replace_with_your_bucket_name" +``` + +## Secret-store secrets + +Additional or instead of environment variables, you can use secret-stores +to fill in credentials or similar. To do so, you need to configure one or more +secret-store plugin(s) and then reference the secret in your plugin +configurations. A reference to a secret is specified in form +`@{:}`, where the `secret store id` is the unique +ID you defined for your secret-store and `secret name` is the name of the secret +to use. +**NOTE:** Both, the `secret store id` as well as the `secret name` can only +consist of letters (both upper- and lowercase), numbers and underscores. + +**Example**: + +This example illustrates the use of secret-store(s) in plugins + +```toml +[global_tags] + user = "alice" + +[[secretstores.os]] + id = "local_secrets" + +[[secretstores.jose]] + id = "cloud_secrets" + path = "/etc/telegraf/secrets" + # Optional reference to another secret store to unlock this one. + password = "@{local_secrets:cloud_store_passwd}" + +[[inputs.http]] + urls = ["http://server.company.org/metrics"] + username = "@{local_secrets:company_server_http_metric_user}" + password = "@{local_secrets:company_server_http_metric_pass}" + +[[outputs.influxdb_v2]] + urls = ["https://us-west-2-1.aws.cloud2.influxdata.com"] + token = "@{cloud_secrets:influxdb_token}" + organization = "yourname@yourcompany.com" + bucket = "replace_with_your_bucket_name" +``` + +### Notes + +When using plugins supporting secrets, Telegraf locks the memory pages +containing the secrets. Therefore, the locked memory limit has to be set to a +suitable value. Telegraf will check the limit and the number of used secrets at +startup and will warn if your limit is too low. In this case, please increase +the limit via `ulimit -l`. + +If you are running Telegraf in an jail you might need to allow locked pages in +that jail by setting `allow.mlock = 1;` in your config. + +## Intervals + +Intervals are durations of time and can be specified for supporting settings by +combining an integer value and time unit as a string value. Valid time units are +`ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. + +```toml +[agent] + interval = "10s" +``` + +## Global Tags + +Global tags can be specified in the `[global_tags]` table in key="value" +format. All metrics that are gathered will be tagged with the tags specified. +Global tags are overridden by tags set by plugins. + +```toml +[global_tags] + dc = "us-east-1" +``` + +## Agent + +The agent table configures Telegraf and the defaults used across all plugins. + +- **interval**: Default data collection [interval][] for all inputs. + +- **round_interval**: Rounds collection interval to [interval][] + ie, if interval="10s" then always collect on :00, :10, :20, etc. + +- **metric_batch_size**: + Telegraf will send metrics to outputs in batches of at most + metric_batch_size metrics. + This controls the size of writes that Telegraf sends to output plugins. + +- **metric_buffer_limit**: + Maximum number of unwritten metrics per output. Increasing this value + allows for longer periods of output downtime without dropping metrics at the + cost of higher maximum memory usage. Oldest metrics are overwritten in favor + of new ones when the buffer fills up. + +- **collection_jitter**: + Collection jitter is used to jitter the collection by a random [interval][]. + Each plugin will sleep for a random time within jitter before collecting. + This can be used to avoid many plugins querying things like sysfs at the + same time, which can have a measurable effect on the system. + +- **collection_offset**: + Collection offset is used to shift the collection by the given [interval][]. + This can be be used to avoid many plugins querying constraint devices + at the same time by manually scheduling them in time. + +- **flush_interval**: + Default flushing [interval][] for all outputs. Maximum flush_interval will be + flush_interval + flush_jitter. + +- **flush_jitter**: + Default flush jitter for all outputs. This jitters the flush [interval][] + by a random amount. This is primarily to avoid large write spikes for users + running a large number of telegraf instances. ie, a jitter of 5s and interval + 10s means flushes will happen every 10-15s. + +- **precision**: + Collected metrics are rounded to the precision specified as an [interval][]. + + Precision will NOT be used for service inputs. It is up to each individual + service input to set the timestamp at the appropriate precision. + +- **debug**: + Log at debug level. + +- **quiet**: + Log only error level messages. + +- **logformat**: + Log format controls the way messages are logged and can be one of "text", + "structured" or, on Windows, "eventlog". The output file (if any) is + determined by the `logfile` setting. + +- **structured_log_message_key**: + Message key for structured logs, to override the default of "msg". + Ignored if `logformat` is not "structured". + +- **logfile**: + Name of the file to be logged to or stderr if unset or empty. This + setting is ignored for the "eventlog" format. + +- **logfile_rotation_interval**: + The logfile will be rotated after the time interval specified. When set to + 0 no time based rotation is performed. + +- **logfile_rotation_max_size**: + The logfile will be rotated when it becomes larger than the specified size. + When set to 0 no size based rotation is performed. + +- **logfile_rotation_max_archives**: + Maximum number of rotated archives to keep, any older logs are deleted. If + set to -1, no archives are removed. + +- **log_with_timezone**: + Pick a timezone to use when logging or type 'local' for local time. Example: 'America/Chicago'. + [See this page for options/formats.](https://socketloop.com/tutorials/golang-display-list-of-timezones-with-gmt) + +- **hostname**: + Override default hostname, if empty use os.Hostname() + +- **omit_hostname**: + If set to true, do no set the "host" tag in the telegraf agent. + +- **snmp_translator**: + Method of translating SNMP objects. Can be "netsnmp" (deprecated) which + translates by calling external programs `snmptranslate` and `snmptable`, + or "gosmi" which translates using the built-in gosmi library. + +- **statefile**: + Name of the file to load the states of plugins from and store the states to. + If uncommented and not empty, this file will be used to save the state of + stateful plugins on termination of Telegraf. If the file exists on start, + the state in the file will be restored for the plugins. + +- **always_include_local_tags**: + Ensure tags explicitly defined in a plugin will *always* pass tag-filtering + via `taginclude` or `tagexclude`. This removes the need to specify local tags + twice. + +- **always_include_global_tags**: + Ensure tags explicitly defined in the `global_tags` section will *always* pass + tag-filtering via `taginclude` or `tagexclude`. This removes the need to + specify those tags twice. + +- **skip_processors_after_aggregators**: + By default, processors are run a second time after aggregators. Changing + this setting to true will skip the second run of processors. + +- **buffer_strategy**: + The type of buffer to use for telegraf output plugins. Supported modes are + `memory`, the default and original buffer type, and `disk`, an experimental + disk-backed buffer which will serialize all metrics to disk as needed to + improve data durability and reduce the chance for data loss. This is only + supported at the agent level. + +- **buffer_directory**: + The directory to use when in `disk` buffer mode. Each output plugin will make + another subdirectory in this directory with the output plugin's ID. + +## Plugins + +Telegraf plugins are divided into 4 types: [inputs][], [outputs][], +[processors][], and [aggregators][]. + +Unlike the `global_tags` and `agent` tables, any plugin can be defined +multiple times and each instance will run independently. This allows you to +have plugins defined with differing configurations as needed within a single +Telegraf process. + +Each plugin has a unique set of configuration options, reference the +sample configuration for details. Additionally, several options are available +on any plugin depending on its type. + +### Input Plugins + +Input plugins gather and create metrics. They support both polling and event +driven operation. + +Parameters that can be used with any input plugin: + +- **alias**: Name an instance of a plugin. +- **interval**: + Overrides the `interval` setting of the [agent][Agent] for the plugin. How + often to gather this metric. Normal plugins use a single global interval, but + if one particular input should be run less or more often, you can configure + that here. +- **precision**: + Overrides the `precision` setting of the [agent][Agent] for the plugin. + Collected metrics are rounded to the precision specified as an [interval][]. + + When this value is set on a service input, multiple events occurring at the + same timestamp may be merged by the output database. +- **time_source**: + Specifies the source of the timestamp on metrics. Possible values are: + - `metric` will not alter the metric (default) + - `collection_start` sets the timestamp to when collection started + - `collection_end` set the timestamp to when collection finished + + `time_source` will NOT be used for service inputs. It is up to each individual + service input to set the timestamp. +- **collection_jitter**: + Overrides the `collection_jitter` setting of the [agent][Agent] for the + plugin. Collection jitter is used to jitter the collection by a random + [interval][]. The value must be non-zero to override the agent setting. +- **collection_offset**: + Overrides the `collection_offset` setting of the [agent][Agent] for the + plugin. Collection offset is used to shift the collection by the given + [interval][]. The value must be non-zero to override the agent setting. +- **name_override**: Override the base name of the measurement. (Default is + the name of the input). +- **name_prefix**: Specifies a prefix to attach to the measurement name. +- **name_suffix**: Specifies a suffix to attach to the measurement name. +- **tags**: A map of tags to apply to a specific input's measurements. +- **log_level**: Override the log-level for this plugin. Possible values are + `error`, `warn`, `info`, `debug` and `trace`. + +The [metric filtering][] parameters can be used to limit what metrics are +emitted from the input plugin. + +#### Examples + +Use the name_suffix parameter to emit measurements with the name `cpu_total`: + +```toml +[[inputs.cpu]] + name_suffix = "_total" + percpu = false + totalcpu = true +``` + +Use the name_override parameter to emit measurements with the name `foobar`: + +```toml +[[inputs.cpu]] + name_override = "foobar" + percpu = false + totalcpu = true +``` + +Emit measurements with two additional tags: `tag1=foo` and `tag2=bar` + +> **NOTE**: With TOML, order matters. Parameters belong to the last defined +> table header, place `[inputs.cpu.tags]` table at the *end* of the plugin +> definition. + +```toml +[[inputs.cpu]] + percpu = false + totalcpu = true + [inputs.cpu.tags] + tag1 = "foo" + tag2 = "bar" +``` + +Alternatively, when using the inline table syntax, the tags do not need +to go at the end: + +```toml +[[inputs.cpu]] + tags = {tag1 = "foo", tag2 = "bar"} + percpu = false + totalcpu = true +``` + +Utilize `name_override`, `name_prefix`, or `name_suffix` config options to +avoid measurement collisions when defining multiple plugins: + +```toml +[[inputs.cpu]] + percpu = false + totalcpu = true + +[[inputs.cpu]] + percpu = true + totalcpu = false + name_override = "percpu_usage" + fieldexclude = ["cpu_time*"] +``` + +### Output Plugins + +Output plugins write metrics to a location. Outputs commonly write to +databases, network services, and messaging systems. + +Parameters that can be used with any output plugin: + +- **alias**: Name an instance of a plugin. +- **flush_interval**: The maximum time between flushes. Use this setting to + override the agent `flush_interval` on a per plugin basis. +- **flush_jitter**: The amount of time to jitter the flush interval. Use this + setting to override the agent `flush_jitter` on a per plugin basis. The value + must be non-zero to override the agent setting. +- **metric_batch_size**: The maximum number of metrics to send at once. Use + this setting to override the agent `metric_batch_size` on a per plugin basis. +- **metric_buffer_limit**: The maximum number of unsent metrics to buffer. + Use this setting to override the agent `metric_buffer_limit` on a per plugin + basis. +- **name_override**: Override the original name of the measurement. +- **name_prefix**: Specifies a prefix to attach to the measurement name. +- **name_suffix**: Specifies a suffix to attach to the measurement name. +- **log_level**: Override the log-level for this plugin. Possible values are + `error`, `warn`, `info` and `debug`. + +The [metric filtering][] parameters can be used to limit what metrics are +emitted from the output plugin. + +#### Examples + +Override flush parameters for a single output: + +```toml +[agent] + flush_interval = "10s" + flush_jitter = "5s" + metric_batch_size = 1000 + +[[outputs.influxdb]] + urls = [ "http://example.org:8086" ] + database = "telegraf" + +[[outputs.file]] + files = [ "stdout" ] + flush_interval = "1s" + flush_jitter = "1s" + metric_batch_size = 10 +``` + +### Processor Plugins + +Processor plugins perform processing tasks on metrics and are commonly used to +rename or apply transformations to metrics. Processors are applied after the +input plugins and before any aggregator plugins. + +Parameters that can be used with any processor plugin: + +- **alias**: Name an instance of a plugin. +- **order**: The order in which the processor(s) are executed. starting with 1. + If this is not specified then processor execution order will be the order in + the config. Processors without "order" will take precedence over those + with a defined order. +- **log_level**: Override the log-level for this plugin. Possible values are + `error`, `warn`, `info` and `debug`. + +The [metric filtering][] parameters can be used to limit what metrics are +handled by the processor. Excluded metrics are passed downstream to the next +processor. + +#### Examples + +If the order processors are applied matters you must set order on all involved +processors: + +```toml +[[processors.rename]] + order = 1 + [[processors.rename.replace]] + tag = "path" + dest = "resource" + +[[processors.strings]] + order = 2 + [[processors.strings.trim_prefix]] + tag = "resource" + prefix = "/api/" +``` + +### Aggregator Plugins + +Aggregator plugins produce new metrics after examining metrics over a time +period, as the name suggests they are commonly used to produce new aggregates +such as mean/max/min metrics. Aggregators operate on metrics after any +processors have been applied. + +Parameters that can be used with any aggregator plugin: + +- **alias**: Name an instance of a plugin. +- **period**: The period on which to flush & clear each aggregator. All + metrics that are sent with timestamps outside of this period will be ignored + by the aggregator. + The default period is set to 30 seconds. +- **delay**: The delay before each aggregator is flushed. This is to control + how long for aggregators to wait before receiving metrics from input + plugins, in the case that aggregators are flushing and inputs are gathering + on the same interval. + The default delay is set to 100 ms. +- **grace**: The duration when the metrics will still be aggregated + by the plugin, even though they're outside of the aggregation period. This + is needed in a situation when the agent is expected to receive late metrics + and it's acceptable to roll them up into next aggregation period. + The default grace duration is set to 0 s. +- **drop_original**: If true, the original metric will be dropped by the + aggregator and will not get sent to the output plugins. +- **name_override**: Override the base name of the measurement. (Default is + the name of the input). +- **name_prefix**: Specifies a prefix to attach to the measurement name. +- **name_suffix**: Specifies a suffix to attach to the measurement name. +- **tags**: A map of tags to apply to the measurement - behavior varies based on aggregator. +- **log_level**: Override the log-level for this plugin. Possible values are + `error`, `warn`, `info` and `debug`. + +The [metric filtering][] parameters can be used to limit what metrics are +handled by the aggregator. Excluded metrics are passed downstream to the next +aggregator. + +#### Examples + +Collect and emit the min/max of the system load1 metric every 30s, dropping +the originals. + +```toml +[[inputs.system]] + fieldinclude = ["load1"] # collects system load1 metric. + +[[aggregators.minmax]] + period = "30s" # send & clear the aggregate every 30s. + drop_original = true # drop the original metrics. + +[[outputs.file]] + files = ["stdout"] +``` + +Collect and emit the min/max of the swap metrics every 30s, dropping the +originals. The aggregator will not be applied to the system load metrics due +to the `namepass` parameter. + +```toml +[[inputs.swap]] + +[[inputs.system]] + fieldinclude = ["load1"] # collects system load1 metric. + +[[aggregators.minmax]] + period = "30s" # send & clear the aggregate every 30s. + drop_original = true # drop the original metrics. + namepass = ["swap"] # only "pass" swap metrics through the aggregator. + +[[outputs.file]] + files = ["stdout"] +``` + +## Metric Filtering + +Metric filtering can be configured per plugin on any input, output, processor, +and aggregator plugin. Filters fall under two categories: Selectors and +Modifiers. + +### Selectors + +Selector filters include or exclude entire metrics. When a metric is excluded +from a Input or an Output plugin, the metric is dropped. If a metric is +excluded from a Processor or Aggregator plugin, it is skips the plugin and is +sent onwards to the next stage of processing. + +- **namepass**: +An array of [glob pattern][] strings. Only metrics whose measurement name +matches a pattern in this list are emitted. Additionally, custom list of +separators can be specified using `namepass_separator`. These separators +are excluded from wildcard glob pattern matching. + +- **namedrop**: +The inverse of `namepass`. If a match is found the metric is discarded. This +is tested on metrics after they have passed the `namepass` test. Additionally, +custom list of separators can be specified using `namedrop_separator`. These +separators are excluded from wildcard glob pattern matching. + +- **tagpass**: +A table mapping tag keys to arrays of [glob pattern][] strings. Only metrics +that contain a tag key in the table and a tag value matching one of its +patterns is emitted. This can either use the explicit table syntax (e.g. +a subsection using a `[...]` header) or inline table syntax (e.g like +a JSON table with `{...}`). Please see the below notes on specifying the table. + +- **tagdrop**: +The inverse of `tagpass`. If a match is found the metric is discarded. This +is tested on metrics after they have passed the `tagpass` test. + +> NOTE: Due to the way TOML is parsed, when using the explicit table +> syntax (with `[...]`) for `tagpass` and `tagdrop` parameters, they +> must be defined at the **end** of the plugin definition, otherwise subsequent +> plugin config options will be interpreted as part of the tagpass/tagdrop +> tables. +> NOTE: When using the inline table syntax (e.g. `{...}`) the table must exist +> in the main plugin definition and not in any sub-table (e.g. +> `[[inputs.win_perf_counters.object]]`). + +- **metricpass**: +A ["Common Expression Language"][CEL] (CEL) expression with boolean result where +`true` will allow the metric to pass, otherwise the metric is discarded. This +filter expression is more general compared to e.g. `namepass` and also allows +for time-based filtering. An introduction to the CEL language can be found +[here][CEL intro]. Further details, such as available functions and expressions, +are provided in the [language definition][CEL lang] as well as in the +[extension documentation][CEL ext]. + +**NOTE:** Expressions that may be valid and compile, but fail at runtime will +result in the expression reporting as `true`. The metrics will pass through +as a result. An example is when reading a non-existing field. If this happens, +the evaluation is aborted, an error is logged, and the expression is reported as +`true`, so the metric passes. + +> NOTE: As CEL is an *interpreted* languguage, this type of filtering is much +> slower compared to `namepass`/`namedrop` and friends. So consider to use the +> more restricted filter options where possible in case of high-throughput +> scenarios. + +[CEL]:https://github.com/google/cel-go/tree/master +[CEL intro]: https://codelabs.developers.google.com/codelabs/cel-go +[CEL lang]: https://github.com/google/cel-spec/blob/master/doc/langdef.md +[CEL ext]: https://github.com/google/cel-go/tree/master/ext#readme + +### Modifiers + +Modifier filters remove tags and fields from a metric. If all fields are +removed the metric is removed and as result not passed through to the following +processors or any output plugin. Tags and fields are modified before a metric is +passed to a processor, aggregator, or output plugin. When used with an input +plugin the filter applies after the input runs. + +- **fieldinclude**: +An array of [glob pattern][] strings. Only fields whose field key matches a +pattern in this list are emitted. + +- **fieldexclude**: +The inverse of `fieldinclude`. Fields with a field key matching one of the +patterns will be discarded from the metric. This is tested on metrics after +they have passed the `fieldinclude` test. + +- **taginclude**: +An array of [glob pattern][] strings. Only tags with a tag key matching one of +the patterns are emitted. In contrast to `tagpass`, which will pass an entire +metric based on its tag, `taginclude` removes all non matching tags from the +metric. Any tag can be filtered including global tags and the agent `host` +tag. + +- **tagexclude**: +The inverse of `taginclude`. Tags with a tag key matching one of the patterns +will be discarded from the metric. Any tag can be filtered including global +tags and the agent `host` tag. + +### Filtering Examples + +#### Using tagpass and tagdrop + +```toml +[[inputs.cpu]] + percpu = true + totalcpu = false + fieldexclude = ["cpu_time"] + # Don't collect CPU data for cpu6 & cpu7 + [inputs.cpu.tagdrop] + cpu = [ "cpu6", "cpu7" ] + +[[inputs.disk]] + [inputs.disk.tagpass] + # tagpass conditions are OR, not AND. + # If the (filesystem is ext4 or xfs) OR (the path is /opt or /home) + # then the metric passes + fstype = [ "ext4", "xfs" ] + # Globs can also be used on the tag values + path = [ "/opt", "/home*" ] + +[[inputs.win_perf_counters]] + [[inputs.win_perf_counters.object]] + ObjectName = "Network Interface" + Instances = ["*"] + Counters = [ + "Bytes Received/sec", + "Bytes Sent/sec" + ] + Measurement = "win_net" + # Do not send metrics where the Windows interface name (instance) begins with + # 'isatap' or 'Local' + [inputs.win_perf_counters.tagdrop] + instance = ["isatap*", "Local*"] +``` + +#### Using fieldinclude and fieldexclude + +```toml +# Drop all metrics for guest & steal CPU usage +[[inputs.cpu]] + percpu = false + totalcpu = true + fieldexclude = ["usage_guest", "usage_steal"] + +# Only store inode related metrics for disks +[[inputs.disk]] + fieldinclude = ["inodes*"] +``` + +#### Using namepass and namedrop + +```toml +# Drop all metrics about containers for kubelet +[[inputs.prometheus]] + urls = ["http://kube-node-1:4194/metrics"] + namedrop = ["container_*"] + +# Only store rest client related metrics for kubelet +[[inputs.prometheus]] + urls = ["http://kube-node-1:4194/metrics"] + namepass = ["rest_client_*"] +``` + +#### Using namepass and namedrop with separators + +```toml +# Pass all metrics of type 'A.C.B' and drop all others like 'A.C.D.B' +[[inputs.socket_listener]] + data_format = "graphite" + templates = ["measurement*"] + + namepass = ["A.*.B"] + namepass_separator = "." + +# Drop all metrics of type 'A.C.B' and pass all others like 'A.C.D.B' +[[inputs.socket_listener]] + data_format = "graphite" + templates = ["measurement*"] + + namedrop = ["A.*.B"] + namedrop_separator = "." +``` + +#### Using taginclude and tagexclude + +```toml +# Only include the "cpu" tag in the measurements for the cpu plugin. +[[inputs.cpu]] + percpu = true + totalcpu = true + taginclude = ["cpu"] + +# Exclude the "fstype" tag from the measurements for the disk plugin. +[[inputs.disk]] + tagexclude = ["fstype"] +``` + +#### Metrics can be routed to different outputs using the metric name and tags + +```toml +[[outputs.influxdb]] + urls = [ "http://localhost:8086" ] + database = "telegraf" + # Drop all measurements that start with "aerospike" + namedrop = ["aerospike*"] + +[[outputs.influxdb]] + urls = [ "http://localhost:8086" ] + database = "telegraf-aerospike-data" + # Only accept aerospike data: + namepass = ["aerospike*"] + +[[outputs.influxdb]] + urls = [ "http://localhost:8086" ] + database = "telegraf-cpu0-data" + # Only store measurements where the tag "cpu" matches the value "cpu0" + [outputs.influxdb.tagpass] + cpu = ["cpu0"] +``` + +#### Routing metrics to different outputs based on the input + +Metrics are tagged with `influxdb_database` in the input, which is then used to +select the output. The tag is removed in the outputs before writing with `tagexclude`. + +```toml +[[outputs.influxdb]] + urls = ["http://influxdb.example.com"] + database = "db_default" + [outputs.influxdb.tagdrop] + influxdb_database = ["*"] + +[[outputs.influxdb]] + urls = ["http://influxdb.example.com"] + database = "db_other" + tagexclude = ["influxdb_database"] + [outputs.influxdb.tagpass] + influxdb_database = ["other"] + +[[inputs.disk]] + [inputs.disk.tags] + influxdb_database = "other" +``` + +## Transport Layer Security (TLS) + +Reference the detailed [TLS][] documentation. + +[TOML]: https://github.com/toml-lang/toml#toml +[global tags]: #global-tags +[interval]: #intervals +[agent]: #agent +[plugins]: #plugins +[inputs]: #input-plugins +[outputs]: #output-plugins +[processors]: #processor-plugins +[aggregators]: #aggregator-plugins +[metric filtering]: #metric-filtering +[TLS]: /docs/TLS.md +[glob pattern]: https://github.com/gobwas/glob#syntax +[flags]: /docs/COMMANDS_AND_FLAGS.md diff --git a/docs/CUSTOMIZATION.md b/docs/CUSTOMIZATION.md new file mode 100644 index 0000000..eb669a7 --- /dev/null +++ b/docs/CUSTOMIZATION.md @@ -0,0 +1,46 @@ +# Customization + +You can build customized versions of Telegraf with a specific plugin set using +the [custom builder](/tools/custom_builder) tool or +[build-tags](https://pkg.go.dev/cmd/go#hdr-Build_constraints). +For build tags, the plugins can be selected either category-wise, i.e. +`inputs`, `outputs`,`processors`, `aggregators`, `parsers`, `secretstores` +and `serializers` or individually, e.g. `inputs.modbus` or `outputs.influxdb`. + +Usually the build tags correspond to the plugin names used in the Telegraf +configuration. To be sure, check the files in the corresponding +`plugin//all` directory. Make sure to include all parsers you intend +to use. + +__Note:__ You _always_ need to include the `custom` tag when customizing the +build as otherwise _all_ plugins will be selected regardless of other tags. + +## Via make + +When using the project's makefile, the build can be customized via the +`BUILDTAGS` environment variable containing a __comma-separated__ list of the +selected plugins (or categories) __and__ the `custom` tag. + +For example + +```shell +BUILDTAGS="custom,inputs,outputs.influxdb_v2,parsers.json" make +``` + +will build a customized Telegraf including _all_ `inputs`, the InfluxDB v2 +`output` and the `json` parser. + +## Via `go build` + +If you wish to build Telegraf using native go tools, you can use the `go build` +command with the `-tags` option. Specify a __comma-separated__ list of the +selected plugins (or categories) __and__ the `custom` tag as argument. + +For example + +```shell +go build -tags "custom,inputs,outputs.influxdb_v2,parsers.json" ./cmd/telegraf +``` + +will build a customized Telegraf including _all_ `inputs`, the InfluxDB v2 +`output` and the `json` parser. diff --git a/docs/DATA_FORMATS_INPUT.md b/docs/DATA_FORMATS_INPUT.md new file mode 100644 index 0000000..3947ffa --- /dev/null +++ b/docs/DATA_FORMATS_INPUT.md @@ -0,0 +1,45 @@ +# Input Data Formats + +Telegraf contains many general purpose plugins that support parsing input data +using a configurable parser into [metrics][]. This allows, for example, the +`kafka_consumer` input plugin to process messages in any of InfluxDB Line +Protocol, JSON format, or Apache Avro format. + +- [Avro](/plugins/parsers/avro) +- [Binary](/plugins/parsers/binary) +- [Collectd](/plugins/parsers/collectd) +- [CSV](/plugins/parsers/csv) +- [Dropwizard](/plugins/parsers/dropwizard) +- [Form URL Encoded](/plugins/parsers/form_urlencoded) +- [Graphite](/plugins/parsers/graphite) +- [Grok](/plugins/parsers/grok) +- [InfluxDB Line Protocol](/plugins/parsers/influx) +- [JSON](/plugins/parsers/json) +- [JSON v2](/plugins/parsers/json_v2) +- [Logfmt](/plugins/parsers/logfmt) +- [Nagios](/plugins/parsers/nagios) +- [OpenMetrics](/plugins/parsers/openmetrics) +- [OpenTSDB](/plugins/parsers/opentsdb) +- [Parquet](/plugins/parsers/parquet) +- [Prometheus](/plugins/parsers/prometheus) +- [PrometheusRemoteWrite](/plugins/parsers/prometheusremotewrite) +- [Value](/plugins/parsers/value), ie: 45 or "booyah" +- [Wavefront](/plugins/parsers/wavefront) +- [XPath](/plugins/parsers/xpath) (supports XML, JSON, MessagePack, Protocol Buffers) + +Any input plugin containing the `data_format` option can use it to select the +desired parser: + +```toml +[[inputs.exec]] + ## Commands array + commands = ["/tmp/test.sh", "/usr/bin/mycollector --foo=bar"] + + ## measurement name suffix (for separating different commands) + name_suffix = "_mycollector" + + ## Data format to consume. + data_format = "json" +``` + +[metrics]: /docs/METRICS.md diff --git a/docs/DATA_FORMATS_OUTPUT.md b/docs/DATA_FORMATS_OUTPUT.md new file mode 100644 index 0000000..6dfa50c --- /dev/null +++ b/docs/DATA_FORMATS_OUTPUT.md @@ -0,0 +1,32 @@ +# Output Data Formats + +In addition to output specific data formats, Telegraf supports a set of +standard data formats that may be selected from when configuring many output +plugins. + +1. [InfluxDB Line Protocol](/plugins/serializers/influx) +1. [Binary](/plugins/serializers/binary) +1. [Carbon2](/plugins/serializers/carbon2) +1. [CloudEvents](/plugins/serializers/cloudevents) +1. [CSV](/plugins/serializers/csv) +1. [Graphite](/plugins/serializers/graphite) +1. [JSON](/plugins/serializers/json) +1. [MessagePack](/plugins/serializers/msgpack) +1. [Prometheus](/plugins/serializers/prometheus) +1. [Prometheus Remote Write](/plugins/serializers/prometheusremotewrite) +1. [ServiceNow Metrics](/plugins/serializers/nowmetric) +1. [SplunkMetric](/plugins/serializers/splunkmetric) +1. [Template](/plugins/serializers/template) +1. [Wavefront](/plugins/serializers/wavefront) + +You will be able to identify the plugins with support by the presence of a +`data_format` config option, for example, in the `file` output plugin: + +```toml +[[outputs.file]] + ## Files to write to, "stdout" is a specially handled file. + files = ["stdout"] + + ## Data format to output. + data_format = "influx" +``` diff --git a/docs/DOCKER.md b/docs/DOCKER.md new file mode 100644 index 0000000..d669038 --- /dev/null +++ b/docs/DOCKER.md @@ -0,0 +1,64 @@ +# Docker Images + +Telegraf is available as an [Official image][] on DockerHub. Official images +are a curated set of Docker Images that also automatically get security updates +from Docker, follow a set of best practices, and are available via a shortcut +syntax which omits the organization. + +InfluxData maintains Debian and Alpine based images across the last three +minor releases. To pull the latest Telegraf images: + +```shell +# latest Debian-based image +docker pull telegraf +# latest Alpine-based image +docker pull telegraf:alpine +``` + +See the [Telegraf DockerHub][] page for complete details on available images, +versions, and tags. + +[official image]: https://docs.docker.com/trusted-content/official-images/ +[Telegraf DockerHub]: https://hub.docker.com/_/telegraf + +## Nightly Images + +[Nightly builds][] are available and are generated from the master branch each +day at around midnight UTC. The artifacts include both binary packages, RPM & +DEB packages, as well as nightly Docker images that are hosted on [quay.io][]. + +[Nightly builds]: /docs/NIGHTLIES.md +[quay.io]: https://quay.io/repository/influxdb/telegraf-nightly?tab=tags&tag=latest + +## Dockerfiles + +The [Dockerfiles][] for these images are available for users to use as well. + +[Dockerfiles]: https://github.com/influxdata/influxdata-docker + +## Lockable Memory + +Telegraf does require the ability to use lockable memory when running by default. In some +deployments for Docker a container may not have enough lockable memory, which +results in the following warning: + +```text +W! Insufficient lockable memory 64kb when 72kb is required. Please increase the limit for Telegraf in your Operating System! +``` + +or this error: + +```text +panic: could not acquire lock on 0x7f7a8890f000, limit reached? [Err: cannot allocate memory] +``` + +Users have two options: + +1. Increase the ulimit in the container. The user does this with the `ulimit -l` + command. To both see and set the value. For docker, there is a `--ulimit` flag + that could be used, like `--ulimit memlock=8192:8192` as well. +2. Add the `--unprotected` flag to the command arguments to not use locked + memory and instead store secrets in unprotected memory. This is less secure + as secrets could find their way into paged out memory and can be written to + disk unencrypted, therefore this is opt-in. For docker look at updating the + `CMD` used to include this flag. diff --git a/docs/EXTERNAL_PLUGINS.md b/docs/EXTERNAL_PLUGINS.md new file mode 100644 index 0000000..a1528dc --- /dev/null +++ b/docs/EXTERNAL_PLUGINS.md @@ -0,0 +1,100 @@ +# External Plugins + +[External plugins](/EXTERNAL_PLUGINS.md) are external programs that are built +outside of Telegraf that can run through an `execd` plugin. These external +plugins allow for more flexibility compared to internal Telegraf plugins. + +- External plugins can be written in any language (internal Telegraf plugins can + only be written in Go) +- External plugins can access to libraries not written in Go +- Utilize licensed software that is not available to the open source community +- Can include large dependencies that would otherwise bloat Telegraf +- You do not need to wait on the Telegraf team to publish the plugin and start + working with it. +- Using the [shim](/plugins/common/shim) you can easily convert plugins between + internal and external use +- Using 3rd-party libraries requiring CGO support + +## External Plugin Guidelines + +The guidelines of writing external plugins would follow those for our general +[input](/docs/INPUTS.md), [output](/docs/OUTPUTS.md), +[processor](/docs/PROCESSORS.md), and [aggregator](/docs/AGGREGATORS.md) +plugins. Please reference the documentation on how to create these plugins +written in Go. + +_For listed [external plugins](/EXTERNAL_PLUGINS.md), the author of the external +plugin is also responsible for the maintenance and feature development of +external plugins. Expect to have users open plugin issues on its respective +GitHub repository._ + +### Execd Go Shim + +For Go plugins, there is a [Execd Go Shim](/plugins/common/shim/) that will make +it trivial to extract an internal input, processor, or output plugin from the +main Telegraf repo out to a stand-alone repo. This shim allows anyone to build +and run it as a separate app using one of the `execd` plugins: + +- [inputs.execd](/plugins/inputs/execd) +- [processors.execd](/plugins/processors/execd) +- [outputs.execd](/plugins/outputs/execd) + +Follow the [Steps to externalize a plugin][] and +[Steps to build and run your plugin][] to properly with the Execd Go Shim. + +[Steps to externalize a plugin]: /plugins/common/shim#steps-to-externalize-a-plugin +[Steps to build and run your plugin]: /plugins/common/shim#steps-to-build-and-run-your-plugin + +## Step-by-Step guidelines + +This is a guide to help you set up a plugin to use it with `execd`: + +1. Write a Telegraf plugin. Depending on the plugin, follow the guidelines on + how to create the plugin itself using InfluxData's best practices: + - [Input Plugins](/docs/INPUTS.md) + - [Processor Plugins](/docs/PROCESSORS.md) + - [Aggregator Plugins](/docs/AGGREGATORS.md) + - [Output Plugins](/docs/OUTPUTS.md) +2. Move the project to an external repo, it is recommended to preserve the + path structure, but not strictly necessary. For example, if the plugin was + at `plugins/inputs/cpu`, it is recommended that it also be under + `plugins/inputs/cpu` in the new repo. For a further example of what this + might look like, take a look at [ssoroka/rand][] or + [danielnelson/telegraf-execd-openvpn][]. +3. Copy [main.go](/plugins/common/shim/example/cmd/main.go) into the project + under the `cmd` folder. This will be the entrypoint to the plugin when run as + a stand-alone program and it will call the shim code for you to make that + happen. It is recommended to have only one plugin per repo, as the shim is + not designed to run multiple plugins at the same time. +4. Edit the main.go file to import the plugin. Within Telegraf this would have + been done in an all.go file, but here we do not split the two apart, and the + change just goes in the top of main.go. If you skip this step, the plugin + will do nothing. + > `_ "github.com/me/my-plugin-telegraf/plugins/inputs/cpu"` +5. Optionally add a [plugin.conf](./example/cmd/plugin.conf) for configuration + specific to the plugin. Note that this config file **must be separate from + the rest of the config for Telegraf, and must not be in a shared directory + where Telegraf is expecting to load all configs**. If Telegraf reads this + config file it will not know which plugin it relates to. Telegraf instead + uses an execd config block to look for this plugin. +6. Add usage and development instructions in the homepage of the repository + for running the plugin with its respective `execd` plugin. Please refer to + [openvpn install][] and [awsalarms install][] for examples. Include the + following steps: + 1. How to download the release package for the platform or how to clone the + binary for the external plugin + 1. The commands to build the binary + 1. Location to edit the `telegraf.conf` + 1. Configuration to run the external plugin with + [inputs.execd](/plugins/inputs/execd), + [processors.execd](/plugins/processors/execd), or + [outputs.execd](/plugins/outputs/execd) +7. Submit the plugin by opening a PR to add the external plugin to the + [/EXTERNAL_PLUGINS.md](/EXTERNAL_PLUGINS.md) list. Please include the + plugin name, link to the plugin repository and a short description of the + plugin. + +[ssoroka/rand]: https://github.com/ssoroka/rand +[danielnelson/telegraf-execd-openvpn]: https://github.com/danielnelson/telegraf-execd-openvpn +[openvpn install]: https://github.com/danielnelson/telegraf-execd-openvpn#usage +[awsalarms install]: https://github.com/vipinvkmenon/awsalarms#installation diff --git a/docs/FAQ.md b/docs/FAQ.md new file mode 100644 index 0000000..4016ebc --- /dev/null +++ b/docs/FAQ.md @@ -0,0 +1,135 @@ +# Frequently Asked Questions + +## When is the next release? When will my PR or fix get released? + +Telegraf has four minor releases a year in March, June, September, and +December. In between each of those minor releases, there are 2-4 bug fix +releases that happen every 3 weeks. + +This [Google Calendar][] is kept up to date for upcoming releases dates. +Additionally, users can look at the [GitHub milestones][] for the next minor +and bug fix release. + +PRs that resolves issues are released in the next release. PRs that introduce +new features are held for the next minor release. Users can view what +[GitHub milestones][] a PR belongs to to determine the release it will go out +with. + +[Google Calendar]: https://calendar.google.com/calendar/embed?src=c_03d981cefd8d6432894cb162da5c6186e393bc0f970ca6c371201aa05d30d763%40group.calendar.google.com +[GitHub milestones]: https://github.com/influxdata/telegraf/milestones + +## How can I filter or select specific metrics? + +Telegraf has options to select certain metrics or tags as well as filter out +specific tags or fields: + +- **Selectors** allow a user to include or exclude entire metrics based on the + metric name or tag key/pair values. +- **Modifiers** allow a user to remove tags and fields based on specific keys, + with glob support. + +For more details and examples, see the [Metric Filtering][metric filtering] +section in the docs. + +## Could not find a usable config.yml, you may have revoked the CircleCI OAuth app + +This is an error from CircleCI during test runs. + +To resolve the error, you need to log back into CircleCI with your +username/password if that is how you log in or if you use GitHub log, re-create +your oauth/re-login with github. + +That should regenerate your token and then allow you to push a commit or close +and reopen this PR and tests should run. + +## What does "Context Deadline exceeded (Client.Timeout while awaiting headers)" mean? + +This is a generic error received from Go's HTTP client. It is generally the +result of a network blip or hiccup as a result of a DNS, proxy, firewall, +and/or other network issue. + +The error should be temporary and Telegraf will recover shortly after without +the loss of data. + +## How do I set the timestamp format for parsing data? + +Telegraf's `timestamp_format` config option requires the use +[Go's reference time][go ref time] to correctly translate the timestamp. For +example, if you have the time: + +```s +2023-03-01T00:00:42.586+0800 +``` + +A user needs the timestamp format: + +```s +2006-01-02T15:04:05.000-0700 +``` + +User's can try this out in the [Go playground][playground]. + +[go ref time]: https://pkg.go.dev/time#pkg-constants +[playground]: https://goplay.tools/snippet/hi9GIOG_gVQ + +## Q: How can I monitor the Docker Engine Host from within a container? + +You will need to setup several volume mounts as well as some environment +variables: + +```shell +docker run --name telegraf \ + -v /:/hostfs:ro \ + -e HOST_ETC=/hostfs/etc \ + -e HOST_PROC=/hostfs/proc \ + -e HOST_SYS=/hostfs/sys \ + -e HOST_VAR=/hostfs/var \ + -e HOST_RUN=/hostfs/run \ + -e HOST_MOUNT_PREFIX=/hostfs \ + telegraf +``` + +## Q: Why do I get a "no such host" error resolving hostnames that other programs can resolve? + +Go uses a pure Go resolver by default for [name resolution](https://golang.org/pkg/net/#hdr-Name_Resolution). +This resolver behaves differently than the C library functions but is more +efficient when used with the Go runtime. + +If you encounter problems or want to use more advanced name resolution methods +that are unsupported by the pure Go resolver, you can switch to the cgo +resolver. + +If running manually set: + +```shell +export GODEBUG=netdns=cgo +``` + +If running as a service add the environment variable to `/etc/default/telegraf`: + +```shell +GODEBUG=netdns=cgo +``` + +## Q: How can I manage series cardinality? + +High [series cardinality][], when not properly managed, can cause high load on +your database. Telegraf attempts to avoid creating series with high +cardinality, but some monitoring workloads such as tracking containers are are +inherently high cardinality. These workloads can still be monitored, but care +must be taken to manage cardinality growth. + +You can use the following techniques to avoid cardinality issues: + +- Use [metric filtering][] options to exclude unneeded measurements and tags. +- Write to a database with an appropriate [retention policy][]. +- Consider using the [Time Series Index][tsi]. +- Monitor your databases using the [show cardinality][] commands. +- Consult the [InfluxDB documentation][influx docs] for the most up-to-date techniques. + +[series cardinality]: https://docs.influxdata.com/influxdb/v1.7/concepts/glossary/#series-cardinality +[metric filtering]: https://github.com/influxdata/telegraf/blob/master/docs/CONFIGURATION.md#metric-filtering +[retention policy]: https://docs.influxdata.com/influxdb/latest/guides/downsampling_and_retention/ +[tsi]: https://docs.influxdata.com/influxdb/latest/concepts/time-series-index/ +[show cardinality]: https://docs.influxdata.com/influxdb/latest/query_language/spec/#show-cardinality +[influx docs]: https://docs.influxdata.com/influxdb/latest/ diff --git a/docs/INPUTS.md b/docs/INPUTS.md new file mode 100644 index 0000000..650f9ac --- /dev/null +++ b/docs/INPUTS.md @@ -0,0 +1,189 @@ +# Input Plugins + +This section is for developers who want to create new collection inputs. +Telegraf is entirely plugin driven. This interface allows for operators to +pick and chose what is gathered and makes it easy for developers +to create new ways of generating metrics. + +Plugin authorship is kept as simple as possible to promote people to develop +and submit new inputs. + +## Input Plugin Guidelines + +- A plugin must conform to the [telegraf.Input][] interface. +- Input Plugins should call `inputs.Add` in their `init` function to register + themselves. See below for a quick example. +- To be available within Telegraf itself, plugins must register themselves + using a file in `github.com/influxdata/telegraf/plugins/inputs/all` named + according to the plugin name. Make sure you also add build-tags to + conditionally build the plugin. +- Each plugin requires a file called `sample.conf` containing the sample + configuration for the plugin in TOML format. + Please consult the [Sample Config][] page for the latest style guidelines. +- Each plugin `README.md` file should include the `sample.conf` file in a + section describing the configuration by specifying a `toml` section in the + form `toml @sample.conf`. The specified file(s) are then injected + automatically into the Readme. +- Follow the recommended [Code Style][]. + +[Sample Config]: /docs/developers/SAMPLE_CONFIG.md +[Code Style]: /docs/developers/CODE_STYLE.md +[telegraf.Input]: https://godoc.org/github.com/influxdata/telegraf#Input + +### Typed Metrics + +In addition to the `AddFields` function, the accumulator also supports +functions to add typed metrics: `AddGauge`, `AddCounter`, etc. Metric types +are ignored by the InfluxDB output, but can be used for other outputs, such as +[prometheus][prom metric types]. + +[prom metric types]: https://prometheus.io/docs/concepts/metric_types/ + +### Data Formats + +Some input plugins, such as the [exec][] plugin, can accept any supported +[input data formats][]. + +In order to enable this, you must specify a `SetParser(parser parsers.Parser)` +function on the plugin object (see the exec plugin for an example), as well as +defining `parser` as a field of the object. + +You can then utilize the parser internally in your plugin, parsing data as you +see fit. Telegraf's configuration layer will take care of instantiating and +creating the `Parser` object. + +Add the following to the sample configuration in the README.md: + +```toml + ## Data format to consume. + ## Each data format has its own unique set of configuration options, read + ## more about them here: + ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md + data_format = "influx" +``` + +[exec]: /plugins/inputs/exec +[input data formats]: /docs/DATA_FORMATS_INPUT.md + +### Service Input Plugins + +This section is for developers who want to create new "service" collection +inputs. A service plugin differs from a regular plugin in that it operates a +background service while Telegraf is running. One example would be the +`statsd` plugin, which operates a statsd server. + +Service Input Plugins are substantially more complicated than a regular +plugin, as they will require threads and locks to verify data integrity. +Service Input Plugins should be avoided unless there is no way to create their +behavior with a regular plugin. + +To create a Service Input implement the [telegraf.ServiceInput][] interface. + +[telegraf.ServiceInput]: https://godoc.org/github.com/influxdata/telegraf#ServiceInput + +### Metric Tracking + +Metric Tracking provides a system to be notified when metrics have been +successfully written to their outputs or otherwise discarded. This allows +inputs to be created that function as reliable queue consumers. + +Please note that this process applies only to internal plugins. For external +plugins, the metrics are acknowledged regardless of the actual output. + +To get started with metric tracking begin by calling `WithTracking` on the +[telegraf.Accumulator][]. Add metrics using the `AddTrackingMetricGroup` +function on the returned [telegraf.TrackingAccumulator][] and store the +`TrackingID`. The `Delivered()` channel will return a type with information +about the final delivery status of the metric group. + +Check the [amqp_consumer][] for an example implementation. + +[telegraf.Accumulator]: https://godoc.org/github.com/influxdata/telegraf#Accumulator +[telegraf.TrackingAccumulator]: https://godoc.org/github.com/influxdata/telegraf#Accumulator +[amqp_consumer]: /plugins/inputs/amqp_consumer + +### External Services + +Plugins that connect or require the use of external services should ensure that +those servers are active. When may depend on the type of input plugin: + +For service input plugins, `Init` should be used to check for configuration +issues (e.g. bad option) and for other non-recoverable errors. Then `Start` +is used to create connections or other retry-able operations. + +For normal inputs, `Init` should also be used to check for configuration issues +as well as any other dependencies that the plugin will require. For example, +any binaries that must exist for the plugin to function. If making a connection, +this should also take place in `Init`. + +Developers may find that they switch to using service input plugins more and +more to take advantage of the error on retry behavior features. This allows +the user to decide what to do on an error, like ignoring the plugin or retrying +constantly. + +## Input Plugin Example + +Let's say you've written a plugin that emits metrics about processes on the +current host. + +### Register Plugin + +Registration of the plugin on `plugins/inputs/all/simple.go`: + +```go +//go:build !custom || inputs || inputs.simple + +package all + +import _ "github.com/influxdata/telegraf/plugins/inputs/simple" // register plugin +``` + +The _build-tags_ in the first line allow to selectively include/exclude your +plugin when customizing Telegraf. + +### Plugin + +Content of your plugin file e.g. `simple.go` + +```go +//go:generate ../../../tools/readme_config_includer/generator +package simple + +import ( + _ "embed" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/inputs" +) + +//go:embed sample.conf +var sampleConfig string + +type Simple struct { + Ok bool `toml:"ok"` + Log telegraf.Logger `toml:"-"` +} + +func (*Simple) SampleConfig() string { + return sampleConfig +} + +// Init is for setup, and validating config. +func (s *Simple) Init() error { + return nil +} + +func (s *Simple) Gather(acc telegraf.Accumulator) error { + if s.Ok { + acc.AddFields("state", map[string]interface{}{"value": "pretty good"}, nil) + } else { + acc.AddFields("state", map[string]interface{}{"value": "not great"}, nil) + } + + return nil +} + +func init() { + inputs.Add("simple", func() telegraf.Input { return &Simple{} }) +} +``` diff --git a/docs/INSTALL_GUIDE.md b/docs/INSTALL_GUIDE.md new file mode 100644 index 0000000..4b121c9 --- /dev/null +++ b/docs/INSTALL_GUIDE.md @@ -0,0 +1,156 @@ +# Installation + +Telegraf compiles to a single static binary, which makes it easy to install. +Both InfluxData and the community provide for a wide range of methods to install +Telegraf from. For details on each release, view the [changelog][] for the +latest updates and changes by version. + +[changelog]: /CHANGELOG.md + +There are many places to obtain Telegraf from: + +* [Binary downloads](#binary-downloads) +* [Homebrew](#homebrew) +* [InfluxData Linux package repository](#influxdata-linux-package-repository) +* [Official Docker images](#official-docker-images) +* [Helm charts](#helm-charts) +* [Nightly builds](#nightly-builds) +* [Build from source](#build-from-source) +* [Custom builder](#custom-builder) + +## Binary downloads + +Binary downloads for a wide range of architectures and operating systems are +available from the [InfluxData downloads][] page or from the +[GitHub Releases][] page. + +[InfluxData downloads]: https://www.influxdata.com/downloads +[GitHub Releases]: https://github.com/influxdata/telegraf/releases + +## Homebrew + +A [Homebrew Formula][] for Telegraf that updates after each release: + +```shell +brew update +brew install telegraf +``` + +Note that the Homebrew organization builds Telegraf itself and does not use +binaries built by InfluxData. This is important as Homebrew builds with CGO, +which means there are some differences between the official binaries and those +found with Homebrew. + +[Homebrew Formula]: https://formulae.brew.sh/formula/telegraf + +## InfluxData Linux package repository + +InfluxData provides a package repo that contains both DEB and RPM packages. + +### DEB + +For DEB-based platforms (e.g. Ubuntu and Debian) run the following to add the +repo GPG key and setup a new sources.list entry: + +```shell +# influxdata-archive_compat.key GPG fingerprint: +# 9D53 9D90 D332 8DC7 D6C8 D3B9 D8FF 8E1F 7DF8 B07E +wget -q https://repos.influxdata.com/influxdata-archive_compat.key +echo '393e8779c89ac8d958f81f942f9ad7fb82a25e133faddaf92e15b16e6ac9ce4c influxdata-archive_compat.key' | sha256sum -c && cat influxdata-archive_compat.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/influxdata-archive_compat.gpg > /dev/null +echo 'deb [signed-by=/etc/apt/trusted.gpg.d/influxdata-archive_compat.gpg] https://repos.influxdata.com/debian stable main' | sudo tee /etc/apt/sources.list.d/influxdata.list +sudo apt-get update && sudo apt-get install telegraf +``` + +### RPM + +For RPM-based platforms (e.g. RHEL, CentOS) use the following to create a repo +file and install telegraf: + +```shell +# influxdata-archive_compat.key GPG fingerprint: +# 9D53 9D90 D332 8DC7 D6C8 D3B9 D8FF 8E1F 7DF8 B07E +cat < "testcontainers-go" +[2]: "DockerHub" +[3]: "DockerHub Official Images" +[4]: "Bitnami Images" + +## Network + +By default the containers will use the bridge network where other containers +cannot talk to each other. + +If a custom network is required for running tests, for example if containers +do need to communicate, then users can set that up with the following code: + +```go +networkName := "test-network" +net, err := testcontainers.GenericNetwork(ctx, testcontainers.GenericNetworkRequest{ + NetworkRequest: testcontainers.NetworkRequest{ + Name: networkName, + Attachable: true, + CheckDuplicate: true, + }, +}) +require.NoError(t, err) +defer func() { + require.NoError(t, net.Remove(ctx), "terminating network failed") +}() +``` + +Then specify the network name in the container startup: + +```go +zookeeper := testutil.Container{ + Image: "wurstmeister/zookeeper", + ExposedPorts: []string{"2181:2181"}, + Networks: []string{networkName}, + WaitingFor: wait.ForLog("binding to port"), + Name: "telegraf-test-zookeeper", +} +``` + +## Contributing + +When adding integrations tests please do the following: + +- Add integration to the end of the test name +- Use testcontainers when an external service is required +- Use the testutil.Container to setup and configure testcontainers +- Ensure the testcontainer wait stanza is well-tested diff --git a/docs/LICENSE_OF_DEPENDENCIES.md b/docs/LICENSE_OF_DEPENDENCIES.md new file mode 100644 index 0000000..e862f73 --- /dev/null +++ b/docs/LICENSE_OF_DEPENDENCIES.md @@ -0,0 +1,480 @@ +# Licenses of dependencies + +When distributed in a binary form, Telegraf may contain portions of the +following works: + +- cel.dev/expr [Apache License 2.0](https://github.com/google/cel-spec/blob/master/LICENSE) +- cloud.google.com/go [Apache License 2.0](https://github.com/googleapis/google-cloud-go/blob/master/LICENSE) +- code.cloudfoundry.org/clock [Apache License 2.0](https://github.com/cloudfoundry/clock/blob/master/LICENSE) +- collectd.org [ISC License](https://github.com/collectd/go-collectd/blob/master/LICENSE) +- dario.cat/mergo [BSD 3-Clause "New" or "Revised" License](https://github.com/imdario/mergo/blob/master/LICENSE) +- filippo.io/edwards25519 [BSD 3-Clause "New" or "Revised" License](https://github.com/FiloSottile/edwards25519/blob/main/LICENSE) +- github.com/99designs/keyring [MIT License](https://github.com/99designs/keyring/blob/master/LICENSE) +- github.com/Azure/azure-amqp-common-go [MIT License](https://github.com/Azure/azure-amqp-common-go/blob/master/LICENSE) +- github.com/Azure/azure-event-hubs-go [MIT License](https://github.com/Azure/azure-event-hubs-go/blob/master/LICENSE) +- github.com/Azure/azure-kusto-go [MIT License](https://github.com/Azure/azure-kusto-go/blob/master/LICENSE) +- github.com/Azure/azure-pipeline-go [MIT License](https://github.com/Azure/azure-pipeline-go/blob/master/LICENSE) +- github.com/Azure/azure-sdk-for-go [MIT License](https://github.com/Azure/azure-sdk-for-go/blob/main/LICENSE.txt) +- github.com/Azure/azure-sdk-for-go/sdk/azcore [MIT License](https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/azcore/LICENSE.txt) +- github.com/Azure/azure-sdk-for-go/sdk/azidentity [MIT License](https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/azidentity/LICENSE.txt) +- github.com/Azure/azure-sdk-for-go/sdk/internal [MIT License](https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/internal/LICENSE.txt) +- github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs [MIT License](https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/messaging/azeventhubs/LICENSE.txt) +- github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor [MIT License](https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/resourcemanager/monitor/armmonitor/LICENSE.txt) +- github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources [MIT License](https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/resourcemanager/resources/armresources/LICENSE.txt) +- github.com/Azure/azure-sdk-for-go/sdk/storage/azblob [MIT License](https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/storage/azblob/LICENSE.txt) +- github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue [MIT License](https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/storage/azqueue/LICENSE.txt) +- github.com/Azure/azure-storage-queue-go [MIT License](https://github.com/Azure/azure-storage-queue-go/blob/master/LICENSE) +- github.com/Azure/go-amqp [MIT License](https://github.com/Azure/go-amqp/blob/master/LICENSE) +- github.com/Azure/go-ansiterm [MIT License](https://github.com/Azure/go-ansiterm/blob/master/LICENSE) +- github.com/Azure/go-autorest [Apache License 2.0](https://github.com/Azure/go-autorest/blob/master/LICENSE) +- github.com/Azure/go-ntlmssp [MIT License](https://github.com/Azure/go-ntlmssp/blob/master/LICENSE) +- github.com/AzureAD/microsoft-authentication-library-for-go [MIT License](https://github.com/AzureAD/microsoft-authentication-library-for-go/blob/main/LICENSE) +- github.com/BurntSushi/toml [MIT License](https://github.com/BurntSushi/toml/blob/master/COPYING) +- github.com/ClickHouse/ch-go [Apache License 2.0](https://github.com/ClickHouse/ch-go/blob/main/LICENSE) +- github.com/ClickHouse/clickhouse-go [Apache License 2.0](https://github.com/ClickHouse/clickhouse-go/blob/master/LICENSE) +- github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp [Apache License 2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/main/LICENSE) +- github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric [Apache License 2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/main/LICENSE) +- github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping [Apache License 2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/main/LICENSE) +- github.com/IBM/nzgo [MIT License](https://github.com/IBM/nzgo/blob/master/LICENSE.md) +- github.com/IBM/sarama [MIT License](https://github.com/IBM/sarama/blob/master/LICENSE.md) +- github.com/Masterminds/goutils [Apache License 2.0](https://github.com/Masterminds/goutils/blob/master/LICENSE.txt) +- github.com/Masterminds/semver [MIT License](https://github.com/Masterminds/semver/blob/master/LICENSE.txt) +- github.com/Masterminds/sprig [MIT License](https://github.com/Masterminds/sprig/blob/master/LICENSE.txt) +- github.com/Max-Sum/base32768 [MIT License](https://github.com/Max-Sum/base32768/blob/master/LICENSE) +- github.com/Mellanox/rdmamap [Apache License 2.0](https://github.com/Mellanox/rdmamap/blob/master/LICENSE) +- github.com/Microsoft/go-winio [MIT License](https://github.com/Microsoft/go-winio/blob/master/LICENSE) +- github.com/PaesslerAG/gval [BSD 3-Clause "New" or "Revised" License](https://github.com/PaesslerAG/gval/blob/master/LICENSE) +- github.com/SAP/go-hdb [Apache License 2.0](https://github.com/SAP/go-hdb/blob/main/LICENSE.md) +- github.com/abbot/go-http-auth [Apache License 2.0](https://github.com/abbot/go-http-auth/blob/master/LICENSE) +- github.com/aerospike/aerospike-client-go [Apache License 2.0](https://github.com/aerospike/aerospike-client-go/blob/master/LICENSE) +- github.com/alecthomas/participle [MIT License](https://github.com/alecthomas/participle/blob/master/COPYING) +- github.com/alecthomas/units [MIT License](https://github.com/alecthomas/units/blob/master/COPYING) +- github.com/alitto/pond [MIT License](https://github.com/alitto/pond/blob/master/LICENSE) +- github.com/aliyun/alibaba-cloud-sdk-go [Apache License 2.0](https://github.com/aliyun/alibaba-cloud-sdk-go/blob/master/LICENSE) +- github.com/amir/raidman [The Unlicense](https://github.com/amir/raidman/blob/master/UNLICENSE) +- github.com/andybalholm/brotli [MIT License](https://github.com/andybalholm/brotli/blob/master/LICENSE) +- github.com/antchfx/jsonquery [MIT License](https://github.com/antchfx/jsonquery/blob/master/LICENSE) +- github.com/antchfx/xmlquery [MIT License](https://github.com/antchfx/xmlquery/blob/master/LICENSE) +- github.com/antchfx/xpath [MIT License](https://github.com/antchfx/xpath/blob/master/LICENSE) +- github.com/antlr4-go/antlr [BSD 3-Clause "New" or "Revised" License](https://github.com/antlr/antlr4/blob/master/LICENSE.txt) +- github.com/apache/arrow-go [Apache License 2.0](https://github.com/apache/arrow-go/blob/main/LICENSE.txt) +- github.com/apache/arrow/go [Apache License 2.0](https://github.com/apache/arrow/blob/master/LICENSE.txt) +- github.com/apache/iotdb-client-go [Apache License 2.0](https://github.com/apache/iotdb-client-go/blob/main/LICENSE) +- github.com/apache/thrift [Apache License 2.0](https://github.com/apache/thrift/blob/master/LICENSE) +- github.com/apapsch/go-jsonmerge [MIT License](https://github.com/apapsch/go-jsonmerge/blob/master/LICENSE) +- github.com/aristanetworks/glog [Apache License 2.0](https://github.com/aristanetworks/glog/blob/master/LICENSE) +- github.com/aristanetworks/goarista [Apache License 2.0](https://github.com/aristanetworks/goarista/blob/master/COPYING) +- github.com/armon/go-metrics [MIT License](https://github.com/armon/go-metrics/blob/master/LICENSE) +- github.com/awnumar/memcall [Apache License 2.0](https://github.com/awnumar/memcall/blob/master/LICENSE) +- github.com/awnumar/memguard [Apache License 2.0](https://github.com/awnumar/memguard/blob/master/LICENSE) +- github.com/aws/aws-sdk-go-v2 [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/aws/protocol/eventstream/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/config [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/config/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/credentials [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/credentials/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/feature/ec2/imds [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/feature/ec2/imds/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/feature/s3/manager [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/feature/s3/manager/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/internal/configsources [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/internal/configsources/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/internal/endpoints [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/internal/endpoints/v2/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/internal/ini [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/internal/ini/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/internal/v4a [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/internal/v4a/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/cloudwatch [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/cloudwatch/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/cloudwatchlogs/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/dynamodb [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/dynamodb/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/ec2 [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/ec2/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/internal/accept-encoding/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/internal/checksum [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/internal/checksum/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/internal/endpoint-discovery/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/internal/presigned-url [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/internal/presigned-url/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/internal/s3shared [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/internal/s3shared/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/kinesis [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/kinesis/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/s3 [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/s3/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/sso [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/ec2/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/ssooidc [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/ssooidc/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/sts [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/sts/LICENSE.txt) +- github.com/aws/aws-sdk-go-v2/service/timestreamwrite [Apache License 2.0](https://github.com/aws/aws-sdk-go-v2/blob/main/service/timestreamwrite/LICENSE.txt) +- github.com/aws/smithy-go [Apache License 2.0](https://github.com/aws/smithy-go/blob/main/LICENSE) +- github.com/benbjohnson/clock [MIT License](https://github.com/benbjohnson/clock/blob/master/LICENSE) +- github.com/beorn7/perks [MIT License](https://github.com/beorn7/perks/blob/master/LICENSE) +- github.com/blues/jsonata-go [MIT License](https://github.com/blues/jsonata-go/blob/main/LICENSE) +- github.com/bmatcuk/doublestar [MIT License](https://github.com/bmatcuk/doublestar/blob/master/LICENSE) +- github.com/boschrexroth/ctrlx-datalayer-golang [MIT License](https://github.com/boschrexroth/ctrlx-datalayer-golang/blob/main/LICENSE) +- github.com/brutella/dnssd [MIT License](https://github.com/brutella/dnssd/blob/master/LICENSE) +- github.com/bufbuild/protocompile [Apache License 2.0](https://github.com/bufbuild/protocompile/blob/main/LICENSE) +- github.com/caio/go-tdigest [MIT License](https://github.com/caio/go-tdigest/blob/master/LICENSE) +- github.com/cenkalti/backoff [MIT License](https://github.com/cenkalti/backoff/blob/master/LICENSE) +- github.com/cespare/xxhash [MIT License](https://github.com/cespare/xxhash/blob/master/LICENSE.txt) +- github.com/cisco-ie/nx-telemetry-proto [Apache License 2.0](https://github.com/cisco-ie/nx-telemetry-proto/blob/master/LICENSE) +- github.com/clarify/clarify-go [Apache License 2.0](https://github.com/clarify/clarify-go/blob/master/LICENSE) +- github.com/cloudevents/sdk-go [Apache License 2.0](https://github.com/cloudevents/sdk-go/blob/main/LICENSE) +- github.com/cncf/xds/go [Apache License 2.0](https://github.com/cncf/xds/blob/main/LICENSE) +- github.com/compose-spec/compose-go [Apache License 2.0](https://github.com/compose-spec/compose-go/blob/master/LICENSE) +- github.com/containerd/log [Apache License 2.0](https://github.com/containerd/log/blob/main/LICENSE) +- github.com/containerd/platforms [Apache License 2.0](https://github.com/containerd/platforms/blob/main/LICENSE) +- github.com/coocood/freecache [MIT License](https://github.com/coocood/freecache/blob/master/LICENSE) +- github.com/coreos/go-semver [Apache License 2.0](https://github.com/coreos/go-semver/blob/main/LICENSE) +- github.com/coreos/go-systemd [Apache License 2.0](https://github.com/coreos/go-systemd/blob/main/LICENSE) +- github.com/couchbase/go-couchbase [MIT License](https://github.com/couchbase/go-couchbase/blob/master/LICENSE) +- github.com/couchbase/gomemcached [MIT License](https://github.com/couchbase/gomemcached/blob/master/LICENSE) +- github.com/couchbase/goutils [Apache License 2.0](https://github.com/couchbase/goutils/blob/master/LICENSE.md) +- github.com/cpuguy83/dockercfg [MIT License](https://github.com/cpuguy83/dockercfg/blob/main/LICENSE) +- github.com/cpuguy83/go-md2man [MIT License](https://github.com/cpuguy83/go-md2man/blob/master/LICENSE.md) +- github.com/danieljoos/wincred [MIT License](https://github.com/danieljoos/wincred/blob/master/LICENSE) +- github.com/datadope-io/go-zabbix [MIT License](https://github.com/datadope-io/go-zabbix/blob/master/LICENSE) +- github.com/davecgh/go-spew [ISC License](https://github.com/davecgh/go-spew/blob/master/LICENSE) +- github.com/devigned/tab [MIT License](https://github.com/devigned/tab/blob/master/LICENSE) +- github.com/dgryski/go-rendezvous [MIT License](https://github.com/dgryski/go-rendezvous/blob/master/LICENSE) +- github.com/digitalocean/go-libvirt [Apache License 2.0](https://github.com/digitalocean/go-libvirt/blob/master/LICENSE.md) +- github.com/dimchansky/utfbom [Apache License 2.0](https://github.com/dimchansky/utfbom/blob/master/LICENSE) +- github.com/distribution/reference [Apache License 2.0](https://github.com/distribution/reference/blob/main/LICENSE) +- github.com/djherbis/times [MIT License](https://github.com/djherbis/times/blob/master/LICENSE) +- github.com/docker/docker [Apache License 2.0](https://github.com/docker/docker/blob/master/LICENSE) +- github.com/docker/go-connections [Apache License 2.0](https://github.com/docker/go-connections/blob/master/LICENSE) +- github.com/docker/go-units [Apache License 2.0](https://github.com/docker/go-units/blob/master/LICENSE) +- github.com/dustin/go-humanize [MIT License](https://github.com/dustin/go-humanize/blob/master/LICENSE) +- github.com/dvsekhvalnov/jose2go [MIT License](https://github.com/dvsekhvalnov/jose2go/blob/master/LICENSE) +- github.com/dynatrace-oss/dynatrace-metric-utils-go [Apache License 2.0](https://github.com/dynatrace-oss/dynatrace-metric-utils-go/blob/master/LICENSE) +- github.com/eapache/go-resiliency [MIT License](https://github.com/eapache/go-resiliency/blob/master/LICENSE) +- github.com/eapache/go-xerial-snappy [MIT License](https://github.com/eapache/go-xerial-snappy/blob/master/LICENSE) +- github.com/eapache/queue [MIT License](https://github.com/eapache/queue/blob/master/LICENSE) +- github.com/ebitengine/purego [Apache License 2.0](https://github.com/ebitengine/purego/blob/main/LICENSE) +- github.com/eclipse/paho.golang [Eclipse Public License - v 2.0](https://github.com/eclipse/paho.golang/blob/master/LICENSE) +- github.com/eclipse/paho.mqtt.golang [Eclipse Public License - v 2.0](https://github.com/eclipse/paho.mqtt.golang/blob/master/LICENSE) +- github.com/emicklei/go-restful [MIT License](https://github.com/emicklei/go-restful/blob/v3/LICENSE) +- github.com/envoyproxy/go-control-plane/envoy [Apache License 2.0](https://github.com/envoyproxy/go-control-plane/blob/main/LICENSE) +- github.com/envoyproxy/protoc-gen-validate [Apache License 2.0](https://github.com/bufbuild/protoc-gen-validate/blob/main/LICENSE) +- github.com/facebook/time [Apache License 2.0](https://github.com/facebook/time/blob/main/LICENSE) +- github.com/fatih/color [MIT License](https://github.com/fatih/color/blob/master/LICENSE.md) +- github.com/felixge/httpsnoop [MIT License](https://github.com/felixge/httpsnoop/blob/master/LICENSE.txt) +- github.com/fxamacker/cbor [MIT License](https://github.com/fxamacker/cbor/blob/master/LICENSE) +- github.com/gabriel-vasile/mimetype [MIT License](https://github.com/gabriel-vasile/mimetype/blob/master/LICENSE) +- github.com/go-asn1-ber/asn1-ber [MIT License](https://github.com/go-asn1-ber/asn1-ber/blob/v1.3/LICENSE) +- github.com/go-chi/chi [MIT License](https://github.com/go-chi/chi/blob/master/LICENSE) +- github.com/go-faster/city [MIT License](https://github.com/go-faster/city/blob/main/LICENSE) +- github.com/go-faster/errors [BSD 3-Clause "New" or "Revised" License](https://github.com/go-faster/errors/blob/main/LICENSE) +- github.com/go-git/go-billy [Apache License 2.0](https://github.com/go-git/go-billy/blob/master/LICENSE) +- github.com/go-jose/go-jose [Apache License 2.0](https://github.com/go-jose/go-jose/blob/main/LICENSE) +- github.com/go-ldap/ldap [MIT License](https://github.com/go-ldap/ldap/blob/v3.4.1/LICENSE) +- github.com/go-logfmt/logfmt [MIT License](https://github.com/go-logfmt/logfmt/blob/master/LICENSE) +- github.com/go-logr/logr [Apache License 2.0](https://github.com/go-logr/logr/blob/master/LICENSE) +- github.com/go-logr/stdr [Apache License 2.0](https://github.com/go-logr/stdr/blob/master/LICENSE) +- github.com/go-ole/go-ole [MIT License](https://github.com/go-ole/go-ole/blob/master/LICENSE) +- github.com/go-openapi/jsonpointer [Apache License 2.0](https://github.com/go-openapi/jsonpointer/blob/master/LICENSE) +- github.com/go-openapi/jsonreference [Apache License 2.0](https://github.com/go-openapi/jsonreference/blob/master/LICENSE) +- github.com/go-openapi/swag [Apache License 2.0](https://github.com/go-openapi/swag/blob/master/LICENSE) +- github.com/go-redis/redis [BSD 2-Clause "Simplified" License](https://github.com/go-redis/redis/blob/master/LICENSE) +- github.com/go-sql-driver/mysql [Mozilla Public License 2.0](https://github.com/go-sql-driver/mysql/blob/master/LICENSE) +- github.com/go-stack/stack [MIT License](https://github.com/go-stack/stack/blob/master/LICENSE.md) +- github.com/go-stomp/stomp [Apache License 2.0](https://github.com/go-stomp/stomp/blob/master/LICENSE.txt) +- github.com/gobwas/glob [MIT License](https://github.com/gobwas/glob/blob/master/LICENSE) +- github.com/goccy/go-json [MIT License](https://github.com/goccy/go-json/blob/master/LICENSE) +- github.com/godbus/dbus [BSD 2-Clause "Simplified" License](https://github.com/godbus/dbus/blob/master/LICENSE) +- github.com/gofrs/uuid [MIT License](https://github.com/gofrs/uuid/blob/master/LICENSE) +- github.com/gogo/protobuf [BSD 3-Clause Clear License](https://github.com/gogo/protobuf/blob/master/LICENSE) +- github.com/golang-jwt/jwt [MIT License](https://github.com/golang-jwt/jwt/blob/main/LICENSE) +- github.com/golang-sql/civil [Apache License 2.0](https://github.com/golang-sql/civil/blob/master/LICENSE) +- github.com/golang-sql/sqlexp [BSD 3-Clause "New" or "Revised" License](https://github.com/golang-sql/sqlexp/blob/master/LICENSE) +- github.com/golang/geo [Apache License 2.0](https://github.com/golang/geo/blob/master/LICENSE) +- github.com/golang/groupcache [Apache License 2.0](https://github.com/golang/groupcache/blob/master/LICENSE) +- github.com/golang/protobuf [BSD 3-Clause "New" or "Revised" License](https://github.com/golang/protobuf/blob/master/LICENSE) +- github.com/golang/snappy [BSD 3-Clause "New" or "Revised" License](https://github.com/golang/snappy/blob/master/LICENSE) +- github.com/google/cel-go [Apache License 2.0](https://github.com/google/cel-go/blob/master/LICENSE) +- github.com/google/flatbuffers [Apache License 2.0](https://github.com/google/flatbuffers/blob/master/LICENSE) +- github.com/google/gnostic-models [Apache License 2.0](https://github.com/google/gnostic-models/blob/master/LICENSE) +- github.com/google/gnxi [Apache License 2.0](https://github.com/google/gnxi/blob/master/LICENSE) +- github.com/google/go-cmp [BSD 3-Clause "New" or "Revised" License](https://github.com/google/go-cmp/blob/master/LICENSE) +- github.com/google/go-github [BSD 3-Clause "New" or "Revised" License](https://github.com/google/go-github/blob/master/LICENSE) +- github.com/google/go-querystring [BSD 3-Clause "New" or "Revised" License](https://github.com/google/go-querystring/blob/master/LICENSE) +- github.com/google/go-tpm [Apache License 2.0](https://github.com/google/go-tpm/blob/main/LICENSE) +- github.com/google/s2a-go [Apache License 2.0](https://github.com/google/s2a-go/blob/main/LICENSE.md) +- github.com/google/uuid [BSD 3-Clause "New" or "Revised" License](https://github.com/google/uuid/blob/master/LICENSE) +- github.com/googleapis/enterprise-certificate-proxy [Apache License 2.0](https://github.com/googleapis/enterprise-certificate-proxy/blob/main/LICENSE) +- github.com/googleapis/gax-go [BSD 3-Clause "New" or "Revised" License](https://github.com/googleapis/gax-go/blob/master/LICENSE) +- github.com/gopacket/gopacket [BSD 3-Clause "New" or "Revised" License](https://github.com/gopacket/gopacket/blob/master/LICENSE) +- github.com/gopcua/opcua [MIT License](https://github.com/gopcua/opcua/blob/master/LICENSE) +- github.com/gophercloud/gophercloud [Apache License 2.0](https://github.com/gophercloud/gophercloud/blob/master/LICENSE) +- github.com/gorcon/rcon [MIT License](https://github.com/gorcon/rcon/blob/master/LICENSE) +- github.com/gorilla/mux [BSD 3-Clause "New" or "Revised" License](https://github.com/gorilla/mux/blob/master/LICENSE) +- github.com/gorilla/websocket [BSD 2-Clause "Simplified" License](https://github.com/gorilla/websocket/blob/master/LICENSE) +- github.com/gosnmp/gosnmp [BSD 2-Clause "Simplified" License](https://github.com/gosnmp/gosnmp/blob/master/LICENSE) +- github.com/grafana/regexp [BSD 3-Clause "New" or "Revised" License](https://github.com/grafana/regexp/blob/main/LICENSE) +- github.com/grid-x/modbus [BSD 3-Clause "New" or "Revised" License](https://github.com/grid-x/modbus/blob/master/LICENSE) +- github.com/grid-x/serial [MIT License](https://github.com/grid-x/serial/blob/master/LICENSE) +- github.com/grpc-ecosystem/grpc-gateway [BSD 3-Clause "New" or "Revised" License](https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE) +- github.com/gsterjov/go-libsecret [MIT License](https://github.com/gsterjov/go-libsecret/blob/master/LICENSE) +- github.com/gwos/tcg/sdk [MIT License](https://github.com/gwos/tcg/blob/master/LICENSE) +- github.com/hailocab/go-hostpool [MIT License](https://github.com/hailocab/go-hostpool/blob/master/LICENSE) +- github.com/hashicorp/consul/api [Mozilla Public License 2.0](https://github.com/hashicorp/consul/blob/main/api/LICENSE) +- github.com/hashicorp/errwrap [Mozilla Public License 2.0](https://github.com/hashicorp/errwrap/blob/master/LICENSE) +- github.com/hashicorp/go-cleanhttp [Mozilla Public License 2.0](https://github.com/hashicorp/go-cleanhttp/blob/master/LICENSE) +- github.com/hashicorp/go-hclog [MIT License](https://github.com/hashicorp/go-hclog/blob/main/LICENSE) +- github.com/hashicorp/go-immutable-radix [Mozilla Public License 2.0](https://github.com/hashicorp/go-immutable-radix/blob/master/LICENSE) +- github.com/hashicorp/go-multierror [Mozilla Public License 2.0](https://github.com/hashicorp/go-multierror/blob/master/LICENSE) +- github.com/hashicorp/go-rootcerts [Mozilla Public License 2.0](https://github.com/hashicorp/go-rootcerts/blob/master/LICENSE) +- github.com/hashicorp/go-uuid [Mozilla Public License 2.0](https://github.com/hashicorp/go-uuid/blob/master/LICENSE) +- github.com/hashicorp/golang-lru [Mozilla Public License 2.0](https://github.com/hashicorp/golang-lru/blob/master/LICENSE) +- github.com/hashicorp/packer-plugin-sdk [Mozilla Public License 2.0](https://github.com/hashicorp/packer-plugin-sdk/blob/main/LICENSE) +- github.com/hashicorp/serf [Mozilla Public License 2.0](https://github.com/hashicorp/serf/blob/master/LICENSE) +- github.com/huandu/xstrings [MIT License](https://github.com/huandu/xstrings/blob/master/LICENSE) +- github.com/imdario/mergo [BSD 3-Clause "New" or "Revised" License](https://github.com/imdario/mergo/blob/master/LICENSE) +- github.com/influxdata/influxdb-observability/common [MIT License](https://github.com/influxdata/influxdb-observability/blob/main/LICENSE) +- github.com/influxdata/influxdb-observability/influx2otel [MIT License](https://github.com/influxdata/influxdb-observability/blob/main/LICENSE) +- github.com/influxdata/influxdb-observability/otel2influx [MIT License](https://github.com/influxdata/influxdb-observability/blob/main/LICENSE) +- github.com/influxdata/line-protocol [MIT License](https://github.com/influxdata/line-protocol/blob/v2/LICENSE) +- github.com/influxdata/tail [MIT License](https://github.com/influxdata/tail/blob/master/LICENSE.txt) +- github.com/influxdata/toml [MIT License](https://github.com/influxdata/toml/blob/master/LICENSE) +- github.com/intel/iaevents [Apache License 2.0](https://github.com/intel/iaevents/blob/main/LICENSE) +- github.com/intel/powertelemetry [Apache License 2.0](https://github.com/intel/powertelemetry/blob/main/LICENSE) +- github.com/jackc/chunkreader [MIT License](https://github.com/jackc/chunkreader/blob/master/LICENSE) +- github.com/jackc/pgconn [MIT License](https://github.com/jackc/pgconn/blob/master/LICENSE) +- github.com/jackc/pgio [MIT License](https://github.com/jackc/pgio/blob/master/LICENSE) +- github.com/jackc/pgpassfile [MIT License](https://github.com/jackc/pgpassfile/blob/master/LICENSE) +- github.com/jackc/pgproto3 [MIT License](https://github.com/jackc/pgproto3/blob/master/LICENSE) +- github.com/jackc/pgservicefile [MIT License](https://github.com/jackc/pgservicefile/blob/master/LICENSE) +- github.com/jackc/pgtype [MIT License](https://github.com/jackc/pgtype/blob/master/LICENSE) +- github.com/jackc/pgx [MIT License](https://github.com/jackc/pgx/blob/master/LICENSE) +- github.com/jackc/puddle [MIT License](https://github.com/jackc/puddle/blob/master/LICENSE) +- github.com/jaegertracing/jaeger [Apache License 2.0](https://github.com/jaegertracing/jaeger/blob/master/LICENSE) +- github.com/jcmturner/aescts [Apache License 2.0](https://github.com/jcmturner/aescts/blob/master/LICENSE) +- github.com/jcmturner/dnsutils [Apache License 2.0](https://github.com/jcmturner/dnsutils/blob/master/LICENSE) +- github.com/jcmturner/gofork [BSD 3-Clause "New" or "Revised" License](https://github.com/jcmturner/gofork/blob/master/LICENSE) +- github.com/jcmturner/goidentity [Apache License 2.0](https://github.com/jcmturner/goidentity/blob/master/LICENSE) +- github.com/jcmturner/gokrb5 [Apache License 2.0](https://github.com/jcmturner/gokrb5/blob/master/LICENSE) +- github.com/jcmturner/rpc [Apache License 2.0](https://github.com/jcmturner/rpc/blob/master/LICENSE) +- github.com/jedib0t/go-pretty [MIT License](https://github.com/jedib0t/go-pretty/blob/main/LICENSE) +- github.com/jeremywohl/flatten [MIT License](https://github.com/jeremywohl/flatten/blob/master/LICENSE) +- github.com/jmespath/go-jmespath [Apache License 2.0](https://github.com/jmespath/go-jmespath/blob/master/LICENSE) +- github.com/jmhodges/clock [MIT License](https://github.com/jmhodges/clock/blob/main/LICENSE) +- github.com/josharian/intern [MIT License](https://github.com/josharian/intern/blob/master/LICENSE.md) +- github.com/josharian/native [MIT License](https://github.com/josharian/native/blob/main/license) +- github.com/jpillora/backoff [MIT License](https://github.com/jpillora/backoff/blob/master/LICENSE) +- github.com/json-iterator/go [MIT License](https://github.com/json-iterator/go/blob/master/LICENSE) +- github.com/jzelinskie/whirlpool [BSD 3-Clause "New" or "Revised" License](https://github.com/jzelinskie/whirlpool/blob/master/LICENSE) +- github.com/karrick/godirwalk [BSD 2-Clause "Simplified" License](https://github.com/karrick/godirwalk/blob/master/LICENSE) +- github.com/kballard/go-shellquote [MIT License](https://github.com/kballard/go-shellquote/blob/master/LICENSE) +- github.com/klauspost/compress [BSD 3-Clause Clear License](https://github.com/klauspost/compress/blob/master/LICENSE) +- github.com/klauspost/cpuid [MIT License](https://github.com/klauspost/cpuid/blob/master/LICENSE) +- github.com/klauspost/pgzip [MIT License](https://github.com/klauspost/pgzip/blob/master/LICENSE) +- github.com/kolo/xmlrpc [MIT License](https://github.com/kolo/xmlrpc/blob/master/LICENSE) +- github.com/kr/fs [BSD 3-Clause "New" or "Revised" License](https://github.com/kr/fs/blob/main/LICENSE) +- github.com/kylelemons/godebug [Apache License 2.0](https://github.com/kylelemons/godebug/blob/master/LICENSE) +- github.com/leodido/go-syslog [MIT License](https://github.com/influxdata/go-syslog/blob/develop/LICENSE) +- github.com/leodido/ragel-machinery [MIT License](https://github.com/leodido/ragel-machinery/blob/develop/LICENSE) +- github.com/linkedin/goavro [Apache License 2.0](https://github.com/linkedin/goavro/blob/master/LICENSE) +- github.com/logzio/azure-monitor-metrics-receiver [MIT License](https://github.com/logzio/azure-monitor-metrics-receiver/blob/master/LICENSE) +- github.com/magiconair/properties [BSD 2-Clause "Simplified" License](https://github.com/magiconair/properties/blob/main/LICENSE.md) +- github.com/mailru/easyjson [MIT License](https://github.com/mailru/easyjson/blob/master/LICENSE) +- github.com/mattn/go-colorable [MIT License](https://github.com/mattn/go-colorable/blob/master/LICENSE) +- github.com/mattn/go-ieproxy [MIT License](https://github.com/mattn/go-ieproxy/blob/master/LICENSE) +- github.com/mattn/go-isatty [MIT License](https://github.com/mattn/go-isatty/blob/master/LICENSE) +- github.com/mattn/go-runewidth [MIT License](https://github.com/mattn/go-runewidth/blob/master/LICENSE) +- github.com/mdlayher/apcupsd [MIT License](https://github.com/mdlayher/apcupsd/blob/master/LICENSE.md) +- github.com/mdlayher/genetlink [MIT License](https://github.com/mdlayher/genetlink/blob/master/LICENSE.md) +- github.com/mdlayher/netlink [MIT License](https://github.com/mdlayher/netlink/blob/master/LICENSE.md) +- github.com/mdlayher/socket [MIT License](https://github.com/mdlayher/socket/blob/master/LICENSE.md) +- github.com/mdlayher/vsock [MIT License](https://github.com/mdlayher/vsock/blob/main/LICENSE.md) +- github.com/microsoft/ApplicationInsights-Go [MIT License](https://github.com/microsoft/ApplicationInsights-Go/blob/master/LICENSE) +- github.com/microsoft/go-mssqldb [BSD 3-Clause "New" or "Revised" License](https://github.com/microsoft/go-mssqldb/blob/master/LICENSE.txt) +- github.com/miekg/dns [BSD 3-Clause Clear License](https://github.com/miekg/dns/blob/master/LICENSE) +- github.com/minio/highwayhash [Apache License 2.0](https://github.com/minio/highwayhash/blob/master/LICENSE) +- github.com/mitchellh/copystructure [MIT License](https://github.com/mitchellh/copystructure/blob/master/LICENSE) +- github.com/mitchellh/go-homedir [MIT License](https://github.com/mitchellh/go-homedir/blob/master/LICENSE) +- github.com/mitchellh/mapstructure [MIT License](https://github.com/mitchellh/mapstructure/blob/master/LICENSE) +- github.com/mitchellh/reflectwalk [MIT License](https://github.com/mitchellh/reflectwalk/blob/master/LICENSE) +- github.com/moby/docker-image-spec [Apache License 2.0](https://github.com/moby/docker-image-spec/blob/main/LICENSE) +- github.com/moby/go-archive [Apache License 2.0](https://github.com/moby/go-archive/blob/main/LICENSE) +- github.com/moby/ipvs [Apache License 2.0](https://github.com/moby/ipvs/blob/master/LICENSE) +- github.com/moby/patternmatcher [Apache License 2.0](https://github.com/moby/patternmatcher/blob/main/LICENSE) +- github.com/moby/sys/sequential [Apache License 2.0](https://github.com/moby/sys/blob/main/LICENSE) +- github.com/moby/sys/user [Apache License 2.0](https://github.com/moby/sys/blob/main/LICENSE) +- github.com/moby/sys/userns [Apache License 2.0](https://github.com/moby/sys/blob/main/LICENSE) +- github.com/moby/term [Apache License 2.0](https://github.com/moby/term/blob/master/LICENSE) +- github.com/modern-go/concurrent [Apache License 2.0](https://github.com/modern-go/concurrent/blob/master/LICENSE) +- github.com/modern-go/reflect2 [Apache License 2.0](https://github.com/modern-go/reflect2/blob/master/LICENSE) +- github.com/montanaflynn/stats [MIT License](https://github.com/montanaflynn/stats/blob/master/LICENSE) +- github.com/morikuni/aec [MIT License](https://github.com/morikuni/aec/blob/master/LICENSE) +- github.com/mtibben/percent [MIT License](https://github.com/mtibben/percent/blob/master/LICENSE) +- github.com/multiplay/go-ts3 [BSD 2-Clause "Simplified" License](https://github.com/multiplay/go-ts3/blob/master/LICENSE) +- github.com/munnerz/goautoneg [BSD 3-Clause Clear License](https://github.com/munnerz/goautoneg/blob/master/LICENSE) +- github.com/naoina/go-stringutil [MIT License](https://github.com/naoina/go-stringutil/blob/master/LICENSE) +- github.com/nats-io/jwt [Apache License 2.0](https://github.com/nats-io/jwt/blob/master/LICENSE) +- github.com/nats-io/nats-server [Apache License 2.0](https://github.com/nats-io/nats-server/blob/master/LICENSE) +- github.com/nats-io/nats.go [Apache License 2.0](https://github.com/nats-io/nats.go/blob/master/LICENSE) +- github.com/nats-io/nkeys [Apache License 2.0](https://github.com/nats-io/nkeys/blob/master/LICENSE) +- github.com/nats-io/nuid [Apache License 2.0](https://github.com/nats-io/nuid/blob/master/LICENSE) +- github.com/ncruces/go-strftime [MIT License](https://github.com/ncruces/go-strftime/blob/main/LICENSE) +- github.com/ncw/swift [MIT License](https://github.com/ncw/swift/blob/master/COPYING) +- github.com/netsampler/goflow2 [BSD 3-Clause "New" or "Revised" License](https://github.com/netsampler/goflow2/blob/main/LICENSE) +- github.com/newrelic/newrelic-telemetry-sdk-go [Apache License 2.0](https://github.com/newrelic/newrelic-telemetry-sdk-go/blob/master/LICENSE.md) +- github.com/nsqio/go-nsq [MIT License](https://github.com/nsqio/go-nsq/blob/master/LICENSE) +- github.com/nwaples/tacplus [BSD 2-Clause "Simplified" License](https://github.com/nwaples/tacplus/blob/master/LICENSE) +- github.com/oapi-codegen/runtime [Apache License 2.0](https://github.com/oapi-codegen/runtime/blob/main/LICENSE) +- github.com/olivere/elastic [MIT License](https://github.com/olivere/elastic/blob/release-branch.v7/LICENSE) +- github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/LICENSE) +- github.com/openconfig/gnmi [Apache License 2.0](https://github.com/openconfig/gnmi/blob/master/LICENSE) +- github.com/openconfig/goyang [Apache License 2.0](https://github.com/openconfig/goyang/blob/master/LICENSE) +- github.com/opencontainers/go-digest [Apache License 2.0](https://github.com/opencontainers/go-digest/blob/master/LICENSE) +- github.com/opencontainers/image-spec [Apache License 2.0](https://github.com/opencontainers/image-spec/blob/master/LICENSE) +- github.com/opensearch-project/opensearch-go [Apache License 2.0](https://github.com/opensearch-project/opensearch-go/blob/main/LICENSE.txt) +- github.com/opentracing/opentracing-go [Apache License 2.0](https://github.com/opentracing/opentracing-go/blob/master/LICENSE) +- github.com/p4lang/p4runtime [Apache License 2.0](https://github.com/p4lang/p4runtime/blob/main/LICENSE) +- github.com/paulmach/orb [MIT License](https://github.com/paulmach/orb/blob/master/LICENSE.md) +- github.com/pavlo-v-chernykh/keystore-go [MIT License](https://github.com/pavlo-v-chernykh/keystore-go/blob/master/LICENSE) +- github.com/pborman/ansi [BSD 3-Clause "New" or "Revised" License](https://github.com/pborman/ansi/blob/master/LICENSE) +- github.com/pcolladosoto/goslurm [MIT License](https://github.com/pcolladosoto/goslurm/blob/main/LICENSE) +- github.com/peterbourgon/unixtransport [Apache License 2.0](https://github.com/peterbourgon/unixtransport/blob/main/LICENSE) +- github.com/philhofer/fwd [MIT License](https://github.com/philhofer/fwd/blob/master/LICENSE.md) +- github.com/pierrec/lz4 [BSD 3-Clause "New" or "Revised" License](https://github.com/pierrec/lz4/blob/master/LICENSE) +- github.com/pion/dtls [MIT License](https://github.com/pion/dtls/blob/master/LICENSES/MIT.txt) +- github.com/pion/logging [MIT License](https://github.com/pion/logging/blob/master/LICENSES/MIT.txt) +- github.com/pion/transport [MIT License](https://github.com/pion/transport/blob/master/LICENSES/MIT.txt) +- github.com/pkg/browser [BSD 2-Clause "Simplified" License](https://github.com/pkg/browser/blob/master/LICENSE) +- github.com/pkg/errors [BSD 2-Clause "Simplified" License](https://github.com/pkg/errors/blob/master/LICENSE) +- github.com/pkg/sftp [BSD 2-Clause "Simplified" License](https://github.com/pkg/sftp/blob/master/LICENSE) +- github.com/pkg/xattr [BSD 2-Clause "Simplified" License](https://github.com/pkg/xattr/blob/master/LICENSE) +- github.com/pmezard/go-difflib [BSD 3-Clause Clear License](https://github.com/pmezard/go-difflib/blob/master/LICENSE) +- github.com/prometheus-community/pro-bing [MIT License](https://github.com/prometheus-community/pro-bing/blob/main/LICENSE) +- github.com/prometheus/client_golang [Apache License 2.0](https://github.com/prometheus/client_golang/blob/master/LICENSE) +- github.com/prometheus/client_model [Apache License 2.0](https://github.com/prometheus/client_model/blob/master/LICENSE) +- github.com/prometheus/common [Apache License 2.0](https://github.com/prometheus/common/blob/master/LICENSE) +- github.com/prometheus/procfs [Apache License 2.0](https://github.com/prometheus/procfs/blob/master/LICENSE) +- github.com/prometheus/prometheus [Apache License 2.0](https://github.com/prometheus/prometheus/blob/master/LICENSE) +- github.com/rabbitmq/amqp091-go [BSD 2-Clause "Simplified" License](https://github.com/rabbitmq/amqp091-go/blob/main/LICENSE) +- github.com/rclone/rclone [MIT License](https://github.com/rclone/rclone/blob/master/COPYING) +- github.com/rcrowley/go-metrics [BSD 2-Clause with views sentence](https://github.com/rcrowley/go-metrics/blob/master/LICENSE) +- github.com/redis/go-redis [BSD 2-Clause "Simplified" License](https://github.com/redis/go-redis/blob/master/LICENSE) +- github.com/remyoudompheng/bigfft [BSD 3-Clause "New" or "Revised" License](https://github.com/remyoudompheng/bigfft/blob/master/LICENSE) +- github.com/rfjakob/eme [MIT License](https://github.com/rfjakob/eme/blob/master/LICENSE) +- github.com/riemann/riemann-go-client [MIT License](https://github.com/riemann/riemann-go-client/blob/master/LICENSE) +- github.com/rivo/uniseg [MIT License](https://github.com/rivo/uniseg/blob/master/LICENSE.txt) +- github.com/robbiet480/go.nut [MIT License](https://github.com/robbiet480/go.nut/blob/master/LICENSE) +- github.com/robinson/gos7 [BSD 3-Clause "New" or "Revised" License](https://github.com/robinson/gos7/blob/master/LICENSE) +- github.com/russross/blackfriday [BSD 2-Clause "Simplified" License](https://github.com/russross/blackfriday/blob/master/LICENSE.txt) +- github.com/safchain/ethtool [Apache License 2.0](https://github.com/safchain/ethtool/blob/master/LICENSE) +- github.com/samber/lo [MIT License](https://github.com/samber/lo/blob/master/LICENSE) +- github.com/seancfoley/bintree [Apache License 2.0](https://github.com/seancfoley/bintree/blob/master/LICENSE) +- github.com/seancfoley/ipaddress-go [Apache License 2.0](https://github.com/seancfoley/ipaddress-go/blob/master/LICENSE) +- github.com/segmentio/asm [MIT License](https://github.com/segmentio/asm/blob/main/LICENSE) +- github.com/shirou/gopsutil [BSD 3-Clause Clear License](https://github.com/shirou/gopsutil/blob/master/LICENSE) +- github.com/shopspring/decimal [MIT License](https://github.com/shopspring/decimal/blob/master/LICENSE) +- github.com/showwin/speedtest-go [MIT License](https://github.com/showwin/speedtest-go/blob/master/LICENSE) +- github.com/signalfx/com_signalfx_metrics_protobuf [Apache License 2.0](https://github.com/signalfx/com_signalfx_metrics_protobuf/blob/master/LICENSE) +- github.com/signalfx/gohistogram [MIT License](https://github.com/signalfx/gohistogram/blob/master/LICENSE) +- github.com/signalfx/golib [Apache License 2.0](https://github.com/signalfx/golib/blob/master/LICENSE) +- github.com/signalfx/sapm-proto [Apache License 2.0](https://github.com/signalfx/sapm-proto/blob/master/LICENSE) +- github.com/sijms/go-ora [MIT License](https://github.com/sijms/go-ora/blob/master/LICENSE) +- github.com/sirupsen/logrus [MIT License](https://github.com/sirupsen/logrus/blob/master/LICENSE) +- github.com/sleepinggenius2/gosmi [MIT License](https://github.com/sleepinggenius2/gosmi/blob/master/LICENSE) +- github.com/snowflakedb/gosnowflake [Apache License 2.0](https://github.com/snowflakedb/gosnowflake/blob/master/LICENSE) +- github.com/spf13/cast [MIT License](https://github.com/spf13/cast/blob/master/LICENSE) +- github.com/spf13/pflag [BSD 3-Clause "New" or "Revised" License](https://github.com/spf13/pflag/blob/master/LICENSE) +- github.com/spiffe/go-spiffe [Apache License 2.0](https://github.com/spiffe/go-spiffe/blob/main/LICENSE) +- github.com/srebhan/cborquery [MIT License](https://github.com/srebhan/cborquery/blob/main/LICENSE) +- github.com/srebhan/protobufquery [MIT License](https://github.com/srebhan/protobufquery/blob/master/LICENSE) +- github.com/stoewer/go-strcase [MIT License](https://github.com/stoewer/go-strcase/blob/master/LICENSE) +- github.com/stretchr/objx [MIT License](https://github.com/stretchr/objx/blob/master/LICENSE) +- github.com/stretchr/testify [MIT License](https://github.com/stretchr/testify/blob/master/LICENSE) +- github.com/tdrn-org/go-hue [MIT License](https://github.com/tdrn-org/go-log/blob/main/LICENSE) +- github.com/tdrn-org/go-nsdp [MIT License](https://github.com/tdrn-org/go-nsdp/blob/main/LICENSE) +- github.com/testcontainers/testcontainers-go [MIT License](https://github.com/testcontainers/testcontainers-go/blob/main/LICENSE) +- github.com/thomasklein94/packer-plugin-libvirt [Mozilla Public License 2.0](https://github.com/thomasklein94/packer-plugin-libvirt/blob/main/LICENSE) +- github.com/tidwall/gjson [MIT License](https://github.com/tidwall/gjson/blob/master/LICENSE) +- github.com/tidwall/match [MIT License](https://github.com/tidwall/match/blob/master/LICENSE) +- github.com/tidwall/pretty [MIT License](https://github.com/tidwall/pretty/blob/master/LICENSE) +- github.com/tidwall/tinylru [MIT License](https://github.com/tidwall/tinylru/blob/master/LICENSE) +- github.com/tidwall/wal [MIT License](https://github.com/tidwall/wal/blob/master/LICENSE) +- github.com/tinylib/msgp [MIT License](https://github.com/tinylib/msgp/blob/master/LICENSE) +- github.com/tklauser/go-sysconf [BSD 3-Clause "New" or "Revised" License](https://github.com/tklauser/go-sysconf/blob/master/LICENSE) +- github.com/tklauser/numcpus [Apache License 2.0](https://github.com/tklauser/numcpus/blob/master/LICENSE) +- github.com/twmb/murmur3 [BSD 3-Clause "New" or "Revised" License](https://github.com/twmb/murmur3/blob/master/LICENSE) +- github.com/uber/jaeger-client-go [Apache License 2.0](https://github.com/jaegertracing/jaeger-client-go/blob/master/LICENSE) +- github.com/uber/jaeger-lib [Apache License 2.0](https://github.com/jaegertracing/jaeger-lib/blob/main/LICENSE) +- github.com/urfave/cli [MIT License](https://github.com/urfave/cli/blob/main/LICENSE) +- github.com/vapourismo/knx-go [MIT License](https://github.com/vapourismo/knx-go/blob/master/LICENSE) +- github.com/vishvananda/netlink [Apache License 2.0](https://github.com/vishvananda/netlink/blob/master/LICENSE) +- github.com/vishvananda/netns [Apache License 2.0](https://github.com/vishvananda/netns/blob/master/LICENSE) +- github.com/vjeantet/grok [Apache License 2.0](https://github.com/vjeantet/grok/blob/master/LICENSE) +- github.com/vmware/govmomi [Apache License 2.0](https://github.com/vmware/govmomi/blob/master/LICENSE.txt) +- github.com/wavefronthq/wavefront-sdk-go [Apache License 2.0](https://github.com/wavefrontHQ/wavefront-sdk-go/blob/master/LICENSE) +- github.com/x448/float16 [MIT License](https://github.com/x448/float16/blob/master/LICENSE) +- github.com/xanzy/ssh-agent [Apache License 2.0](https://github.com/xanzy/ssh-agent/blob/main/LICENSE) +- github.com/xdg-go/pbkdf2 [Apache License 2.0](https://github.com/xdg-go/pbkdf2/blob/main/LICENSE) +- github.com/xdg-go/scram [Apache License 2.0](https://github.com/xdg-go/scram/blob/master/LICENSE) +- github.com/xdg-go/stringprep [Apache License 2.0](https://github.com/xdg-go/stringprep/blob/master/LICENSE) +- github.com/xdg/scram [Apache License 2.0](https://github.com/xdg-go/scram/blob/master/LICENSE) +- github.com/xdg/stringprep [Apache License 2.0](https://github.com/xdg-go/stringprep/blob/master/LICENSE) +- github.com/xrash/smetrics [MIT License](https://github.com/xrash/smetrics/blob/master/LICENSE) +- github.com/youmark/pkcs8 [MIT License](https://github.com/youmark/pkcs8/blob/master/LICENSE) +- github.com/yuin/gopher-lua [MIT License](https://github.com/yuin/gopher-lua/blob/master/LICENSE) +- github.com/yusufpapurcu/wmi [MIT License](https://github.com/yusufpapurcu/wmi/blob/master/LICENSE) +- github.com/zeebo/errs [MIT License](https://github.com/zeebo/errs/blob/master/LICENSE) +- github.com/zeebo/xxh3 [BSD 2-Clause "Simplified" License](https://github.com/zeebo/xxh3/blob/master/LICENSE) +- go.mongodb.org/mongo-driver [Apache License 2.0](https://github.com/mongodb/mongo-go-driver/blob/master/LICENSE) +- go.opencensus.io [Apache License 2.0](https://github.com/census-instrumentation/opencensus-go/blob/master/LICENSE) +- go.opentelemetry.io/auto/sdk [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go-instrumentation/blob/main/sdk/LICENSE) +- go.opentelemetry.io/collector/consumer [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-collector/blob/main/LICENSE) +- go.opentelemetry.io/collector/pdata [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-collector/blob/main/LICENSE) +- go.opentelemetry.io/collector/semconv [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-collector/blob/main/LICENSE) +- go.opentelemetry.io/contrib/detectors/gcp [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/LICENSE) +- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/LICENSE) +- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/LICENSE) +- go.opentelemetry.io/otel [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE) +- go.opentelemetry.io/otel/metric [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE) +- go.opentelemetry.io/otel/sdk [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE) +- go.opentelemetry.io/otel/sdk/metric [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE) +- go.opentelemetry.io/otel/trace [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE) +- go.opentelemetry.io/proto/otlp [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-proto-go/blob/main/LICENSE) +- go.starlark.net [BSD 3-Clause "New" or "Revised" License](https://github.com/google/starlark-go/blob/master/LICENSE) +- go.step.sm/crypto [Apache License 2.0](https://github.com/smallstep/crypto/blob/master/LICENSE) +- go.uber.org/atomic [MIT License](https://pkg.go.dev/go.uber.org/atomic?tab=licenses) +- go.uber.org/multierr [MIT License](https://pkg.go.dev/go.uber.org/multierr?tab=licenses) +- go.uber.org/zap [MIT License](https://pkg.go.dev/go.uber.org/zap?tab=licenses) +- golang.org/x/crypto [BSD 3-Clause Clear License](https://github.com/golang/crypto/blob/master/LICENSE) +- golang.org/x/exp [BSD 3-Clause Clear License](https://github.com/golang/exp/blob/master/LICENSE) +- golang.org/x/net [BSD 3-Clause Clear License](https://github.com/golang/net/blob/master/LICENSE) +- golang.org/x/oauth2 [BSD 3-Clause "New" or "Revised" License](https://github.com/golang/oauth2/blob/master/LICENSE) +- golang.org/x/sync [BSD 3-Clause "New" or "Revised" License](https://github.com/golang/sync/blob/master/LICENSE) +- golang.org/x/sys [BSD 3-Clause Clear License](https://github.com/golang/sys/blob/master/LICENSE) +- golang.org/x/term [BSD 3-Clause License](https://pkg.go.dev/golang.org/x/term?tab=licenses) +- golang.org/x/text [BSD 3-Clause Clear License](https://github.com/golang/text/blob/master/LICENSE) +- golang.org/x/time [BSD 3-Clause Clear License](https://github.com/golang/time/blob/master/LICENSE) +- golang.org/x/xerrors [BSD 3-Clause Clear License](https://github.com/golang/xerrors/blob/master/LICENSE) +- golang.zx2c4.com/wireguard [MIT License](https://github.com/WireGuard/wgctrl-go/blob/master/LICENSE.md) +- golang.zx2c4.com/wireguard/wgctrl [MIT License](https://github.com/WireGuard/wgctrl-go/blob/master/LICENSE.md) +- gonum.org/v1/gonum [BSD 3-Clause "New" or "Revised" License](https://github.com/gonum/gonum/blob/master/LICENSE) +- google.golang.org/api [BSD 3-Clause "New" or "Revised" License](https://github.com/googleapis/google-api-go-client/blob/master/LICENSE) +- google.golang.org/genproto [Apache License 2.0](https://github.com/google/go-genproto/blob/master/LICENSE) +- google.golang.org/genproto/googleapis/api [Apache License 2.0](https://pkg.go.dev/google.golang.org/genproto/googleapis/api?tab=licenses) +- google.golang.org/genproto/googleapis/rpc [Apache License 2.0](https://pkg.go.dev/google.golang.org/genproto/googleapis/rpc?tab=licenses) +- google.golang.org/grpc [Apache License 2.0](https://github.com/grpc/grpc-go/blob/master/LICENSE) +- google.golang.org/protobuf [BSD 3-Clause "New" or "Revised" License](https://pkg.go.dev/google.golang.org/protobuf?tab=licenses) +- gopkg.in/evanphx/json-patch.v4 [BSD 3-Clause "New" or "Revised" License](https://github.com/evanphx/json-patch/blob/master/LICENSE) +- gopkg.in/fatih/pool.v2 [MIT License](https://github.com/fatih/pool/blob/v2.0.0/LICENSE) +- gopkg.in/fsnotify.v1 [BSD 3-Clause "New" or "Revised" License](https://github.com/fsnotify/fsnotify/blob/v1.4.7/LICENSE) +- gopkg.in/gorethink/gorethink.v3 [Apache License 2.0](https://github.com/rethinkdb/rethinkdb-go/blob/v3.0.5/LICENSE) +- gopkg.in/inf.v0 [BSD 3-Clause "New" or "Revised" License](https://github.com/go-inf/inf/blob/v0.9.1/LICENSE) +- gopkg.in/ini.v1 [Apache License 2.0](https://github.com/go-ini/ini/blob/master/LICENSE) +- gopkg.in/olivere/elastic.v5 [MIT License](https://github.com/olivere/elastic/blob/v5.0.76/LICENSE) +- gopkg.in/tomb.v1 [BSD 3-Clause Clear License](https://github.com/go-tomb/tomb/blob/v1/LICENSE) +- gopkg.in/tomb.v2 [BSD 3-Clause Clear License](https://github.com/go-tomb/tomb/blob/v2/LICENSE) +- gopkg.in/yaml.v2 [Apache License 2.0](https://github.com/go-yaml/yaml/blob/v2.2.2/LICENSE) +- gopkg.in/yaml.v3 [MIT License](https://github.com/go-yaml/yaml/blob/v3/LICENSE) +- k8s.io/api [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE) +- k8s.io/apimachinery [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE) +- k8s.io/client-go [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE) +- k8s.io/klog [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE) +- k8s.io/kube-openapi [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE) +- k8s.io/utils [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE) +- layeh.com/radius [Mozilla Public License 2.0](https://github.com/layeh/radius/blob/master/LICENSE) +- modernc.org/libc [BSD 3-Clause "New" or "Revised" License](https://gitlab.com/cznic/libc/-/blob/master/LICENSE) +- modernc.org/mathutil [BSD 3-Clause "New" or "Revised" License](https://gitlab.com/cznic/mathutil/-/blob/master/LICENSE) +- modernc.org/memory [BSD 3-Clause "New" or "Revised" License](https://gitlab.com/cznic/memory/-/blob/master/LICENSE) +- modernc.org/sqlite [BSD 3-Clause "New" or "Revised" License](https://gitlab.com/cznic/sqlite/-/blob/master/LICENSE) +- sigs.k8s.io/json [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE) +- sigs.k8s.io/randfill [Apache License 2.0](https://github.com/kubernetes-sigs/randfill/blob/main/LICENSE) +- sigs.k8s.io/structured-merge-diff [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE) +- sigs.k8s.io/yaml [Apache License 2.0](https://github.com/kubernetes/client-go/blob/master/LICENSE) +- software.sslmate.com/src/go-pkcs12 [BSD 3-Clause "New" or "Revised" License](https://github.com/SSLMate/go-pkcs12/blob/master/LICENSE) + +## Telegraf used and modified code from these projects + +- github.com/DataDog/datadog-agent [Apache License 2.0](https://github.com/DataDog/datadog-agent/blob/main/LICENSE) diff --git a/docs/METRICS.md b/docs/METRICS.md new file mode 100644 index 0000000..8ec1823 --- /dev/null +++ b/docs/METRICS.md @@ -0,0 +1,50 @@ +# Metrics + +Telegraf metrics are the internal representation used to model data during +processing. Metrics are closely based on InfluxDB's data model and contain +four main components: + +- **Measurement Name**: Description and namespace for the metric. +- **Tags**: Key/Value string pairs and usually used to identify the + metric. +- **Fields**: Key/Value pairs that are typed and usually contain the + metric data. +- **Timestamp**: Date and time associated with the fields. + +This metric type exists only in memory and must be converted to a concrete +representation in order to be transmitted or viewed. To achieve this we +provide several [output data formats][] sometimes referred to as +*serializers*. Our default serializer converts to [InfluxDB Line +Protocol][line protocol] which provides a high performance and one-to-one +direct mapping from Telegraf metrics. + +[output data formats]: /docs/DATA_FORMATS_OUTPUT.md +[line protocol]: /plugins/serializers/influx + +## Tracking Metrics + +Tracking metrics are metrics that ensure that data is passed from the input and +handed to an output before acknowledging the message back to the input. The +use case for these types of metrics is to ensure that the message makes it to +the destination before removing the metric from the input. + +For example, if a configuration is reading from MQTT, Kafka, or an AMQP source +Telegraf will read the message and wait till the metric is handed to the output +before telling the metric source that the message was read. If Telegraf were to +stop or the system running Telegraf to crash, this allows the messages that +were not completely delivered to an output to get re-read at a later date. + +Please note that this process applies only to internal plugins. For external +plugins, the metrics are acknowledged regardless of the actual output. + +### Undelivered Messages + +When an input uses tracking metrics, an additional setting, +`max_undelivered_messages`, is available in that plugin. This setting +determines how many metrics should be read in before reading additional +messages. In practice, this means that Telegraf may not read new messages from +an input at every collection interval. + +Users need to use caution with this setting. Setting the value too high may +mean that Telegraf pushes constant batches to an output, ignoring the flush +interval. diff --git a/docs/NIGHTLIES.md b/docs/NIGHTLIES.md new file mode 100644 index 0000000..0e65547 --- /dev/null +++ b/docs/NIGHTLIES.md @@ -0,0 +1,32 @@ + +# Nightly Builds + +These builds are generated from the master branch at midnight UTC: + +| DEB | RPM | TAR GZ | ZIP | +| --------------- | --------------- | ------------------------------| --- | +| [amd64.deb](https://dl.influxdata.com/telegraf/nightlies/telegraf_nightly_amd64.deb) | [aarch64.rpm](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly.aarch64.rpm) | [darwin_amd64.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_darwin_amd64.tar.gz) | [windows_amd64.zip](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_windows_amd64.zip) | +| [arm64.deb](https://dl.influxdata.com/telegraf/nightlies/telegraf_nightly_arm64.deb) | [armel.rpm](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly.armel.rpm) | [darwin_arm64.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_darwin_arm64.tar.gz) | [windows_arm64.zip](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_windows_arm64.zip) | +| [armel.deb](https://dl.influxdata.com/telegraf/nightlies/telegraf_nightly_armel.deb) | [armv6hl.rpm](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly.armv6hl.rpm) | [freebsd_amd64.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_freebsd_amd64.tar.gz) | [windows_i386.zip](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_windows_i386.zip) | +| [armhf.deb](https://dl.influxdata.com/telegraf/nightlies/telegraf_nightly_armhf.deb) | [i386.rpm](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly.i386.rpm) | [freebsd_armv7.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_freebsd_armv7.tar.gz) | | +| [i386.deb](https://dl.influxdata.com/telegraf/nightlies/telegraf_nightly_i386.deb) | [loong64.rpm](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly.loong64.rpm) | [freebsd_i386.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_freebsd_i386.tar.gz) | | +| [loong64.deb](https://dl.influxdata.com/telegraf/nightlies/telegraf_nightly_loong64.deb) | [ppc64le.rpm](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly.ppc64le.rpm) | [linux_amd64.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_amd64.tar.gz) | | +| [mips.deb](https://dl.influxdata.com/telegraf/nightlies/telegraf_nightly_mips.deb) | [riscv64.rpm](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly.riscv64.rpm) | [linux_arm64.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_arm64.tar.gz) | | +| [mipsel.deb](https://dl.influxdata.com/telegraf/nightlies/telegraf_nightly_mipsel.deb) | [s390x.rpm](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly.s390x.rpm) | [linux_armel.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_armel.tar.gz) | | +| [ppc64el.deb](https://dl.influxdata.com/telegraf/nightlies/telegraf_nightly_ppc64el.deb) | [x86_64.rpm](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly.x86_64.rpm) | [linux_armhf.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_armhf.tar.gz) | | +| [riscv64.deb](https://dl.influxdata.com/telegraf/nightlies/telegraf_nightly_riscv64.deb) | | [linux_i386.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_i386.tar.gz) | | +| [s390x.deb](https://dl.influxdata.com/telegraf/nightlies/telegraf_nightly_s390x.deb) | | [linux_loong64.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_loong64.tar.gz) | | +| | | [linux_mips.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_mips.tar.gz) | | +| | | [linux_mipsel.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_mipsel.tar.gz) | | +| | | [linux_ppc64le.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_ppc64le.tar.gz) | | +| | | [linux_riscv64.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_riscv64.tar.gz) | | +| | | [linux_s390x.tar.gz](https://dl.influxdata.com/telegraf/nightlies/telegraf-nightly_linux_s390x.tar.gz) | | + +Nightly docker images are available on [quay.io](https://quay.io/repository/influxdb/telegraf-nightly?tab=tags): + +```shell +# Debian-based image +docker pull quay.io/influxdb/telegraf-nightly:latest +# Alpine-based image +docker pull quay.io/influxdb/telegraf-nightly:alpine +``` diff --git a/docs/OUTPUTS.md b/docs/OUTPUTS.md new file mode 100644 index 0000000..28b6b02 --- /dev/null +++ b/docs/OUTPUTS.md @@ -0,0 +1,150 @@ +# Output Plugins + +This section is for developers who want to create a new output sink. Outputs +are created in a similar manner as collection plugins, and their interface has +similar constructs. + +## Output Plugin Guidelines + +- An output must conform to the [telegraf.Output][] interface. +- Outputs should call `outputs.Add` in their `init` function to register + themselves. See below for a quick example. +- To be available within Telegraf itself, plugins must register themselves + using a file in `github.com/influxdata/telegraf/plugins/outputs/all` named + according to the plugin name. Make sure you also add build-tags to + conditionally build the plugin. +- Each plugin requires a file called `sample.conf` containing the sample + configuration for the plugin in TOML format. + Please consult the [Sample Config][] page for the latest style guidelines. +- Each plugin `README.md` file should include the `sample.conf` file in a + section describing the configuration by specifying a `toml` section in the + form `toml @sample.conf`. The specified file(s) are then injected + automatically into the Readme. +- Follow the recommended [Code Style][]. + +[Sample Config]: /docs/developers/SAMPLE_CONFIG.md +[Code Style]: /docs/developers/CODE_STYLE.md +[telegraf.Output]: https://godoc.org/github.com/influxdata/telegraf#Output + +## Data Formats + +Some output plugins, such as the [file][] plugin, can write in any supported +[output data formats][]. + +In order to enable this, you must specify a +`SetSerializer(serializer serializers.Serializer)` +function on the plugin object (see the file plugin for an example), as well as +defining `serializer` as a field of the object. + +You can then utilize the serializer internally in your plugin, serializing data +before it's written. Telegraf's configuration layer will take care of +instantiating and creating the `Serializer` object. + +You should also add the following to your `SampleConfig()`: + +```toml + ## Data format to output. + ## Each data format has its own unique set of configuration options, read + ## more about them here: + ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md + data_format = "influx" +``` + +[file]: /plugins/inputs/file +[output data formats]: /docs/DATA_FORMATS_OUTPUT.md + +## Flushing Metrics to Outputs + +Metrics are flushed to outputs when any of the following events happen: + +- `flush_interval + rand(flush_jitter)` has elapsed since start or the last + flush interval +- At least `metric_batch_size` count of metrics are waiting in the buffer +- The telegraf process has received a SIGUSR1 signal + +Note that if the flush takes longer than the `agent.interval` to write the +metrics to the output, user will see a message saying the output: + +> did not complete within its flush interval + +This may mean the output is not keeping up with the flow of metrics, and you may +want to look into enabling compression, reducing the size of your metrics or +investigate other reasons why the writes might be taking longer than expected. + +## Output Plugin Example + +## Registration + +Registration of the plugin on `plugins/outputs/all/simpleoutput.go`: + +```go +//go:build !custom || outputs || outputs.simpleoutput + +package all + +import _ "github.com/influxdata/telegraf/plugins/outputs/simpleoutput" // register plugin + +``` + +The _build-tags_ in the first line allow to selectively include/exclude your +plugin when customizing Telegraf. + +## Plugin + +Content of your plugin file e.g. `simpleoutput.go` + +```go +//go:generate ../../../tools/readme_config_includer/generator +package simpleoutput + +// simpleoutput.go + +import ( + _ "embed" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/outputs" +) + +//go:embed sample.conf +var sampleConfig string + +type Simple struct { + Ok bool `toml:"ok"` + Log telegraf.Logger `toml:"-"` +} + +func (*Simple) SampleConfig() string { + return sampleConfig +} + +// Init is for setup, and validating config. +func (s *Simple) Init() error { + return nil +} + +func (s *Simple) Connect() error { + // Make any connection required here + return nil +} + +func (s *Simple) Close() error { + // Close any connections here. + // Write will not be called once Close is called, so there is no need to synchronize. + return nil +} + +// Write should write immediately to the output, and not buffer writes +// (Telegraf manages the buffer for you). Returning an error will fail this +// batch of writes and the entire batch will be retried automatically. +func (s *Simple) Write(metrics []telegraf.Metric) error { + for _, metric := range metrics { + // write `metric` to the output sink here + } + return nil +} + +func init() { + outputs.Add("simpleoutput", func() telegraf.Output { return &Simple{} }) +} +``` diff --git a/docs/PARSING_DATA.md b/docs/PARSING_DATA.md new file mode 100644 index 0000000..5142ebd --- /dev/null +++ b/docs/PARSING_DATA.md @@ -0,0 +1,243 @@ +# Parsing Data + +Telegraf has the ability to take data in a variety of formats. Telegraf requires +configuration from the user in order to correctly parse, store, and send the +original data. Telegraf does not take the raw data and maintain it internally. + +Telegraf uses an internal metric representation consisting of the metric name, +tags, fields and a timestamp, very similar to [line protocol][]. This +means that data needs to be broken up into a metric name, tags, fields, and a +timestamp. While none of these options are required, they are available to +the user and might be necessary to ensure the data is represented correctly. + +[line protocol]: https://docs.influxdata.com/influxdb/cloud/reference/syntax/line-protocol/ + +## Parsers + +The first step is to determine which parser to use. Look at the list of +[parsers][] and find one that will work with the user's data. This is generally +straightforward as the data-type will only have one parser that is actually +applicable to the data. + +[parsers]: https://github.com/influxdata/telegraf/tree/master/plugins/parsers + +### JSON parsers + +There is an exception when it comes to JSON data. Instead of a single parser, +there are three different parsers capable of reading JSON data: + +* `json`: This parser is great for flat JSON data. If the JSON is more complex + and for example, has other objects or nested arrays, then do not use this and + look at the other two options. +* `json_v2`: The v2 parser was created out of the need to parse JSON objects. It + can take on more advanced cases, at the cost of additional configuration. +* `xpath_json`: The xpath parser is the most capable of the three options. While + the xpath name may imply XML data, it can parse a variety of data types using + XPath expressions. + +## Tags and fields + +The next step is to look at the data and determine how the data needs to be +split up between tags and fields. Tags are generally strings or values that a +user will want to search on. While fields are the raw data values, numeric +types, etc. Generally, data is considered to be a field unless otherwise +specified as a tag. + +## Timestamp + +To parse a timestamp, at the very least the users needs to specify which field +has the timestamp and what the format of the timestamp is. The format can either +be a predefined Unix timestamp or parsed using a custom format based on Go +reference time. + +For Unix timestamps Telegraf understands the following settings: + +| Timestamp | Timestamp Format | +|-----------------------|------------------| +| `1709572232` | `unix` | +| `1709572232123` | `unix_ms` | +| `1709572232123456` | `unix_us` | +| `1709572232123456789` | `unix_ns` | + +There are some named formats available as well: + +| Timestamp | Named Format | +|---------------------------------------|---------------| +| `Mon Jan _2 15:04:05 2006` | `ANSIC` | +| `Mon Jan _2 15:04:05 MST 2006` | `UnixDate` | +| `Mon Jan 02 15:04:05 -0700 2006` | `RubyDate` | +| `02 Jan 06 15:04 MST` | `RFC822` | +| `02 Jan 06 15:04 -0700` | `RFC822Z` | +| `Monday, 02-Jan-06 15:04:05 MST` | `RFC850` | +| `Mon, 02 Jan 2006 15:04:05 MST` | `RFC1123` | +| `Mon, 02 Jan 2006 15:04:05 -0700` | `RFC1123Z` | +| `2006-01-02T15:04:05Z07:00` | `RFC3339` | +| `2006-01-02T15:04:05.999999999Z07:00` | `RFC3339Nano` | +| `Jan _2 15:04:05` | `Stamp` | +| `Jan _2 15:04:05.000` | `StampMilli` | +| `Jan _2 15:04:05.000000` | `StampMicro` | +| `Jan _2 15:04:05.000000000` | `StampNano` | + +If the timestamp does not conform to any of the above, then the user can specify +a custom timestamp format, in which the user must provide the timestamp in +[Go reference time][] notation. Here are a few example timestamps and their Go +reference time equivalent: + +| Timestamp | Go reference time | +|-------------------------------|-------------------------------| +| `2024-03-04T17:10:32` | `2006-01-02T15:04:05` | +| `04 Mar 24 10:10 -0700` | `02 Jan 06 15:04 -0700` | +| `2024-03-04T10:10:32Z07:00` | `2006-01-02T15:04:05Z07:00` | +| `2024-03-04 17:10:32.123+00` | `2006-01-02 15:04:05.999+00` | +| `2024-03-04T10:10:32.123456Z` | `2006-01-02T15:04:05.000000Z` | +| `2024-03-04T10:10:32.123456Z` | `2006-01-02T15:04:05.999999999Z` | + +Note for fractional second values, the user can use either a `9` or `0`. Using a +`0` forces a certain length, but using `9`s do not. + +Please note, that timezone abbreviations are ambiguous! For example `MST`, can +stand for either Mountain Standard Time (UTC-07) or Malaysia Standard Time +(UTC+08). As such, avoid abbreviated timezones if possible. + +Unix timestamps use UTC, there is no concept of a timezone for a Unix timestamp. + +[Go reference time]: https://pkg.go.dev/time#pkg-constants + +## Examples + +Below are a few basic examples to get users started. + +### CSV + +Given the following data: + +```csv +node,temp,humidity,alarm,time +node1,32.3,23,false,2023-03-06T16:52:23Z +node2,22.6,44,false,2023-03-06T16:52:23Z +node3,17.9,56,true,2023-03-06T16:52:23Z +``` + +Here is corresponding parser configuration and result: + +```toml +[[inputs.file]] +files = ["test.csv"] +data_format = "csv" + +csv_header_row_count = 1 +csv_column_names = ["node","temp","humidity","alarm","time"] +csv_tag_columns = ["node"] +csv_timestamp_column = "time" +csv_timestamp_format = "2006-01-02T15:04:05Z" +``` + +```text +file,node=node1 temp=32.3,humidity=23i,alarm=false 1678121543000000000 +file,node=node2 temp=22.6,humidity=44i,alarm=false 1678121543000000000 +file,node=node3 temp=17.9,humidity=56i,alarm=true 1678121543000000000 +``` + +### JSON flat data + +Given the following data: + +```json +{ "node": "node", "temp": 32.3, "humidity": 23, "alarm": false, "time": "1709572232123456789"} +``` + +Here is corresponding parser configuration: + +```toml +[[inputs.file]] +files = ["test.json"] +precision = "1ns" +data_format = "json" + +tag_keys = ["node"] +json_time_key = "time" +json_time_format = "unix_ns" + +``` + +```text +file,node=node temp=32.3,humidity=23 1709572232123456789 +``` + +### JSON Objects + +Given the following data: + +```json +{ + "metrics": [ + { "node": "node1", "temp": 32.3, "humidity": 23, "alarm": "false", "time": "1678121543"}, + { "node": "node2", "temp": 22.6, "humidity": 44, "alarm": "false", "time": "1678121543"}, + { "node": "node3", "temp": 17.9, "humidity": 56, "alarm": "true", "time": "1678121543"} + ] +} +``` + +Here is corresponding parser configuration: + +```toml +[[inputs.file]] +files = ["test.json"] +data_format = "json_v2" + +[[inputs.file.json_v2]] +[[inputs.file.json_v2.object]] + path = "metrics" + timestamp_key = "time" + timestamp_format = "unix" + [[inputs.file.json_v2.object.tag]] + path = "#.node" + [[inputs.file.json_v2.object.field]] + path = "#.temp" + type = "float" + [[inputs.file.json_v2.object.field]] + path = "#.humidity" + type = "int" + [[inputs.file.json_v2.object.field]] + path = "#.alarm" + type = "bool" +``` + +```text +file,node=node1 temp=32.3,humidity=23i,alarm=false 1678121543000000000 +file,node=node2 temp=22.6,humidity=44i,alarm=false 1678121543000000000 +file,node=node3 temp=17.9,humidity=56i,alarm=true 1678121543000000000 +``` + +### JSON Line Protocol + +Given the following data: + +```json +{ + "fields": {"temp": 32.3, "humidity": 23, "alarm": false}, + "name": "measurement", + "tags": {"node": "node1"}, + "time": "2024-03-04T10:10:32.123456Z" +} +``` + +Here is corresponding parser configuration: + +```toml +[[inputs.file]] +files = ["test.json"] +precision = "1us" +data_format = "xpath_json" + +[[inputs.file.xpath]] + metric_name = "/name" + field_selection = "fields/*" + tag_selection = "tags/*" + timestamp = "/time" + timestamp_format = "2006-01-02T15:04:05.999999999Z" +``` + +```text +measurement,node=node1 alarm="false",humidity="23",temp="32.3" 1709547032123456000 +``` diff --git a/docs/PROCESSORS.md b/docs/PROCESSORS.md new file mode 100644 index 0000000..1820026 --- /dev/null +++ b/docs/PROCESSORS.md @@ -0,0 +1,180 @@ +# Processor Plugins + +This section is for developers who want to create a new processor plugin. + +## Processor Plugin Guidelines + +* A processor must conform to the [telegraf.Processor][] interface. +* Processors should call `processors.Add` in their `init` function to register + themselves. See below for a quick example. +* To be available within Telegraf itself, plugins must register themselves + using a file in `github.com/influxdata/telegraf/plugins/processors/all` + named according to the plugin name. Make sure you also add build-tags to + conditionally build the plugin. +* Each plugin requires a file called `sample.conf` containing the sample + configuration for the plugin in TOML format. + Please consult the [Sample Config][] page for the latest style guidelines. +* Each plugin `README.md` file should include the `sample.conf` file in a + section describing the configuration by specifying a `toml` section in the + form `toml @sample.conf`. The specified file(s) are then injected + automatically into the Readme. +* Follow the recommended [Code Style][]. + +[Sample Config]: /docs/developers/SAMPLE_CONFIG.md +[Code Style]: /docs/developers/CODE_STYLE.md +[telegraf.Processor]: https://godoc.org/github.com/influxdata/telegraf#Processor + +## Streaming Processors + +Streaming processors are a new processor type available to you. They are +particularly useful to implement processor types that use background processes +or goroutines to process multiple metrics at the same time. Some examples of +this are the execd processor, which pipes metrics out to an external process +over stdin and reads them back over stdout, and the reverse_dns processor, which +does reverse dns lookups on IP addresses in fields. While both of these come +with a speed cost, it would be significantly worse if you had to process one +metric completely from start to finish before handling the next metric, and thus +they benefit significantly from a streaming-pipe approach. + +Some differences from classic Processors: + +* Streaming processors must conform to the [telegraf.StreamingProcessor][] interface. +* Processors should call `processors.AddStreaming` in their `init` function to register + themselves. See below for a quick example. + +[telegraf.StreamingProcessor]: https://godoc.org/github.com/influxdata/telegraf#StreamingProcessor + +## Processor Plugin Example + +### Registration + +Registration of the plugin on `plugins/processors/all/printer.go`: + +```go +//go:build !custom || processors || processors.printer + +package all + +import _ "github.com/influxdata/telegraf/plugins/processors/printer" // register plugin +``` + +The _build-tags_ in the first line allow to selectively include/exclude your +plugin when customizing Telegraf. + +### Plugin + +Content of your plugin file e.g. `printer.go` + +```go +//go:generate ../../../tools/readme_config_includer/generator +package printer + +import ( + _ "embed" + "fmt" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/processors" +) + +//go:embed sample.conf +var sampleConfig string + +type Printer struct { + Log telegraf.Logger `toml:"-"` +} + +func (*Printer) SampleConfig() string { + return sampleConfig +} + +// Init is for setup, and validating config. +func (p *Printer) Init() error { + return nil +} + +func (p *Printer) Apply(in ...telegraf.Metric) []telegraf.Metric { + for _, metric := range in { + fmt.Println(metric.String()) + } + return in +} + +func init() { + processors.Add("printer", func() telegraf.Processor { + return &Printer{} + }) +} +``` + +## Streaming Processor Example + +```go +//go:generate ../../../tools/readme_config_includer/generator +package printer + +import ( + _ "embed" + "fmt" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/processors" +) + +//go:embed sample.conf +var sampleConfig string + +type Printer struct { + Log telegraf.Logger `toml:"-"` +} + +func (*Printer) SampleConfig() string { + return sampleConfig +} + +// Init is for setup, and validating config. +func (p *Printer) Init() error { + return nil +} + +// Start is called once when the plugin starts; it is only called once per +// plugin instance, and never in parallel. +// Start should return once it is ready to receive metrics. +// The passed in accumulator is the same as the one passed to Add(), so you +// can choose to save it in the plugin, or use the one received from Add(). +func (p *Printer) Start(acc telegraf.Accumulator) error { +} + +// Add is called for each metric to be processed. The Add() function does not +// need to wait for the metric to be processed before returning, and it may +// be acceptable to let background goroutine(s) handle the processing if you +// have slow processing you need to do in parallel. +// Keep in mind Add() should not spawn unbounded goroutines, so you may need +// to use a semaphore or pool of workers (eg: reverse_dns plugin does this). +// Metrics you don't want to pass downstream should have metric.Drop() called, +// rather than simply omitting the acc.AddMetric() call +func (p *Printer) Add(metric telegraf.Metric, acc telegraf.Accumulator) error { + // print! + fmt.Println(metric.String()) + // pass the metric downstream, or metric.Drop() it. + // Metric will be dropped if this function returns an error. + acc.AddMetric(metric) + + return nil +} + +// Stop gives you an opportunity to gracefully shut down the processor. +// Once Stop() is called, Add() will not be called any more. If you are using +// goroutines, you should wait for any in-progress metrics to be processed +// before returning from Stop(). +// When stop returns, you should no longer be writing metrics to the +// accumulator. +func (p *Printer) Stop() error { +} + +func init() { + processors.AddStreaming("printer", func() telegraf.StreamingProcessor { + return &Printer{} + }) +} +``` diff --git a/docs/PROFILING.md b/docs/PROFILING.md new file mode 100644 index 0000000..09c54e8 --- /dev/null +++ b/docs/PROFILING.md @@ -0,0 +1,57 @@ +# Profiling + +Telegraf uses the standard package `net/http/pprof`. This package serves via +its HTTP server runtime profiling data in the format expected by the pprof +visualization tool. + +## Enable profiling + +By default, the profiling is turned off. To enable profiling users need to +specify the pprof address config parameter `pprof-addr`. For example: + +```shell +telegraf --config telegraf.conf --pprof-addr localhost:6060 +``` + +## Profiles + +To view all available profiles, open the URL specified in a browser. For +example, open `http://localhost:6060/debug/pprof/` in your browser. + +To look at the heap profile: + +```shell +go tool pprof http://localhost:6060/debug/pprof/heap +``` + +To look at a 30-second CPU profile: + +```shell +go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30 +``` + +## Generate heap image + +It is very helpful to generate an image to visualize what heap memory is used. +It is best to capture an image a few moments after Telegraf starts and then at +additional periods (e.g. 1min, 5min, etc.). + +A user can capture the image with Go via: + +```shell +go tool pprof -png http://localhost:6060/debug/pprof/heap > heap.png +``` + +The resulting image can be uploaded to a bug report. + +## References + +For additional information on pprof see the following: + +* [net/http/pprof][] +* [Julia Evans: Profiling Go programs with pprof][] +* [Debugging Go Code][] + +[net/http/pprof]: https://pkg.go.dev/net/http/pprof +[julia evans: profiling go programs with pprof]: https://jvns.ca/blog/2017/09/24/profiling-go-with-pprof/ +[Debugging Go Code]: https://www.infoq.com/articles/debugging-go-programs-pprof-trace/ diff --git a/docs/QUICK_START.md b/docs/QUICK_START.md new file mode 100644 index 0000000..191802f --- /dev/null +++ b/docs/QUICK_START.md @@ -0,0 +1,68 @@ +# Quick Start + +The following demos getting started with Telegraf quickly using Docker to +monitor the local system. + +## Install + +This example will use Docker to launch a Telegraf container: + +```shell +docker pull telegraf +``` + +Refer to the [Install Guide][] for the full list of ways to install Telegraf. + +[Install Guide]: /docs/INSTALL_GUIDE.md + +## Configure + +Telegraf requires a configuration to start up. A configuration requires at least +one input to collect data from and one output to send data to. The configuration +file is a [TOML][] file. + +[TOML]: /docs/TOML.md + +```sh +$ cat config.toml +[[inputs.cpu]] +[[inputs.mem]] +[[outputs.file]] +``` + +The above enables two inputs, CPU and Memory, and one output file. The inputs +will collect usage information about the CPU and Memory, while the file output +is used to print the metrics to STDOUT. + +Note that defining plugins to use are a TOML array of tables. This means users +can define a plugin multiple times. This is more useful with other plugins that +may need to connect to different endpoints. + +## Launch + +With the image downloaded and a config file created, launch the image: + +```sh +docker run --rm --volume $PWD/config.toml:/etc/telegraf/telegraf.conf telegraf +``` + +The user will see some initial information print out about which config file was +loaded, version information, and what plugins were loaded. After the initial few +seconds metrics will start to print out. + +## Next steps + +To go beyond this quick start, users should consider the following: + +1. Determine where you want to collect data or metrics from and look at the + available [input plugins][] +2. Determine where you want to send metrics to and look at the available + [output plugins][] +3. Look at the [install guide][] for the complete list of methods to deploy and + install Telegraf +4. If parsing arbitrary data or sending metrics or logs to Telegraf, read + through the [parsing data][] guide. + +[input plugins]: /plugins/inputs +[output plugins]: /plugins/outputs +[parsing data]: /docs/PARSING_DATA.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..0eb7a0a --- /dev/null +++ b/docs/README.md @@ -0,0 +1,89 @@ +# Telegraf Documentation + +* [FAQ][] +* [Install Guide][] +* [Quick Start][] + +## Usage + +* [Commands and Flags][] +* [Configuration][] +* [Docker][] +* [Windows Service][] +* [Releases][] +* [Supported Platforms][] + +## Plugins + +* [Aggregators][] +* [External Plugins][] +* [Inputs][] + * [SQL Drivers Input][] +* [Parsers: Input Data Formats][] +* [Outputs][] +* [Secret Stores][] +* [Serializers: Output Data Formats][] +* [Processors][] + +## Developers + +* [Custom Builds][] +* [Integration Tests][] +* [License of Dependencies][] +* [Nightlies][] +* [Profiling][] + +## Reference + +* [Aggregators & Processors][] +* [AppArmor][] +* [Metrics][] +* [Parsing Data][] +* [Template Pattern][] +* [TOML][] +* [TLS][] + +## Blog Posts + +* [Common Expression Language][] +* [Config Recommendations and Performance Monitoring][] +* [Deploying Telegraf via Docker Compose][] +* [Reduce Binary Size][] +* [Storing Secrets][] + +[Aggregators & Processors]: /docs/AGGREGATORS_AND_PROCESSORS.md +[Aggregators]: /docs/AGGREGATORS.md +[AppArmor]: /docs/APPARMOR.md +[Commands and Flags]: /docs/COMMANDS_AND_FLAGS.md +[Configuration]: /docs/CONFIGURATION.md +[Custom Builds]: /docs/CUSTOMIZATION.md +[Parsers: Input Data Formats]: /docs/DATA_FORMATS_INPUT.md +[Serializers: Output Data Formats]: /docs/DATA_FORMATS_OUTPUT.md +[Docker]: /docs/DOCKER.md +[External Plugins]: /docs/EXTERNAL_PLUGINS.md +[FAQ]: /docs/FAQ.md +[Inputs]: /docs/INPUTS.md +[Install Guide]: /docs/INSTALL_GUIDE.md +[Integration Tests]: /docs/INTEGRATION_TESTS.md +[License of Dependencies]: /docs/LICENSE_OF_DEPENDENCIES.md +[Metrics]: /docs/METRICS.md +[Nightlies]: /docs/NIGHTLIES.md +[Outputs]: /docs/OUTPUTS.md +[Parsing Data]: /docs/PARSING_DATA.md +[Processors]: /docs/PROCESSORS.md +[Profiling]: /docs/PROFILING.md +[Quick Start]: /docs/QUICK_START.md +[Releases]: /docs/RELEASES.md +[Secret Stores]: /docs/SECRETSTORES.md +[SQL Drivers Input]: /docs/SQL_DRIVERS_INPUT.md +[Supported Platforms]: /docs/SUPPORTED_PLATFORMS.md +[Template Pattern]: /docs/TEMPLATE_PATTERN.md +[TLS]: /docs/TLS.md +[TOML]: /docs/TOML.md +[Windows Service]: /docs/WINDOWS_SERVICE.md + +[Config Recommendations and Performance Monitoring]: https://www.influxdata.com/blog/telegraf-best-practices/ +[Deploying Telegraf via Docker Compose]: https://www.influxdata.com/blog/telegraf-deployment-strategies-docker-compose/ +[Common Expression Language]: https://www.influxdata.com/blog/using-common-expression-language-metric-filtering-telegraf/ +[Storing Secrets]: https://www.influxdata.com/blog/storing-secrets-telegraf/ +[Reduce Binary Size]: https://www.influxdata.com/blog/how-reduce-telegraf-binary-size/ diff --git a/docs/RELEASES.md b/docs/RELEASES.md new file mode 100644 index 0000000..233cb2a --- /dev/null +++ b/docs/RELEASES.md @@ -0,0 +1,23 @@ +# Releases + +Telegraf has four minor releases a year in March, June, September, and +December. In between each of those minor releases, there are 2-4 bug fix +releases that happen every 3 weeks. + +This [Google Calendar][] is kept up to date for upcoming release dates. +Additionally, users can look at the [GitHub milestones][] for the next minor +and bug fix releases. + +## Versioning + +Telegraf uses semantic versioning. + +## Minor vs Patch Release + +PRs that resolve issues are released in the next release. PRs that introduce +new features are held for the next minor release. Users can view what +[GitHub milestones][] a PR belongs to when they want to determine the release +it will go out with. + +[Google Calendar]: https://calendar.google.com/calendar/embed?src=c_03d981cefd8d6432894cb162da5c6186e393bc0f970ca6c371201aa05d30d763%40group.calendar.google.com +[GitHub milestones]: https://github.com/influxdata/telegraf/milestones diff --git a/docs/SECRETSTORES.md b/docs/SECRETSTORES.md new file mode 100644 index 0000000..7c66b1a --- /dev/null +++ b/docs/SECRETSTORES.md @@ -0,0 +1,115 @@ +# Secret Store Plugins + +This section is for developers who want to create a new secret store plugin. + +## Secret Store Plugin Guidelines + +* A secret store must conform to the [telegraf.SecretStore][] interface. +* Secret-stores should call `secretstores.Add` in their `init` function to register + themselves. See below for a quick example. +* To be available within Telegraf itself, plugins must register themselves + using a file in `github.com/influxdata/telegraf/plugins/secretstores/all` + named according to the plugin name. Make sure you also add build-tags to + conditionally build the plugin. +* Each plugin requires a file called `sample.conf` containing the sample + configuration for the plugin in TOML format. Please consult the + [Sample Config][] page for the latest style guidelines. +* Each plugin `README.md` file should include the `sample.conf` file in a + section describing the configuration by specifying a `toml` section in the + form `toml @sample.conf`. The specified file(s) are then injected + automatically into the Readme. +* Follow the recommended [Code Style][]. + +[telegraf.SecretStore]: https://pkg.go.dev/github.com/influxdata/telegraf?utm_source=godoc#SecretStore +[Sample Config]: https://github.com/influxdata/telegraf/blob/master/docs/developers/SAMPLE_CONFIG.md +[Code Style]: https://github.com/influxdata/telegraf/blob/master/docs/developers/CODE_STYLE.md + +## Secret Store Plugin Example + +### Registration + +Registration of the plugin on `plugins/secretstores/all/printer.go`: + +```go +//go:build !custom || secretstores || secretstores.printer + +package all + +import _ "github.com/influxdata/telegraf/plugins/secretstores/printer" // register plugin +``` + +The _build-tags_ in the first line allow to selectively include/exclude your +plugin when customizing Telegraf. + +### Plugin + +```go +//go:generate ../../../tools/readme_config_includer/generator +package main + +import ( + _ "embed" + "errors" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/secretstores" +) + +//go:embed sample.conf +var sampleConfig string + +type Printer struct { + Log telegraf.Logger `toml:"-"` + + cache map[string]string +} + +func (p *Printer) SampleConfig() string { + return sampleConfig +} + +func (p *Printer) Init() error { + return nil +} + +// Get searches for the given key and return the secret +func (p *Printer) Get(key string) ([]byte, error) { + v, found := p.cache[key] + if !found { + return nil, errors.New("not found") + } + + return []byte(v), nil +} + +// Set sets the given secret for the given key +func (p *Printer) Set(key, value string) error { + p.cache[key] = value + return nil +} + +// List lists all known secret keys +func (p *Printer) List() ([]string, error) { + keys := make([]string, 0, len(p.cache)) + for k := range p.cache { + keys = append(keys, k) + } + return keys, nil +} + +// GetResolver returns a function to resolve the given key. +func (p *Printer) GetResolver(key string) (telegraf.ResolveFunc, error) { + resolver := func() ([]byte, bool, error) { + s, err := p.Get(key) + return s, false, err + } + return resolver, nil +} + +// Register the secret-store on load. +func init() { + secretstores.Add("printer", func(string) telegraf.SecretStore { + return &Printer{} + }) +} +``` diff --git a/docs/SQL_DRIVERS_INPUT.md b/docs/SQL_DRIVERS_INPUT.md new file mode 100644 index 0000000..458c6a0 --- /dev/null +++ b/docs/SQL_DRIVERS_INPUT.md @@ -0,0 +1,55 @@ +# Available SQL drivers for the SQL input plugin + +This is a list of available drivers for the SQL input plugin. The data-source-name (DSN) is driver specific and +might change between versions. Please check the driver documentation for available options and the format. + +| database | driver | aliases | example DSN | comment | +| -------------------- | --------------------------------------------------------- | --------------- |------------------------------------------------------------------------------------------------------------------| --------------------------------------------------------------------------------------------------------------------- | +| ClickHouse | [clickhouse](https://github.com/ClickHouse/clickhouse-go) | | `tcp://host:port[?param1=value&...¶mN=value]"` | see [clickhouse-go docs](https://github.com/ClickHouse/clickhouse-go#dsn) for more information | +| CockroachDB | [cockroach](https://github.com/jackc/pgx) | postgres or pgx | see _postgres_ driver | uses PostgresQL driver | +| FlightSQL | [flightsql](https://github.com/apache/arrow/tree/main/go/arrow/flight/flightsql/driver) | | `flightsql://[username[:password]@]host:port?timeout=10s[&token=TOKEN][¶m1=value1&...¶mN=valueN]` | see [driver docs](https://github.com/apache/arrow/blob/main/go/arrow/flight/flightsql/driver/README.md) for more information | +| IBM Netezza | [nzgo](https://github.com/IBM/nzgo) | | `host=your_nz_host port=5480 user=your_nz_user password=your_nz_password dbname=your_nz_db_name sslmode=disable` | see [driver docs](https://pkg.go.dev/github.com/IBM/nzgo/v12) for more | +| MariaDB | [maria](https://github.com/go-sql-driver/mysql) | mysql | see _mysql_ driver | uses MySQL driver | +| Microsoft SQL Server | [sqlserver](https://github.com/microsoft/go-mssqldb) | mssql | `sqlserver://username:password@host/instance?param1=value¶m2=value` | uses newer _sqlserver_ driver | +| MySQL | [mysql](https://github.com/go-sql-driver/mysql) | | `[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN]` | see [driver docs](https://github.com/go-sql-driver/mysql) for more information | +| Oracle | [oracle](https://github.com/sijms/go-ora) | oracle | `oracle://username:password@host:port/service?param1=value¶m2=value` | see [driver docs](https://github.com/sijms/go-ora/blob/master/README.md) for more information | +| PostgreSQL | [postgres](https://github.com/jackc/pgx) | pgx | `postgresql://[user[:password]@][netloc][:port][,...][/dbname][?param1=value1&...]` | see [postgres docs](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING) for more information | +| SAP HANA | [go-hdb](https://github.com/SAP/go-hdb) | hana | `hdb://user:password@host:port` | see [driver docs](https://github.com/SAP/go-hdb) for more information | +| SQLite | [sqlite](https://gitlab.com/cznic/sqlite) | | `filename` | see [driver docs](https://pkg.go.dev/modernc.org/sqlite) for more information | +| TiDB | [tidb](https://github.com/go-sql-driver/mysql) | mysql | see _mysql_ driver | uses MySQL driver | + +## Comments + +### Driver aliases + +Some database drivers are supported though another driver (e.g. CockroachDB). For other databases we provide a more +obvious name (e.g. postgres) compared to the driver name. For all of those drivers you might use an _alias_ name +during configuration. + +### Example data-source-name DSN + +The given examples are just that, so please check the driver documentation for the exact format +and available options and parameters. Please note that the format of a DSN might also change +between driver version. + +### Type conversions + +Telegraf relies on type conversion of the database driver and/or the golang sql framework. In case you find +any problem, please open an issue! + +## Help + +If nothing seems to work, you might find help in the telegraf forum or in the chat. + +### The documentation is wrong + +Please open an issue or even better send a pull-request! + +### I found a bug + +Please open an issue or even better send a pull-request! + +### My database is not supported + +We currently cannot support CGO drivers in telegraf! Please check if a **pure Go** driver for the [golang sql framework](https://golang.org/pkg/database/sql/) exists. +If you found such a driver, please let us know by opening an issue or even better by sending a pull-request! diff --git a/docs/SUPPORTED_PLATFORMS.md b/docs/SUPPORTED_PLATFORMS.md new file mode 100644 index 0000000..7d518b6 --- /dev/null +++ b/docs/SUPPORTED_PLATFORMS.md @@ -0,0 +1,60 @@ +# Supported Platforms + +This doc helps define the platform support for Telegraf. See the +[install guide][] for specific options for installing Telegraf. + +Bug reports should be submitted only for supported platforms that are under +general support, not extended or paid support. In general, Telegraf supports +Linux, macOS, Microsoft Windows, and FreeBSD. + +Telegraf is written in Go, which supports many operating systems. Golang.org +has a [table][go-table] of valid OS and architecture combinations and the Go +Wiki has more specific [minimum requirements][go-reqs] for Go itself. Telegraf +may work and produce builds for other operating systems and users are welcome to +build their own binaries for them. Again, bug reports must be made on a +supported platform. + +[install guide]: /docs/INSTALL_GUIDE.md +[go-table]: https://golang.org/doc/install/source#environment +[go-reqs]: https://github.com/golang/go/wiki/MinimumRequirements#operating-systems + +## FreeBSD + +Telegraf supports releases under FreeBSD security support. See the +[FreeBSD security page][] for specific versions. + +[FreeBSD security page]: https://www.freebsd.org/security/#sup + +## Linux + +Telegraf will support the latest generally supported versions of major linux +distributions. This does not include extended supported releases where customers +can pay for additional support. + +Below are some of the major distributions and the intent to support: + +* [Debian][]: Releases supported by security and release teams +* [Fedora][]: Releases currently supported by Fedora team +* [Red Hat Enterprise Linux][]: Releases under full support +* [Ubuntu][]: Releases, interim and LTS, releases in standard support + +[Debian]: https://wiki.debian.org/LTS +[Fedora]: https://fedoraproject.org/wiki/Releases +[Red Hat Enterprise Linux]: https://access.redhat.com/support/policy/updates/errata#Life_Cycle_Dates +[Ubuntu]: https://ubuntu.com/about/release-cycle + +## macOS + +Telegraf supports releases supported by Apple. Release history is available from +[wikipedia][wp-macos]. + +[wp-macos]: https://endoflife.date/macos + +## Microsoft Windows + +Telegraf intends to support current versions of [Windows][] and +[Windows Server][]. The release must be under mainstream or generally supported +and not under any paid or extended security support. + +[Windows]: https://learn.microsoft.com/en-us/lifecycle/faq/windows +[Windows Server]: https://learn.microsoft.com/en-us/windows-server/get-started/windows-server-release-info diff --git a/docs/TEMPLATE_PATTERN.md b/docs/TEMPLATE_PATTERN.md new file mode 100644 index 0000000..74443a2 --- /dev/null +++ b/docs/TEMPLATE_PATTERN.md @@ -0,0 +1,137 @@ +# Template Patterns + +Template patterns are a mini language that describes how a dot delimited +string should be mapped to and from [metrics][]. + +A template has the form: + +```text +"host.mytag.mytag.measurement.measurement.field*" +``` + +Where the following keywords can be set: + +1. `measurement`: specifies that this section of the graphite bucket corresponds +to the measurement name. This can be specified multiple times. +2. `field`: specifies that this section of the graphite bucket corresponds +to the field name. This can be specified multiple times. +3. `measurement*`: specifies that all remaining elements of the graphite bucket +correspond to the measurement name. +4. `field*`: specifies that all remaining elements of the graphite bucket +correspond to the field name. + +Any part of the template that is not a keyword is treated as a tag key. This +can also be specified multiple times. + +**NOTE:** `measurement` must be specified in your template. +**NOTE:** `field*` cannot be used in conjunction with `measurement*`. + +## Examples + +### Measurement & Tag Templates + +The most basic template is to specify a single transformation to apply to all +incoming metrics. So the following template: + +```toml +templates = [ + "region.region.measurement*" +] +``` + +would result in the following Graphite -> Telegraf transformation. + +```text +us.west.cpu.load 100 +=> cpu.load,region=us.west value=100 +``` + +Multiple templates can also be specified, but these should be differentiated +using _filters_ (see below for more details) + +```toml +templates = [ + "*.*.* region.region.measurement", # <- all 3-part measurements will match this one. + "*.*.*.* region.region.host.measurement", # <- all 4-part measurements will match this one. +] +``` + +### Field Templates + +The field keyword tells Telegraf to give the metric that field name. +So the following template: + +```toml +separator = "_" +templates = [ + "measurement.measurement.field.field.region" +] +``` + +would result in the following Graphite -> Telegraf transformation. + +```text +cpu.usage.idle.percent.eu-east 100 +=> cpu_usage,region=eu-east idle_percent=100 +``` + +The field key can also be derived from all remaining elements of the graphite +bucket by specifying `field*`: + +```toml +separator = "_" +templates = [ + "measurement.measurement.region.field*" +] +``` + +which would result in the following Graphite -> Telegraf transformation. + +```text +cpu.usage.eu-east.idle.percentage 100 +=> cpu_usage,region=eu-east idle_percentage=100 +``` + +### Filter Templates + +Users can also filter the template(s) to use based on the name of the bucket, +using glob matching, like so: + +```toml +templates = [ + "cpu.* measurement.measurement.region", + "mem.* measurement.measurement.host" +] +``` + +which would result in the following transformation: + +```text +cpu.load.eu-east 100 +=> cpu_load,region=eu-east value=100 + +mem.cached.localhost 256 +=> mem_cached,host=localhost value=256 +``` + +### Adding Tags + +Additional tags can be added to a metric that don't exist on the received metric. +You can add additional tags by specifying them after the pattern. +Tags have the same format as the line protocol. +Multiple tags are separated by commas. + +```toml +templates = [ + "measurement.measurement.field.region datacenter=1a" +] +``` + +would result in the following Graphite -> Telegraf transformation. + +```text +cpu.usage.idle.eu-east 100 +=> cpu_usage,region=eu-east,datacenter=1a idle=100 +``` + +[metrics]: /docs/METRICS.md diff --git a/docs/TLS.md b/docs/TLS.md new file mode 100644 index 0000000..ec147a8 --- /dev/null +++ b/docs/TLS.md @@ -0,0 +1,126 @@ +# Transport Layer Security + +There is an ongoing effort to standardize TLS options across plugins. When +possible, plugins will provide the standard settings described below. With the +exception of the advanced configuration available TLS settings will be +documented in the sample configuration. + +## Client Configuration + +For client TLS support we have the following options: + +```toml +## Enable/disable TLS +## Set to true/false to enforce TLS being enabled/disabled. If not set, +## enable TLS only if any of the other options are specified. +# tls_enable = + +## Root certificates for verifying server certificates encoded in PEM format. +# tls_ca = "/etc/telegraf/ca.pem" + +## The public and private key pairs for the client encoded in PEM format. May +## contain intermediate certificates. +# tls_cert = "/etc/telegraf/cert.pem" +# tls_key = "/etc/telegraf/key.pem" +# passphrase for encrypted private key, if it is in PKCS#8 format. Encrypted PKCS#1 private keys are not supported. +# tls_key_pwd = "changeme" +## Skip TLS verification. +# insecure_skip_verify = false +## Send the specified TLS server name via SNI. +# tls_server_name = "foo.example.com" +# +``` + +### Server Configuration + +The server TLS configuration provides support for TLS mutual authentication: + +```toml +## Set one or more allowed client CA certificate file names to +## enable mutually authenticated TLS connections. +# tls_allowed_cacerts = ["/etc/telegraf/clientca.pem"] + +## Set one or more allowed DNS name to enable a whitelist +## to verify incoming client certificates. +## It will go through all available SAN in the certificate, +## if of them matches the request is accepted. +# tls_allowed_dns_names = ["client.example.org"] + +## Add service certificate and key. +# tls_cert = "/etc/telegraf/cert.pem" +# tls_key = "/etc/telegraf/key.pem" +# passphrase for encrypted private key, if it is in PKCS#8 format. Encrypted PKCS#1 private keys are not supported. +# tls_key_pwd = "changeme" +``` + +#### Advanced Configuration + +For plugins using the standard server configuration you can also set several +advanced settings. These options are not included in the sample configuration +for the interest of brevity. + +```toml +## Define list of allowed ciphers suites. If not defined the default ciphers +## supported by Go will be used. +## ex: tls_cipher_suites = [ +## "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", +## "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", +## "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", +## "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", +## "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", +## "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", +## "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", +## "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", +## "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", +## "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", +## "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", +## "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", +## "TLS_RSA_WITH_AES_128_GCM_SHA256", +## "TLS_RSA_WITH_AES_256_GCM_SHA384", +## "TLS_RSA_WITH_AES_128_CBC_SHA256", +## "TLS_RSA_WITH_AES_128_CBC_SHA", +## "TLS_RSA_WITH_AES_256_CBC_SHA" +## ] +# tls_cipher_suites = [] + +## Minimum TLS version that is acceptable. +# tls_min_version = "TLS10" + +## Maximum SSL/TLS version that is acceptable. +# tls_max_version = "TLS13" +``` + +Cipher suites for use with `tls_cipher_suites`: + +- `TLS_RSA_WITH_RC4_128_SHA` +- `TLS_RSA_WITH_3DES_EDE_CBC_SHA` +- `TLS_RSA_WITH_AES_128_CBC_SHA` +- `TLS_RSA_WITH_AES_256_CBC_SHA` +- `TLS_RSA_WITH_AES_128_CBC_SHA256` +- `TLS_RSA_WITH_AES_128_GCM_SHA256` +- `TLS_RSA_WITH_AES_256_GCM_SHA384` +- `TLS_ECDHE_ECDSA_WITH_RC4_128_SHA` +- `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA` +- `TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA` +- `TLS_ECDHE_RSA_WITH_RC4_128_SHA` +- `TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA` +- `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA` +- `TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA` +- `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256` +- `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256` +- `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` +- `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256` +- `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384` +- `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384` +- `TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305` +- `TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305` +- `TLS_AES_128_GCM_SHA256` +- `TLS_AES_256_GCM_SHA384` +- `TLS_CHACHA20_POLY1305_SHA256` + +TLS versions for use with `tls_min_version` or `tls_max_version`: + +- `TLS10` +- `TLS11` +- `TLS12` +- `TLS13` diff --git a/docs/TOML.md b/docs/TOML.md new file mode 100644 index 0000000..d8de9f2 --- /dev/null +++ b/docs/TOML.md @@ -0,0 +1,100 @@ +# TOML + +Telegraf uses TOML as the configuration language. The following outlines a few +common questions and issues that cause questions or confusion. + +## Reference and Validator + +For all things TOML related, please consult the [TOML Spec][] and consider +using a TOML validator. In VSCode the [Even Better TOML][] extension or use the +[TOML Lint][] website to validate your TOML config. + +[TOML Spec]: https://toml.io/en/v1.0.0 +[Even Better TOML]: https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml +[TOML Lint]: https://www.toml-lint.com/ + +## Multiple TOML Files + +TOML technically does not support multiple files, this is done as a convenience for +users. + +Users should be aware that when Telegraf reads a user's config, if multiple +files or directories are read in, each file at a time and all +settings are combined as if it were one big file. + +## Single Table vs Array of Tables + +Telegraf uses a single agent table (e.g. `[agent]`) to control high-level agent +specific configurations. This section can only be defined once for all config +files and should be in the first file read in to take effect. This cannot be +defined per-config file. + +Telegraf also uses array of tables (e.g. `[[inputs.file]]`) to define multiple +plugins. These can be specified as many times as a user wishes. + +## In-line Table vs Table + +In some cases, a configuration option for a plugin may define a table of +configuration options. Take for example, the ability to add arbitrary tags to +an input plugin: + +```toml +[[inputs.cpu]] + percpu = false + totalcpu = true + [inputs.cpu.tags] + tag1 = "foo" + tag2 = "bar" +``` + +User's should understand that these tables *must* be at the end of the plugin +definition, because any key-value pair is assumed to be part of that table. The +following demonstrates how this can cause confusion: + +```toml +[[inputs.cpu]] + totalcpu = true + [inputs.cpu.tags] + tag1 = "foo" + tag2 = "bar" + percpu = false # this is treated as a tag to add, not a config option +``` + +Note TOML does not care about how a user indents the config or whitespace, so +the `percpu` option is considered a tag. + +A far better approach to avoid this situation is to use inline table syntax: + +```toml +[[inputs.cpu]] + tags = {tag1 = "foo", tag2 = "bar"} + percpu = false + totalcpu = true +``` + +This way the tags value can go anywhere in the config and avoids possible +confusion. + +## Basic String vs String Literal + +In basic strings, signified by double-quotes, certain characters like the +backslash and double quote contained in a basic string need to be escaped for +the string to be valid. + +For example the following invalid TOML, includes a Windows path with +unescaped backslashes: + +```toml +path = "C:\Program Files\" # this is invalid TOML +``` + +User's can either escape the backslashes or use a literal string, which is +signified by single-quotes: + +```toml +path = "C:\\Program Files\\" +path = 'C:\Program Files\' +``` + +Literal strings return exactly what you type. As there is no escaping in literal +strings you cannot have an apostrophe in a literal string. diff --git a/docs/WINDOWS_SERVICE.md b/docs/WINDOWS_SERVICE.md new file mode 100644 index 0000000..8e2c091 --- /dev/null +++ b/docs/WINDOWS_SERVICE.md @@ -0,0 +1,129 @@ +# Running Telegraf as a Windows Service + +Telegraf natively supports running as a Windows Service. Outlined below is are +the general steps to set it up. + +1. Obtain the telegraf windows distribution +2. Create the directory `C:\Program Files\Telegraf` or use a custom directory + if desired +3. Place the telegraf.exe and the telegraf.conf config file into the directory, + either `C:\Program Files\Telegraf` or the custom directory of your choice. + If you install in a different location simply specify the `--config` + parameter with the desired location. +4. To install the service into the Windows Service Manager, run the command + as administrator. Make sure to wrap parameters containing spaces in double + quotes: + + ```shell + > "C:\Program Files\Telegraf\telegraf.exe" service install + ``` + +5. Edit the configuration file to meet your needs +6. To check that it works, run: + + ```shell + > "C:\Program Files\Telegraf\telegraf.exe" --config "C:\Program Files\Telegraf\telegraf.conf" --test + ``` + +7. To start collecting data, run: + + ```shell + > net start telegraf + ``` + + or + + ```shell + > "C:\Program Files\Telegraf\telegraf.exe" service start + ``` + + or use the Windows service manager to start the service + +Please also check the Windows event log or your configured log-file for errors +during startup. + +## Config Directory + +You can also specify a `--config-directory` for the service to use: + +1. Create a directory for config snippets: `C:\Program Files\Telegraf\telegraf.d` +2. Include the `--config-directory` option when registering the service: + + ```shell + > "C:\Program Files\Telegraf\telegraf.exe" --config C:\"Program Files"\Telegraf\telegraf.conf --config-directory C:\"Program Files"\Telegraf\telegraf.d service install + ``` + +## Other supported operations + +Telegraf can manage its own service through the --service flag: + +| Command | Effect | +|----------------------------------|------------------------------------------| +| `telegraf.exe service install` | Install telegraf as a service | +| `telegraf.exe service uninstall` | Remove the telegraf service | +| `telegraf.exe service start` | Start the telegraf service | +| `telegraf.exe service stop` | Stop the telegraf service | +| `telegraf.exe service status` | Query the status of the telegraf service | + +## Install multiple services + +Running multiple instances of Telegraf is seldom needed, as you can run +multiple instances of each plugin and route metric flow using the metric +filtering options. However, if you do need to run multiple telegraf instances +on a single system, you can install the service with the `--service-name` and +`--display-name` flags to give the services unique names: + +```shell +> "C:\Program Files\Telegraf\telegraf.exe" --service-name telegraf-1 service install --display-name "Telegraf 1" +> "C:\Program Files\Telegraf\telegraf.exe" --service-name telegraf-2 service install --display-name "Telegraf 2" +``` + +## Auto restart and restart delay + +By default the service will not automatically restart on failure. Providing the +`--auto-restart` flag during installation will always restart the service with +a default delay of 5 minutes. To modify this to for example 3 minutes, +additionally provide `--restart-delay 3m` flag. The delay can be any valid +`time.Duration` string. + +## Troubleshooting + +When Telegraf runs as a Windows service, Telegraf logs all messages concerning +the service startup to the Windows event log. All messages and errors occuring +during runtime will be logged to the log-target you configured. +Check the event log for errors reported by the `telegraf` service (or the +service-name you configured) during service startup: +`Event Viewer -> Windows Logs -> Application` + +### Common error #1067 + +When installing as service in Windows, always double check to specify full path +of the config file, otherwise windows service will fail to start. Use + +```shell +> "C:\Program Files\Telegraf\telegraf.exe" --config "C:\MyConfigs\telegraf.conf" service install +``` + +instead of + +```shell +> "C:\Program Files\Telegraf\telegraf.exe" --config "telegraf.conf" service install +``` + +### Service is killed during shutdown + +When shuting down Windows the Telegraf service tries to cleanly stop when +receiving the corresponding notification from the Windows service manager. The +exit process involves stopping all inputs, processors and aggregators and +finally to flush all remaining metrics to the output(s). In case many metrics +are not yet flushed this final step might take some time. However, Windows will +kill the service and the corresponding process after a predefined timeout +(usually 5 seconds). + +You can change that timeout in the registry under + +````text +HKLM\SYSTEM\CurrentControlSet\Control\WaitToKillServiceTimeout +``` + +**NOTE:** The value is in milliseconds and applies to **all** services! diff --git a/docs/developers/CODE_STYLE.md b/docs/developers/CODE_STYLE.md new file mode 100644 index 0000000..61485aa --- /dev/null +++ b/docs/developers/CODE_STYLE.md @@ -0,0 +1,8 @@ +# Code Style + +Code is required to be formatted using `gofmt`, this covers most code style +requirements. It is also highly recommended to use `goimports` to +automatically order imports. + +Please try to keep lines length under 80 characters, the exact number of +characters is not strict but it generally helps with readability. diff --git a/docs/developers/DEBUG.md b/docs/developers/DEBUG.md new file mode 100644 index 0000000..2434841 --- /dev/null +++ b/docs/developers/DEBUG.md @@ -0,0 +1,84 @@ +# Debug + +The following describes how to use the [delve][1] debugger with telegraf +during development. Delve has many, very well documented [subcommands][2] and +options. + +[1]: https://github.com/go-delve/delve +[2]: https://github.com/go-delve/delve/blob/master/Documentation/usage/README.md + +## CLI + +To run telegraf manually, users can run: + +```bash +go run ./cmd/telegraf --config config.toml +``` + +To attach delve with a similar config users can run the following. Note the +additional `--` to specify flags passed to telegraf. Additional flags need to +go after this double dash: + +```bash +$ dlv debug ./cmd/telegraf -- --config config.toml +Type 'help' for list of commands. +(dlv) +``` + +At this point a user could set breakpoints and continue execution. + +## Visual Studio Code + +Visual Studio Code's [go language extension][20] includes the ability to easily +make use of [delve for debugging][21]. Check out this [full tutorial][22] from +the go extension's wiki. + +A basic config is all that is required along with additional arguments to tell +Telegraf where the config is located: + +```json +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileDirname}", + "args": ["--config", "/path/to/config"] + } + ] +} +``` + +[20]: https://code.visualstudio.com/docs/languages/go +[21]: https://code.visualstudio.com/docs/languages/go#_debugging +[22]: https://github.com/golang/vscode-go/wiki/debugging + +## GoLand + +JetBrains' [GoLand][30] also includes full featured [debugging][31] options. + +The following is an example debug config to run Telegraf with a config: + +```xml + + + + + + + + + + + + +``` + +[30]: https://www.jetbrains.com/go/ +[31]: https://www.jetbrains.com/help/go/debugging-code.html diff --git a/docs/developers/DEPRECATION.md b/docs/developers/DEPRECATION.md new file mode 100644 index 0000000..ea4abd3 --- /dev/null +++ b/docs/developers/DEPRECATION.md @@ -0,0 +1,93 @@ +# Deprecation + +Deprecation is the primary tool for making changes in Telegraf. A deprecation +indicates that the community should move away from using a feature, and +documents that the feature will be removed in the next major update (2.0). + +Key to deprecation is that the feature remains in Telegraf and the behavior is +not changed. + +We do not have a strict definition of a breaking change. All code changes +change behavior, the decision to deprecate or make the change immediately is +decided based on the impact. + +## Deprecate plugins + +Add an entry to the plugins deprecation list (e.g. in `plugins/inputs/deprecations.go`). Include the deprecation version +and any replacement, e.g. + +```golang + "logparser": { + Since: "1.15.0", + Notice: "use 'inputs.tail' with 'grok' data format instead", + }, +``` + +The entry can contain an optional `RemovalIn` field specifying the planned version for removal of the plugin. + +Also add the deprecation warning to the plugin's README: + +```markdown +# Logparser Input Plugin + +### **Deprecated in 1.10**: Please use the [tail][] plugin along with the +`grok` [data format][]. + +[tail]: /plugins/inputs/tail/README.md +[data formats]: /docs/DATA_FORMATS_INPUT.md +``` + +Telegraf will automatically check if a deprecated plugin is configured and print a warning + +```text +2022-01-26T20:08:15Z W! DeprecationWarning: Plugin "inputs.logparser" deprecated since version 1.15.0 and will be removed in 2.0.0: use 'inputs.tail' with 'grok' data format instead +``` + +## Deprecate options + +Mark the option as deprecated in the sample config, include the deprecation +version and any replacement. + +```toml + ## Broker to publish to. + ## deprecated in 1.7; use the brokers option + # url = "amqp://localhost:5672/influxdb" +``` + +In the plugins configuration struct, add a `deprecated` tag to the option: + +```go +type AMQP struct { + URL string `toml:"url" deprecated:"1.7.0;use 'brokers' instead"` + Precision string `toml:"precision" deprecated:"1.2.0;option is ignored"` +} +``` + +The `deprecated` tag has the format `[;removal version];` where the `removal version` is optional. The specified deprecation info will automatically displayed by Telegraf if the option is used in the config + +```text +2022-01-26T20:08:15Z W! DeprecationWarning: Option "url" of plugin "outputs.amqp" deprecated since version 1.7.0 and will be removed in 2.0.0: use 'brokers' instead +``` + +### Option value + +In the case a specific option value is being deprecated, the method `models.PrintOptionValueDeprecationNotice` needs to be called in the plugin's `Init` method. + +## Deprecate metrics + +In the README document the metric as deprecated. If there is a replacement field, +tag, or measurement then mention it. + +```markdown +- system + - fields: + - uptime_format (string, deprecated in 1.10: use `uptime` field) +``` + +Add filtering to the sample config, leave it commented out. + +```toml +[[inputs.system]] + ## Uncomment to remove deprecated metrics. + # fieldexclude = ["uptime_format"] +``` diff --git a/docs/developers/LOGGING.md b/docs/developers/LOGGING.md new file mode 100644 index 0000000..e009968 --- /dev/null +++ b/docs/developers/LOGGING.md @@ -0,0 +1,79 @@ +# Logging + +## Plugin Logging + +You can access the Logger for a plugin by defining a field named `Log`. This +`Logger` is configured internally with the plugin name and alias so they do not +need to be specified for each log call. + +```go +type MyPlugin struct { + Log telegraf.Logger `toml:"-"` +} +``` + +You can then use this Logger in the plugin. Use the method corresponding to +the log level of the message. + +```go +p.Log.Errorf("Unable to write to file: %v", err) +``` + +## Agent Logging + +In other sections of the code it is required to add the log level and module +manually: + +```go +log.Printf("E! [agent] Error writing to %s: %v", output.LogName(), err) +``` + +## When to Log + +Log a message if an error occurs but the plugin can continue working. For +example if the plugin handles several servers and only one of them has a fatal +error, it can be logged as an error. + +Use logging judiciously for debug purposes. Since Telegraf does not currently +support setting the log level on a per module basis, it is especially important +to not over do it with debug logging. + +If the plugin is listening on a socket, log a message with the address of the socket: + +```go +p.log.InfoF("Listening on %s://%s", protocol, l.Addr()) +``` + +## When not to Log + +Don't use logging to emit performance data or other meta data about the plugin, +instead use the `internal` plugin and the `selfstats` package. + +Don't log fatal errors in the plugin that require the plugin to return, instead +return them from the function and Telegraf will handle the logging. + +Don't log for static configuration errors, check for them in a plugin `Init()` +function and return an error there. + +Don't log a warning every time a plugin is called for situations that are +normal on some systems. + +## Log Level + +The log level is indicated by a single character at the start of the log +message. Adding this prefix is not required when using the Plugin Logger. + +- `D!` Debug +- `I!` Info +- `W!` Warning +- `E!` Error + +## Style + +Log messages should be capitalized and be a single line. + +If it includes data received from another system or process, such as the text +of an error message, the text should be quoted with `%q`. + +Use the `%v` format for the Go error type instead of `%s` to ensure a nil error +is printed. diff --git a/docs/developers/METRIC_FORMAT_CHANGES.md b/docs/developers/METRIC_FORMAT_CHANGES.md new file mode 100644 index 0000000..7d6477c --- /dev/null +++ b/docs/developers/METRIC_FORMAT_CHANGES.md @@ -0,0 +1,49 @@ +# Metric Format Changes + +When making changes to an existing input plugin, care must be taken not to change the metric format in ways that will cause trouble for existing users. This document helps developers understand how to make metric format changes safely. + +## Changes can cause incompatibilities + +If the metric format changes, data collected in the new format can be incompatible with data in the old format. Database queries designed around the old format may not work with the new format. This can cause application failures. + +Some metric format changes don't cause incompatibilities. Also, some unsafe changes are necessary. How do you know what changes are safe and what to do if your change isn't safe? + +## Guidelines + +The main guideline is just to keep compatibility in mind when making changes. Often developers are focused on making a change that fixes their particular problem and they forget that many people use the existing code and will upgrade. When you're coding, keep existing users and applications in mind. + +### Renaming, removing, reusing + +Database queries refer to the metric and its tags and fields by name. Any Telegraf code change that changes those names has the potential to break an existing query. Similarly, removing tags or fields can break queries. + +Changing the meaning of an existing tag value or field value or reusing an existing one in a new way isn't safe. Although queries that use these tags/field may not break, they will not work as they did before the change. + +Adding a field doesn't break existing queries. Queries that select all fields and/or tags (like "select * from") will return an extra series but this is often useful. + +### Performance and storage + +Time series databases can store large amounts of data but many of them don't perform well on high cardinality data. If a metric format change includes a new tag that holds high cardinality data, database performance could be reduced enough to cause existing applications not to work as they previously did. Metric format changes that dramatically increase the number of tags or fields of a metric can increase database storage requirements unexpectedly. Both of these types of changes are unsafe. + +### Make unsafe changes opt-in + +If your change has the potential to seriously affect existing users, the change must be opt-in. To do this, add a plugin configuration setting that lets the user select the metric format. Make the setting's default value select the old metric format. When new users add the plugin they can choose the new format and get its benefits. When existing users upgrade, their config files won't have the new setting so the default will ensure that there is no change. + +When adding a setting, avoid using a boolean and consider instead a string or int for future flexibility. A boolean can only handle two formats but a string can handle many. For example, compare use_new_format=true and features=["enable_foo_fields"]; the latter is much easier to extend and still very descriptive. + +If you want to encourage existing users to use the new format you can log a warning once on startup when the old format is selected. The warning should tell users in a gentle way that they can upgrade to a better metric format. If it doesn't make sense to maintain multiple metric formats forever, you can change the default on a major release or even remove the old format completely. See [[Deprecation]] for details. + +### Utility + +Changes should be useful to many or most users. A change that is only useful for a small number of users may not accepted, even if it's off by default. + +## Summary table + +| | delete | rename | add | +| ------- | ------ | ------ | --- | +| metric | unsafe | unsafe | safe | +| tag | unsafe | unsafe | be careful with cardinality | +| field | unsafe | unsafe | ok as long as it's useful for existing users and is worth the added space | + +## References + +InfluxDB Documentation: "Schema and data layout" diff --git a/docs/developers/PACKAGING.md b/docs/developers/PACKAGING.md new file mode 100644 index 0000000..0342459 --- /dev/null +++ b/docs/developers/PACKAGING.md @@ -0,0 +1,70 @@ +# Packaging + +Building the packages for Telegraf is automated using [Make](https://en.wikipedia.org/wiki/Make_(software)). Just running `make` will build a Telegraf binary for the operating system and architecture you are using (if it is supported). If you need to build a different package then you can run `make package` which will build all the supported packages. You will most likely only want a subset, you can define a subset of packages to be built by overriding the `include_packages` variable like so `make package include_packages="amd64.deb"`. You can also build all packages for a specific architecture like so `make package include_packages="$(make amd64)"`. + +The packaging steps require certain tools to be setup before hand to work. These dependencies are listed in the ci.docker file which you can find in the scripts directory. Therefore it is recommended to use Docker to build the artifacts, see more details below. + +## Go Version + +Telegraf will be built using the latest version of Go whenever possible. + +### Update CI image + +Incrementing the version is maintained by the core Telegraf team because it requires access to an internal docker repository that hosts the docker CI images. When a new version is released, the following process is followed: + +1. Within the `Makefile`, `.circleci\config.yml`, and `scripts/ci.docker` files + update the Go versions to the new version number +2. Run `make ci`, this requires quay.io internal permissions +3. The files `scripts\installgo_linux.sh`, `scripts\installgo_mac.sh`, and + `scripts\installgo_windows.sh` need to be updated as well with the new Go + version and SHA +4. Create a pull request with these new changes, and verify the CI passes and + uses the new docker image + +See the [previous PRs](https://github.com/influxdata/telegraf/search?q=chore+update+go&type=commits) as examples. + +### Access to quay.io + +A member of the team needs to invite you to the quay.io organization. +To push new images, the user needs to do the following: + +1. Create a password if the user logged in using Google authentication +2. Download an encrypted username/password from the quay.io user page +3. Run `docker login quay.io` and enter in the encrypted username and password + from the previous step + +## Package using Docker + +This packaging method uses the CI images, and is very similar to how the +official packages are created on release. This is the recommended method for +building the rpm/deb as it is less system dependent. + +Pull the CI images from quay, the version corresponds to the version of Go +that is used to build the binary: + +```shell +docker pull quay.io/influxdb/telegraf-ci:1.9.7 +``` + +Start a shell in the container: + +```shell +docker run -ti quay.io/influxdb/telegraf-ci:1.9.7 /bin/bash +``` + +From within the container: + +1. `go get -d github.com/influxdata/telegraf` +2. `cd /go/src/github.com/influxdata/telegraf` +3. `git checkout release-1.10` + * Replace tag `release-1.10` with the version of Telegraf you would like to build +4. `git reset --hard 1.10.2` +5. `make deps` +6. `make package include_packages="amd64.deb"` + * Change `include_packages` to change what package you want, run `make help` to see possible values + +From the host system, copy the build artifacts out of the container: + +```shell +docker cp romantic_ptolemy:/go/src/github.com/influxdata/telegraf/build/telegraf-1.10.2-1.x86_64.rpm . +``` diff --git a/docs/developers/PROFILING.md b/docs/developers/PROFILING.md new file mode 100644 index 0000000..c1f02e4 --- /dev/null +++ b/docs/developers/PROFILING.md @@ -0,0 +1,66 @@ +# Profiling + +This article describes how to collect performance traces and memory profiles +from Telegraf. If you are submitting this for an issue, please include the +version.txt generated below. + +Use the `--pprof-addr` option to enable the profiler, the easiest way to do +this may be to add this line to `/etc/default/telegraf`: + +```shell +TELEGRAF_OPTS="--pprof-addr localhost:6060" +``` + +Restart Telegraf to activate the profile address. + +## Trace Profile + +Collect a trace during the time where the performance issue is occurring. This +example collects a 10 second trace and runs for 10 seconds: + +```shell +curl 'http://localhost:6060/debug/pprof/trace?seconds=10' > trace.bin +telegraf --version > version.txt +go env GOOS GOARCH >> version.txt +``` + +The `trace.bin` and `version.txt` files can be sent in for analysis or, if desired, you can +analyze the trace with: + +```shell +go tool trace trace.bin +``` + +## Memory Profile + +Collect a heap memory profile: + +```shell +curl 'http://localhost:6060/debug/pprof/heap' > mem.prof +telegraf --version > version.txt +go env GOOS GOARCH >> version.txt +``` + +Analyze: + +```shell +$ go tool pprof mem.prof +(pprof) top5 +``` + +## CPU Profile + +Collect a 30s CPU profile: + +```shell +curl 'http://localhost:6060/debug/pprof/profile' > cpu.prof +telegraf --version > version.txt +go env GOOS GOARCH >> version.txt +``` + +Analyze: + +```shell +go tool pprof cpu.prof +(pprof) top5 +``` diff --git a/docs/developers/README.md b/docs/developers/README.md new file mode 120000 index 0000000..f939e75 --- /dev/null +++ b/docs/developers/README.md @@ -0,0 +1 @@ +../../CONTRIBUTING.md \ No newline at end of file diff --git a/docs/developers/REVIEWS.md b/docs/developers/REVIEWS.md new file mode 100644 index 0000000..1cffe18 --- /dev/null +++ b/docs/developers/REVIEWS.md @@ -0,0 +1,185 @@ +# Reviews + +Pull-requests require two approvals before being merged. Expect several rounds of back and forth on +reviews, non-trivial changes are rarely accepted on the first pass. It might take some time +until you see a first review so please be patient. + +All pull requests should follow the style and best practices in the +[CONTRIBUTING.md](https://github.com/influxdata/telegraf/blob/master/CONTRIBUTING.md) +document. + +## Process + +The review process is roughly structured as follows: + +1. Submit a pull request. +Please check that you signed the [CLA](https://www.influxdata.com/legal/cla/) (and [Corporate CLA](https://www.influxdata.com/legal/ccla/) if you are contributing code on as an employee of your company). Provide a short description of your submission and reference issues that you potentially close. Make sure the CI tests are all green and there are no linter-issues. +1. Get feedback from a first reviewer and a `ready for final review` tag. +Please constructively work with the reviewer to get your code into a mergeable state (see also [below](#reviewing-plugin-code)). +1. Get a final review by one of the InfluxData maintainers. +Please fix any issue raised. +1. Wait for the pull-request to be merged. +It might take some time until your PR gets merged, depending on the release cycle and the type of +your pull-request (bugfix, enhancement of existing code, new plugin, etc). Remember, it might be necessary to rebase your code before merge to resolve conflicts. + +Please read the review comments carefully, fix the related part of the code and/or respond in case there is anything unclear. Maintainers will add the `waiting for response` tag to PRs to make it clear we are waiting on the submitter for updates. __Once the tag is added, if there is no activity on a pull request or the contributor does not respond, our bot will automatically close the PR after two weeks!__ If you expect a longer period of inactivity or you want to abandon a pull request, please let us know. + +In case you still want to continue with the PR, feel free to reopen it. + +## Reviewing Plugin Code + +- Avoid variables scoped to the package. Everything should be scoped to the plugin struct, since multiple instances of the same plugin are allowed and package-level variables will cause race conditions. +- SampleConfig must match the readme, but not include the plugin name. +- structs should include toml tags for fields that are expected to be editable from the config. eg `toml:"command"` (snake_case) +- plugins that want to log should declare the Telegraf logger, not use the log package. eg: + +```Go + Log telegraf.Logger `toml:"-"` +``` + +(in tests, you can do `myPlugin.Log = testutil.Logger{}`) + +- Initialization and config checking should be done on the `Init() error` function, not in the Connect, Gather, or Start functions. +- `Init() error` should not contain connections to external services. If anything fails in Init, Telegraf will consider it a configuration error and refuse to start. +- plugins should avoid synchronization code if they are not starting goroutines. Plugin functions are never called in parallel. +- avoid goroutines when you don't need them and removing them would simplify the code +- errors should almost always be checked. +- avoid boolean fields when a string or enumerated type would be better for future extension. Lots of boolean fields also make the code difficult to maintain. +- use config.Duration instead of internal.Duration +- compose tls.ClientConfig as opposed to specifying all the TLS fields manually +- http.Client should be declared once on `Init() error` and reused, (or better yet, on the package if there's no client-specific configuration). http.Client has built-in concurrency protection and reuses connections transparently when possible. +- avoid doing network calls in loops where possible, as this has a large performance cost. This isn't always possible to avoid. +- when processing batches of records with multiple network requests (some outputs that need to partition writes do this), return an error when you want the whole batch to be retried, log the error when you want the batch to continue without the record +- consider using the StreamingProcessor interface instead of the (legacy) Processor interface +- avoid network calls in processors when at all possible. If it's necessary, it's possible, but complicated (see processor.reversedns). +- avoid dependencies when: + - they require cgo + - they pull in massive projects instead of small libraries + - they could be replaced by a simple http call + - they seem unnecessary, superfluous, or gratuitous +- consider adding build tags if plugins have OS-specific considerations +- use the right logger log levels so that Telegraf is normally quiet eg `plugin.Log.Debugf()` only shows up when running Telegraf with `--debug` +- consistent field types: dynamically setting the type of a field should be strongly avoided as it causes problems that are difficult to solve later, made worse by having to worry about backwards compatibility in future changes. For example, if an numeric value comes from a string field and it is not clear if the field can sometimes be a float, the author should pick either a float or an int, and parse that field consistently every time. Better to sometimes truncate a float, or to always store ints as floats, rather than changing the field type, which causes downstream problems with output databases. +- backwards compatibility: We work hard not to break existing configurations during new changes. Upgrading Telegraf should be a seamless transition. Possible tools to make this transition smooth are: + - enumerable type fields that allow you to customize behavior (avoid boolean feature flags) + - version fields that can be used to opt in to newer changed behavior without breaking old (see inputs.mysql for example) + - a new version of the plugin if it has changed significantly (eg outputs.influxdb and outputs.influxdb_v2) + - Logger and README deprecation warnings + - changing the default value of a field can be okay, but will affect users who have not specified the field and should be approached cautiously. + - The general rule here is "don't surprise me": users should not be caught off-guard by unexpected or breaking changes. + +## Linting + +Each pull request will have the appropriate linters checking the files for any common mistakes. The github action Super Linter is used: [super-linter](https://github.com/github/super-linter). If it is failing you can click on the action and read the logs to figure out the issue. You can also run the github action locally by following these instructions: [run-linter-locally.md](https://github.com/github/super-linter/blob/main/docs/run-linter-locally.md). You can find more information on each of the linters in the super linter readme. + +## Testing + +Sufficient unit tests must be created. New plugins must always contain +some unit tests. Bug fixes and enhancements should include new tests, but +they can be allowed if the reviewer thinks it would not be worth the effort. + +[Table Driven Tests](https://github.com/golang/go/wiki/TableDrivenTests) are +encouraged to reduce boiler plate in unit tests. + +The [stretchr/testify](https://github.com/stretchr/testify) library should be +used for assertions within the tests when possible, with preference towards +github.com/stretchr/testify/require. + +Primarily use the require package to avoid cascading errors: + +```go +assert.Equal(t, lhs, rhs) # avoid +require.Equal(t, lhs, rhs) # good +``` + +## Configuration + +The config file is the primary interface and should be carefully scrutinized. + +Ensure the [[SampleConfig]] and +[README](https://github.com/influxdata/telegraf/blob/master/plugins/inputs/EXAMPLE_README.md) +match with the current standards. + +READMEs should: + +- be spaces, not tabs +- be indented consistently, matching other READMEs +- have two `#` for comments +- have one `#` for defaults, which should always match the default value of the plugin +- include all appropriate types as a list for enumerable field types +- include a useful example, avoiding "example", "test", etc. +- include tips for any common problems +- include example output from the plugin, if input/processor/aggregator/parser/serializer + +## Metric Schema + +Telegraf metrics are heavily based on InfluxDB points, but have some +extensions to support other outputs and metadata. + +New metrics must follow the recommended +[schema design](https://docs.influxdata.com/influxdb/latest/concepts/schema_and_data_layout/). +Each metric should be evaluated for _series cardinality_, proper use of tags vs +fields, and should use existing patterns for encoding metrics. + +Metrics use `snake_case` naming style. + +### Enumerations + +Generally enumeration data should be encoded as a tag. In some cases it may +be desirable to also include the data as an integer field: + +```shell +net_response,result=success result_code=0i +``` + +### Histograms + +Use tags for each range with the `le` tag, and `+Inf` for the values out of +range. This format is inspired by the Prometheus project: + +```shell +cpu,le=0.0 usage_idle_bucket=0i 1486998330000000000 +cpu,le=50.0 usage_idle_bucket=2i 1486998330000000000 +cpu,le=100.0 usage_idle_bucket=2i 1486998330000000000 +cpu,le=+Inf usage_idle_bucket=2i 1486998330000000000 +``` + +### Lists + +Lists are tricky, but the general technique is to encode using a tag, creating +one series be item in the list. + +### Counters + +Counters retrieved from other projects often are in one of two styles, +monotonically increasing without reset and reset on each interval. No attempt +should be made to switch between these two styles but if given the option it +is preferred to use the non-resetting variant. This style is more resilient in +the face of downtime and does not contain a fixed time element. + +### Source tag + +When metrics are gathered from another host, the metric schema should have a tag +named "source" that contains the other host's name. See [this feature +request](https://github.com/influxdata/telegraf/issues/4413) for details. + +The metric schema doesn't need to have a tag for the host running +telegraf. Telegraf agent code can add a tag named "host" and by default +containing the hostname reported by the kernel. This can be configured through +the "hostname" and "omit_hostname" agent settings. + +## Go Best Practices + +In general code should follow best practice describe in [Code Review +Comments](https://github.com/golang/go/wiki/CodeReviewComments). + +### Networking + +All network operations should have appropriate timeouts. The ability to +cancel the option, preferably using a context, is desirable but not always +worth the implementation complexity. + +### Channels + +Channels should be used in judiciously as they often complicate the design and +can easily be used improperly. Only use them when they are needed. diff --git a/docs/developers/SAMPLE_CONFIG.md b/docs/developers/SAMPLE_CONFIG.md new file mode 100644 index 0000000..18d9cc3 --- /dev/null +++ b/docs/developers/SAMPLE_CONFIG.md @@ -0,0 +1,81 @@ +# Sample Configuration + +The sample config file is generated from a results of the `SampleConfig()` functions of the plugin. + +You can generate a full sample +config: + +```shell +telegraf config +``` + +You can also generate the config for a particular plugin using the `-usage` +option: + +```shell +telegraf --usage influxdb +``` + +## Style + +In the config file we use 2-space indention. Since the config is +[TOML](https://github.com/toml-lang/toml) the indention has no meaning. + +Documentation is double commented, full sentences, and ends with a period. + +```toml + ## This text describes what an the exchange_type option does. + # exchange_type = "topic" +``` + +Try to give every parameter a default value whenever possible. If a +parameter does not have a default or must frequently be changed then have it +uncommented. + +```toml + ## Brokers are the AMQP brokers to connect to. + brokers = ["amqp://localhost:5672"] +``` + +Options where the default value is usually sufficient are normally commented +out. The commented out value is the default. + +```toml + ## What an exchange type is. + # exchange_type = "topic" +``` + +If you want to show an example of a possible setting filled out that is +different from the default, show both: + +```toml + ## Static routing key. Used when no routing_tag is set or as a fallback + ## when the tag specified in routing tag is not found. + ## example: routing_key = "telegraf" + # routing_key = "" +``` + +Unless parameters are closely related, add a space between them. Usually +parameters is closely related have a single description. + +```toml + ## If true, queue will be declared as an exclusive queue. + # queue_exclusive = false + + ## If true, queue will be declared as an auto deleted queue. + # queue_auto_delete = false + + ## Authentication credentials for the PLAIN auth_method. + # username = "" + # password = "" +``` + +Parameters should usually be describable in a few sentences. If it takes +much more than this, try to provide a shorter explanation and provide a more +complex description in the Configuration section of the plugins +[README](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/example) + +Boolean parameters should be used judiciously. You should try to think of +something better since they don't scale well, things are often not truly +boolean, and frequently end up with implicit dependencies: this option does +something if this and this are also set. diff --git a/docs/developers/STATE_PERSISTENCE.md b/docs/developers/STATE_PERSISTENCE.md new file mode 100644 index 0000000..7cdaaad --- /dev/null +++ b/docs/developers/STATE_PERSISTENCE.md @@ -0,0 +1,145 @@ +# State-persistence for plugins + +## Purpose + +Plugin state-persistence allows a plugin to save its state across restarts of +Telegraf. This might be necessary if data-input (or output) is stateful and +depends on the result of a previous operation. + +If you for example query data from a service providing a `next` token, your +plugin would need to know the last token received in order to make the next +query. However, this token is lost after a restart of Telegraf if not persisted +and thus your only chance is to restart the query chain potentially resulting +in handling redundant data producing unnecessary traffic. + +This is where state-persistence comes into play. The state-persistence framework +allows your plugin to store a _state_ on shutdown and load that _state_ again +on startup of Telegraf. + +## State format + +The _state_ of a plugin can be any structure or datatype that is serializable +using Golang's JSON serializer. It can be a key-value map or a more complex +structure. E.g. + +```go +type MyState struct { + CurrentToken string + LastToken string + NextToken string + FilterIDs []int64 +} +``` + +would represent a valid state. + +## Implementation + +To enable state-persistence in your plugin you need to implement the +`StatefulPlugin` interface defined in `plugin.go`. The interface looks as +follows: + +```go +type StatefulPlugin interface { + GetState() interface{} + SetState(state interface{}) error +} +``` + +The `GetState()` function should return the current state of the plugin +(see [state format](#state-format)). Please note that this function should +_always_ succeed and should always be callable directly after `Init()`. So make +sure your relevant data-structures are initialized in `Init` to prevent panics. + +Telegraf will call the `GetState()` function on shutdown and will then compile +an overall Telegraf state from the information of all stateful plugins. This +state is then persisted to disk if (and only if) the `statefile` option in the +`agent` section is set. You do _not_ need take care of any serialization or +writing, Telegraf will handle this for you. + +When starting Telegraf, the overall persisted Telegraf state will be restored, +if `statefile` is set. To do so, the `SetState()` function is called with the +deserialized state of the plugin. Please note that this function is called +directly _after_ the `Init()` function of your plugin. You need to make sure +that the given state is what you expect using a type-assertion! Make sure this +won't panic but rather return a meaningful error. + +To assign the state to the correct plugin, Telegraf relies on a plugin ID. +See the ["State assignment" section](#state-assignment) for more details on +the procedure and ["Plugin Identifier" section](#plugin-identifier) for more +details on ID generation. + +## State assignment + +When restoring the state on loading, Telegraf needs to ensure that each plugin +_instance_ gets the correct state. To do so, a plugin ID is used. By default +this ID is generated automatically for each plugin instance but can be +overwritten if necessary (see [Plugin Identifier](#plugin-identifier)). + +State assignment needs to be able to handle multiple instances of the same +plugin type correctly, e.g. if the user has configured multiple instances of +your plugin with different `server` settings. Here, the state saved for +`foo.example.com` needs to be restored to the plugin instance handling +`foo.example.com` on next startup of Telegraf and should _not_ end up at server +`bar.example.com`. So the plugin identifier used for the assignment should be +consistent over restarts of Telegraf. + +In case plugin instances are added to the configuration between restarts, no +state is restored _for those instances_. Furthermore, all states referencing +plugin identifier that are no-longer valid are dropped and will be ignored. This +can happen in case plugin instances are removed or changed in ID. + +## Plugin Identifier + +As outlined above, the plugin identifier (plugin ID) is crucial when assigning +states to plugin instances. By default, Telegraf will automatically generate an +identifier for each plugin configured when starting up. The ID is consistent +over restarts of Telegraf and is based on the _entire configuration_ of the +plugin. This means for each plugin instance, all settings in the configuration +will be concatenated and hashed to derive the ID. The resulting ID will then be +used in both save and restore operations making sure the state ends up in a +plugin with _exactly_ the same configuration that created the state. + +However, this also means that the plugin identifier _is changing_ whenever _any_ +of the configuration setting is changed! For example if your plugin is defined +as + +```go +type MyPlugin struct { + Server string `toml:"server"` + Token string `toml:"token"` + Timeout config.Duration `toml:"timeout"` + + offset int +} +``` + +with `offset` being your state, the plugin ID will change if a user changes the +`timeout` setting in the configuration file. As a consequence the state cannot +be restored. This might be undesirable for your plugin, therefore you can +overwrite the ID generation by implementing the `PluginWithID` interface (see +`plugin.go`). This interface defines a `ID() string` function returning the +identifier o the current plugin _instance_. When implementing this function you +should take the following criteria into account: + +1. The identifier has to be _unique_ for your plugin _instance_ (not only for + the plugin type) to make sure the state is assigned to the correct instance. +1. The identifier has to be _consistent_ across startups/restarts of Telegraf + as otherwise the state cannot be restored. Make sure the order of + configuration settings doesn't matter. +1. Make sure to _include all settings relevant for state assignment_. In + the example above, the plugin's `token` setting might or might not be + relevant to identify the plugin instance. +1. Make sure to _leave out all settings irrelevant for state assignment_. In + the example above, the plugin's `timeout` setting likely is not relevant + for the state and can be left out. + +Which settings are relevant for the state are plugin specific. For example, if +the `offset` is a property of the _server_ the `token` setting is irrelevant. +However, if the `offset` is specific for a certain user suddenly the `token` +setting is relevant. + +Alternatively to generating an identifier automatically, the plugin can allow +the user to specify that ID directly in a configuration setting. However, please +not that this might lead to colliding IDs in larger setups and should thus be +avoided. diff --git a/docs/includes/plugin_config.md b/docs/includes/plugin_config.md new file mode 100644 index 0000000..85ec5d0 --- /dev/null +++ b/docs/includes/plugin_config.md @@ -0,0 +1,6 @@ +In addition to the plugin-specific configuration settings, plugins support +additional global and plugin configuration settings. These settings are used to +modify metrics, tags, and field or create aliases and configure ordering, etc. +See the [CONFIGURATION.md][CONFIGURATION.md] for more details. + +[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins diff --git a/docs/includes/secret_usage.md b/docs/includes/secret_usage.md new file mode 100644 index 0000000..6738a57 --- /dev/null +++ b/docs/includes/secret_usage.md @@ -0,0 +1,7 @@ +Secrets defined by a store are referenced with `@{:}` +the Telegraf configuration. Only certain Telegraf plugins and options of +support secret stores. To see which plugins and options support +secrets, see their respective documentation (e.g. +`plugins/outputs/influxdb/README.md`). If the plugin's README has the +`Secret-store support` section, it will detail which options support secret +store usage. diff --git a/docs/includes/service_input.md b/docs/includes/service_input.md new file mode 100644 index 0000000..2645c9d --- /dev/null +++ b/docs/includes/service_input.md @@ -0,0 +1,8 @@ +This plugin is a service input. Normal plugins gather metrics determined by the +interval setting. Service plugins start a service to listen and wait for +metrics or events to occur. Service plugins have two key differences from +normal plugins: + +1. The global or plugin specific `interval` setting may not apply +2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce + output for this plugin diff --git a/docs/includes/startup_error_behavior.md b/docs/includes/startup_error_behavior.md new file mode 100644 index 0000000..7b2a291 --- /dev/null +++ b/docs/includes/startup_error_behavior.md @@ -0,0 +1,14 @@ +In addition to the plugin-specific and global configuration settings the plugin +supports options for specifying the behavior when experiencing startup errors +using the `startup_error_behavior` setting. Available values are: + +- `error`: Telegraf with stop and exit in case of startup errors. This is the + default behavior. +- `ignore`: Telegraf will ignore startup errors for this plugin and disables it + but continues processing for all other plugins. +- `retry`: Telegraf will try to startup the plugin in every gather or write + cycle in case of startup errors. The plugin is disabled until + the startup succeeds. +- `probe`: Telegraf will probe the plugin's function (if possible) and disables the plugin + in case probing fails. If the plugin does not support probing, Telegraf will + behave as if `ignore` was set instead. diff --git a/docs/specs/README.md b/docs/specs/README.md new file mode 100644 index 0000000..8c59405 --- /dev/null +++ b/docs/specs/README.md @@ -0,0 +1,71 @@ +# Telegraf Specification Overview + +## Objective + +Define and layout the Telegraf specification process. + +## Overview + +The general goal of a spec is to detail the work that needs to get accomplished +for a new feature. A developer should be able to pick up a spec and have a +decent understanding of the objective, the steps required, and most of the +general design decisions. + +The specs can then live in the Telegraf repository to share and involve the +community in the process of planning larger changes or new features. The specs +also serve as a public historical record for changes. + +## Process + +The general workflow is for a user to put up a PR with a spec outlining the +task, have any discussion in the PR, reach consensus, and ultimately commit +the finished spec to the repo. + +While researching a new feature may involve an investment of time, writing the +spec should be relatively quick. It should not take hours of time. + +## Spec naming + +Please name the actual file prefixed with `tsd` and the next available +number, for example: + +* tsd-001-agent-write-ahead-log.md +* tsd-002-inputs-apache-increase-timeout.md +* tsd-003-serializers-parquet.md + +All lower-case and separated by hyphens. + +## What belongs in a spec + +A spec should involve the creation of a markdown file with at least an objective +and overview: + +* Objective (required) - One sentence headline +* Overview (required) - Explain the reasoning for the new feature and any + historical information. Answer the why this is needed. + +Please feel free to make a copy the template.md and start with that. + +The user is free to add additional sections or parts in order to express and +convey a new feature. For example this might include: + +* Keywords - Help identify what the spec is about +* Is/Is-not - Explicitly state what this change includes and does not include +* Prior Art - Point at existing or previous PRs, issues, or other works that + demonstrate the feature or need for it. +* Open Questions - Section with open questions that can get captured in + updates to the PR + +## Changing existing specs + +Small changes which are non-substantive, like grammar or formatting are gladly +accepted. + +After a feature is complete it may make sense to come back and update a spec +based on the final result. + +Other changes that make substantive changes are entirely up to the maintainers +whether the edits to an existing RFC will be accepted. In general, finished +specs should be considered complete and done, however, priorities, details, or +other situations may evolve over time and as such introduce the need to make +updates. diff --git a/docs/specs/template.md b/docs/specs/template.md new file mode 100644 index 0000000..ed69d7a --- /dev/null +++ b/docs/specs/template.md @@ -0,0 +1,20 @@ +# Title + +## Objective + +One sentence explanation of the feature. + +## Overview + +Background and details about the feature. + +## Keywords + +A few items to specify what areas of Telegraf this spec affects (e.g. outputs, +inputs, processors, aggregators, agent, packaging, etc.) + +## Is/Is-not + +## Prior art + +## Open questions diff --git a/docs/specs/tsd-001-deprecation.md b/docs/specs/tsd-001-deprecation.md new file mode 100644 index 0000000..16ce332 --- /dev/null +++ b/docs/specs/tsd-001-deprecation.md @@ -0,0 +1,182 @@ +# Plugin and Plugin Option Deprecation + +## Objective + +Specifies the process of deprecating and removing plugins, plugin settings +including values of those settings or features. + +## Keywords + +procedure, removal, all plugins + +## Overview + +Over time the number of plugins, plugin options and plugin features grow and +some of those plugins or options are either not relevant anymore, have been +superseded or subsumed by other plugins or options. To be able to remove those, +this specification defines a process to deprecate plugins, plugin options and +plugin features including a timeline and minimal time-frames. Additionally, the +specification defines a framework to annotate deprecations in the code and +inform users about such deprecations. + +## User experience + +In the deprecation phase a warning will be shown at Telegraf startup with the +following content + +```text +Plugin "inputs.logparser" deprecated since version 1.15.0 and will be removed in 1.40.0: use 'inputs.tail' with 'grok' data format instead +``` + +Similar warnings will be shown when removing plugin options or option values. +This provides users with time to replace the deprecated plugin in their +configuration file. + +After the shown release (`v1.40.0` in this case) the warning will be promoted +to an error preventing Telegraf from starting. The user now has to adapt the +configuration file to start Telegraf. + +## Time frames and considerations + +When deprecating parts of Telegraf, it is important to provide users with enough +time to migrate to alternative solutions before actually removing those parts. + +In general, plugins, plugin options or option values should only be deprecated +if a suitable alternative exists! In those cases, the deprecations should +predate the removal by at least one and a half years. In current release terms +this corresponds to six minor-versions. However, there might be circumstances +requiring a prolonged time between deprecation and removal to ensure a smooth +transition for users. + +Versions between deprecation and removal of plugins, plugin options or option +values, Telegraf must log a *warning* on startup including information about +the version introducing the deprecation, the version of removal and an +user-facing hint on suitable replacements. In this phase Telegraf should +operate normally even with deprecated plugins, plugin options or option values +being set in the configuration files. + +Starting from the removal version, Telegraf must show an *error* message for +deprecated plugins present in the configuration including all information listed +above. Removed plugin options and option values should be handled as invalid +settings in the configuration files and must lead to an error. In this phase, +Telegraf should *stop running* until all deprecated plugins, plugin options and +option values are removed from the configuration files. + +## Deprecation Process + +The deprecation process comprises the following the steps below. + +### File issue + +In the filed issue you should outline which plugin, plugin option or feature +you want to deprecate and *why*! Determine in which version the plugin should +be removed. + +Try to reach an agreement in the issue before continuing and get a sign off +from the maintainers! + +### Submit deprecation pull-request + +Send a pull request adding deprecation information to the code and update the +plugin's `README.md` file. Depending on what you want to deprecate this +comprises different locations and steps as detailed below. + +Once the deprecation pull-request is merged and Telegraf is released, we have +to wait for the targeted Telegraf version for actually removing the code. + +#### Deprecating a plugin + +When deprecating a plugin you need to add an entry to the `deprecation.go` file +in the respective plugin category with the following format + +```golang + "": { + Since: "", + RemovalIn: "", + Notice: "", + }, +``` + +If you for example want to remove the `inputs.logparser` plugin you should add + +```golang + "logparser": { + Since: "1.15.0", + RemovalIn: "1.40.0" + Notice: "use 'inputs.tail' with 'grok' data format instead", + }, +``` + +to `plugins/inputs/deprecations.go`. By doing this, Telegraf will show a +deprecation warning to the user starting from version `1.15.0` including the +`Notice` you provided. The plugin can then be remove in version `1.40.0`. + +Additionally, you should update the plugin's `README.md` adding a paragraph +mentioning since when the plugin is deprecated, when it will be removed and a +hint to alternatives or replacements. The paragraph should look like this + +```text +**Deprecated in version v1.15.0 and scheduled for removal in v1.40.0**: +Please use the [tail][] plugin with the [`grok` data format][grok parser] +instead! +``` + +#### Deprecating an option + +To deprecate a plugin option, remove the option from the `sample.conf` file and +add the deprecation information to the structure field in the code. If you for +for example want to deprecate the `ssl_enabled` option in `inputs.example` you +should add + +```golang +type Example struct { + ... + SSLEnabled bool `toml:"ssl_enabled" deprecated:"1.3.0;1.40.0;use 'tls_*' options instead"` +} +``` + +to schedule the setting for removal in version `1.40.0`. The last element of +the `deprecated` tag is a user-facing notice similar to plugin deprecation. + +#### Deprecating an option-value + +Sometimes, certain option values become deprecated or superseded by other +options or values. To deprecate those option values, remove them from +`sample.conf` and add the deprecation info in the code if the deprecated value +is *actually used* via + +```golang +func (e *Example) Init() error { + ... + if e.Mode == "old" { + models.PrintOptionDeprecationNotice(telegraf.Warn, "inputs.example", "mode", telegraf.DeprecationInfo{ + Since: "1.23.1", + RemovalIn: "1.40.0", + Notice: "use 'v1' instead", + }) + } + ... + return nil +} +``` + +This will show a warning if the deprecated `v1` value is used for the `mode` +setting in `inputs.example` with a user-facing notice. + +### Submit pull-request for removing code + +Once the plugin, plugin option or option-value is deprecated, we have to wait +for the `RemovedIn` release to remove the code. In the examples above, this +would be version `1.40.0`. After all scheduled bugfix-releases are done, with +`1.40.0` being the next release, you can create a pull-request to actually +remove the deprecated code. + +Please make sure, you remove the plugin, plugin option or option value and the +code referencing those. This might also comprise the `all` files of your plugin +category, test-cases including those of other plugins, README files or other +documentation. For removed plugins, please keep the deprecation info in +`deprecations.go` so users can find a reference when switching from a really +old version. + +Make sure you add an `Important Changes` sections to the `CHANGELOG.md` file +describing the removal with a reference to your PR. diff --git a/docs/specs/tsd-002-custom-builder.md b/docs/specs/tsd-002-custom-builder.md new file mode 100644 index 0000000..3df714e --- /dev/null +++ b/docs/specs/tsd-002-custom-builder.md @@ -0,0 +1,71 @@ +# Telegraf Custom-Builder + +## Objective + +Provide a tool to build a customized, smaller version of Telegraf with only +the required plugins included. + +## Keywords + +tool, binary size, customization + +## Overview + +The Telegraf binary continues to grow as new plugins and features are added +and dependencies are updated. Users running on resource constrained systems +such as embedded-systems or inside containers might suffer from the growth. + +This document specifies a tool to build a smaller Telegraf binary tailored to +the plugins configured and actually used, removing unnecessary and unused +plugins. The implementation should be able to cope with configured parsers and +serializers including defaults for those plugin categories. Valid Telegraf +configuration files, including directories containing such files, are the input +to the customization process. + +The customization tool might not be available for older versions of Telegraf. +Furthermore, the degree of customization and thus the effective size reduction +might vary across versions. The tool must create a single static Telegraf +binary. Distribution packages or containers are *not* targeted. + +## Prior art + +[PR #5809](https://github.com/influxdata/telegraf/pull/5809) and +[telegraf-lite-builder](https://github.com/influxdata/telegraf/tree/telegraf-lite-builder/cmd/telegraf-lite-builder): + +- Uses docker +- Uses browser: + - Generates a webpage to pick what options you want. User chooses plugins; + does not take a config file + - Build a binary, then minifies by stripping and compressing that binary +- Does some steps that belong in makefile, not builder + - Special case for upx + - Makes gzip, zip, tar.gz +- Uses gopkg.in? +- Can also work from the command line + +[PR #8519](https://github.com/influxdata/telegraf/pull/8519) + +- User chooses plugins OR provides a config file + +[powers/telegraf-build](https://github.com/powersj/telegraf-build) + +- User chooses plugins OR provides a config file +- Currently kept in separate repo +- Undoes changes to all.go files + +[rawkode/bring-your-own-telegraf](https://github.com/rawkode/bring-your-own-telegraf) + +- Uses docker + +## Additional information + +You might be able to further reduce the binary size of Telegraf by removing +debugging information. This is done by adding `-w` and `-s` to the linker flags +before building `LDFLAGS="-w -s"`. + +However, please note that this removes information helpful for debugging issues +in Telegraf. + +Additionally, you can use a binary packer such as [UPX](https://upx.github.io/) +to reduce the required *disk* space. This compresses the binary and decompresses +it again at runtime. However, this does not reduce memory footprint at runtime. diff --git a/docs/specs/tsd-003-state-persistence.md b/docs/specs/tsd-003-state-persistence.md new file mode 100644 index 0000000..5a482f7 --- /dev/null +++ b/docs/specs/tsd-003-state-persistence.md @@ -0,0 +1,125 @@ +# Plugin State-Persistence + +## Objective + +Retain the state of stateful plugins across restarts of Telegraf. + +## Keywords + +framework, plugin, stateful, persistence + +## Overview + +Telegraf contains a number of plugins that hold an internal state while +processing. For some of the plugins this state is important for efficient +processing like the location when reading a large file or when continuously +querying data from a stateful peer requiring for example an offset or the last +queried timestamp. For those plugins it is important to persistent their +internal state over restarts of Telegraf. + +It is intended to + +- allow for opt-in of plugins to store a state per plugin _instance_ +- restore the state for each plugin instances at startup +- track the plugin instances over restarts to relate the stored state with a + corresponding plugin instance +- automatically compute plugin instance IDs based on the plugin configuration +- provide a way to manually specify instance IDs by the user +- _not_ restore states if the plugin configuration changed between runs +- make implementation easy for plugin developers +- make no assumption on the state _content_ + +The persistence will use the following steps: + +- Compute an unique ID for each of the plugin _instances_ +- Startup Telegraf plugins calling `Init()`, etc. +- Initialize persistence framework with the user specified `statefile` location + and load the state if present +- Determine all stateful plugin instances by fulfilling the `StatefulPlugin` + interface +- Restore plugin states (if any) for each plugin ID present in the state-file +- Run data-collection etc... +- On shutdown, stopping all Telegraf plugins calling `Stop()` or `Close()` + depending on the plugin type +- Query the state of all registered stateful plugins state +- Create an overall state-map with the plugin instance ID as a key and the + serialized plugin state as value. +- Marshal the overall state-map and store to disk + +Potential users of this functionality are plugins continuously querying +endpoints with information of a previous query (e.g. timestamps, offsets, +transaction tokens, etc.) The following plugins are known to have an internal +state. This is not a comprehensive list. + +- `inputs.win_eventlog` ([PR #8281](https://github.com/influxdata/telegraf/pull/8281)) +- `inputs.docker_log` ([PR #7749](https://github.com/influxdata/telegraf/pull/7749)) +- `inputs.tail` (file offset) +- `inputs.cloudwatch` (`windowStart`/`windowEnd` parameters) +- `inputs.stackdriver` (`prevEnd` parameter) + +### Plugin ID computation + +The plugin ID is computed based on the configuration options specified for the +plugin instance. To generate the ID all settings are extracted as `string` +key-value pairs with the option name being the key and the value being the +configuration option setting. For nested configuration options, e.g. if the +plugins has a sub-table, the options are flattened with a canonical key. The +canonical key elements must be concatenated with a dot (`.`) separator. In case +the sub-element is a list of tables, the key must include the index of each +table prefixed by a hash sign i.e. `#.`. + +The resulting key-value pairs of configuration options are then sorted by the +key in lexical order to make the resulting ID invariant against changes in the +order of configuration options. The key and the value of each pair are joined +by a colon (`:`) to a single `string`. + +Finally, a SHA256 sum is computed across all key-value strings separated by a +`null` byte. The HEX representation of the resulting SHA256 is used as the +plugin instance ID. + +### State serialization format + +The overall Telegraf state maps the plugin IDs (keys) to the serialized state +of the corresponding plugin (values). The state data returned by stateful +plugins is serialized to JSON. The resulting byte-sequence is used as the value +for the overall state. On-disk, the overall state of Telegraf is stored as JSON. + +To restore the state of a plugin, the overall Telegraf state is first +deserialized from the on-disk JSON data and a lookup for the plugin ID is +performed in the resulting map. The value, if found, is then deserialized to the +plugin's state data-structure and provided to the plugin after calling `Init()`. + +## Is / Is-not + +### Is + +- A framework to persist states over restarts of Telegraf +- A simple local state store +- A way to restore plugin states between restarts without configuration changes +- A unified API for plugins to use when requiring persistence of a state + +### Is-Not + +- A remote storage framework +- A way to store anything beyond fundamental plugin states +- A data-store or database +- A way to reassign plugin states if their configuration changes +- A tool to interactively adding/removing/modifying states of plugins +- A persistence guarantee beyond clean shutdown (i.e. no crash resistance) + +## Prior art + +- [PR #8281](https://github.com/influxdata/telegraf/pull/8281): Stores Windows + event-log bookmarks in the registry +- [PR #7749](https://github.com/influxdata/telegraf/pull/7749): Stores container + ID and log offset to a file at a user-provided path +- [PR #7537](https://github.com/influxdata/telegraf/pull/7537): Provides a + global state object and periodically queries plugin states to store the state + object to a JSON file. This approach does not provide a ID per plugin + _instance_ so it seems like there is only a single state for a plugin _type_ +- [PR #9476](https://github.com/influxdata/telegraf/pull/9476): Register + stateful plugins to persister and automatically assigns an ID to plugin + _instances_ based on the configuration. The approach also allows to overwrite + the automatic ID e.g. with user specified data. It uses the plugin instance ID + to store/restore state to the same plugin instance and queries the plugin + state on shutdown and write file (currently JSON). diff --git a/docs/specs/tsd-004-configuration-migration.md b/docs/specs/tsd-004-configuration-migration.md new file mode 100644 index 0000000..883c830 --- /dev/null +++ b/docs/specs/tsd-004-configuration-migration.md @@ -0,0 +1,69 @@ +# Configuration Migration + +## Objective + +Provides a subcommand and framework to migrate configurations containing +deprecated settings to a corresponding recent configuration. + +## Keywords + +configuration, deprecation, telegraf command + +## Overview + +With the deprecation framework of [TSD-001](tsd-001-deprecation.md) implemented +we see more and more plugins and options being scheduled for removal in the +future. Furthermore, deprecations become visible to the user due to the warnings +issued for removed plugins, plugin options and plugin option values. + +To aid the user in mitigating deprecated configuration settings this +specifications proposes the implementation of a `migrate` sub-command to the +Telegraf `config` command for automatically migrate the user's existing +configuration files away from the deprecated settings to an equivalent, recent +configuration. Furthermore, the specification describes the layout and +functionality of a plugin-based migration framework to implement migrations. + +### `migrate` sub-command + +The `migrate` sub-command of the `config` command should take a set of +configuration files and configuration directories and apply available migrations +to deprecated plugins, plugin options or plugin option-values in order to +generate new configuration files that do not make use of deprecated options. + +In the process, the migration procedure must ensure that only plugins with +applicable migrations are modified. Existing configuration must be kept and not +be overwritten without manual confirmation of the user. This should be +accomplished by storing modified configuration files with a `.migrated` suffix +and leaving it to the user to overwrite the existing configuration with the +generated counterparts. If no migration is applied in a configuration file, the +command might not generate a new file and leave the original file untouched. + +During migration, the configuration, plugin behavior, resulting metrics and +comments should be kept on a best-effort basis. Telegraf must inform the user +about applied migrations and potential changes in the plugin behavior or +resulting metrics. If a plugin cannot be automatically migrated but requires +manual intervention, Telegraf should inform the user. + +### Migration implementations + +To implement migrations for deprecated plugins, plugin option or plugin option +values, Telegraf must provide a plugin-based infrastructure to register and +apply implemented migrations based on the plugin-type. Only one migration per +plugin-type must be registered. + +Developers must implement the required interfaces and register the migration +to the mentioned framework. The developer must provide the possibility to +exclude the migration at build-time according to +[TSD-002](tsd-002-custom-builder.md). Existing migrations can be extended but +must be cumulative such that any previous configuration migration functionality +is kept. + +Resulting configurations should generate metrics equivalent to the previous +setup also making use of metric selection, renaming and filtering mechanisms. +In cases this is not possible, there must be a clear information to the user +what to expect and which differences might occur. +A migration can only be informative, i.e. notify the user that a plugin has to +manually be migrated and should point users to additional information. + +Deprecated plugins and plugin options must be removed from the migrated +configuration. diff --git a/docs/specs/tsd-005-output-buffer-strategy.md b/docs/specs/tsd-005-output-buffer-strategy.md new file mode 100644 index 0000000..fbc5497 --- /dev/null +++ b/docs/specs/tsd-005-output-buffer-strategy.md @@ -0,0 +1,77 @@ +# Telegraf Output Buffer Strategy + +## Objective + +Introduce a new agent-level config option to choose a disk buffer strategy for +output plugin metric queues. + +## Overview + +Currently, when a Telegraf output metric queue fills, either due to incoming +metrics being too fast or various issues with writing to the output, oldest +metrics are overwritten and never written to the output. This specification +defines a set of options to make this output queue more durable by persisting +pending metrics to disk rather than only an in-memory limited size queue. + +## Keywords + +output plugins, agent configuration, persist to disk + +## Agent Configuration + +The configuration is at the agent-level, with options for: + +- **Memory**, the current implementation, with no persistence to disk +- **Write-through**, all metrics are also written to disk using a + Write Ahead Log (WAL) file +- **Disk-overflow**, when the memory buffer fills, metrics are flushed to a + WAL file to avoid dropping overflow metrics + +As well as an option to specify a directory to store the WAL files on disk, +with a default value. These configurations are global, and no change means +memory only mode, retaining current behavior. + +## Metric Ordering and Tracking + +Tracking metrics will be accepted on a successful write to the output +destination. Metrics will be written to their appropriate output in the order +they are received in the buffer regardless of which buffer strategy is chosen. + +## Disk Utilization and File Handling + +Each output plugin has its own in-memory output buffer, and therefore will +each have their own WAL file for buffer persistence. This file may not exist +if Telegraf is successfully able to write all of its metrics without filling +the in-memory buffer in disk-overflow mode, or not at all in memory mode. +Telegraf should use one file per output plugin, and remove entries from the +WAL file as they are written to the output. + +Telegraf will not make any attempt to limit the size on disk taken by these +files beyond cleaning up WAL files for metrics that have successfully been +flushed to their output destination. It is the user's responsibility to ensure +these files do not entirely fill the disk, both during Telegraf uptime and +with lingering files from previous instances of the program. + +If WAL files exist for an output plugin from previous instances of Telegraf, +they will be picked up and flushed before any new metrics that are written +to the output. This is to ensure that these metrics are not lost, and to +ensure that output write order remains consistent. + +Telegraf must additionally provide a way to manually flush WAL files via +some separate plugin or similar. This could be used as a way to ensure that +WAL files are properly written in the event that the output plugin changes +and the WAL file is unable to be detected by a new instance of Telegraf. +This plugin should not be required for use to allow the buffer strategy to +work. + +## Is/Is-not + +- Is a way to prevent metrics from being dropped due to a full memory buffer +- Is not a way to guarantee data safety in the event of a crash or system failure +- Is not a way to manage file system allocation size, file space will be used + until the disk is full + +## Prior art + +[Initial issue](https://github.com/influxdata/telegraf/issues/802) +[Loose specification issue](https://github.com/influxdata/telegraf/issues/14805) diff --git a/docs/specs/tsd-006-startup-error-behavior.md b/docs/specs/tsd-006-startup-error-behavior.md new file mode 100644 index 0000000..4ae8549 --- /dev/null +++ b/docs/specs/tsd-006-startup-error-behavior.md @@ -0,0 +1,115 @@ +# Startup Error Behavior + +## Objective + +Unified, configurable behavior on retriable startup errors. + +## Keywords + +inputs, outputs, startup, error, retry + +## Overview + +Many Telegraf plugins connect to an external service either on the same machine +or via network. On automated startup of Telegraf (e.g. via service) there is no +guarantee that those services are fully started yet, especially when they reside +on a remote host. More and more plugins implement mechanisms to retry reaching +their related service if they failed to do so on startup. + +This specification intends to unify the naming of configuration-options, the +values of those options, and their semantic meaning. It describes the behavior +for the different options on handling startup-errors. + +Startup errors are all errors occurring in calls to `Start()` for inputs and +service-inputs or `Connect()` for outputs. The behaviors described below +should only be applied in cases where the plugin *explicitly* states that an +startup error is *retriable*. This includes for example network errors +indicating that the host or service is not yet reachable or external +resources, like a machine or file, which are not yet available, but might become +available later. To indicate a retriable startup error the plugin should return +a predefined error-type. + +In cases where the error cannot be generally determined be retriable by +the plugin, the plugin might add configuration settings to let the user +configure that property. For example, where an error code indicates a fatal, +non-recoverable error in one case but a non-fatal, recoverable error in another +case. + +## Configuration Options and Behaviors + +Telegraf must introduce a unified `startup_error_behavior` configuration option +for inputs and output plugins. The option is handled directly by the Telegraf +agent and is not passed down to the plugins. The setting must be available on a +per-plugin basis and defines how Telegraf behaves on startup errors. + +For all config option values Telegraf might retry to start the plugin for a +limited number of times during the startup phase before actually processing +data. This corresponds to the current behavior of Telegraf to retry three times +with a fifteen second interval before continuing processing of the plugins. + +### `error` behavior + +The `error` setting for the `startup_error_behavior` option causes Telegraf to +fail and exit on startup errors. This must be the default behavior. + +### `retry` behavior + +The `retry` setting for the `startup_error_behavior` option Telegraf must *not* +fail on startup errors and should continue running. Telegraf must retry to +startup the failed plugin in each gather or write cycle, for inputs or for +outputs respectively, for an unlimited number of times. Neither the +plugin's `Gather()` nor `Write()` method is called as long as the startup did +not succeed. Metrics sent to an output plugin will be buffered until the plugin +is actually started. If the metric-buffer limit is reached **metrics might be +dropped**! + +In case a plugin signals a partially successful startup, e.g. a subset of the +given endpoints are reachable, Telegraf must try to fully startup the remaining +endpoints by calling `Start()` or `Connect()`, respectively, until full startup +is reached **and** trigger the plugin's `Gather()` nor `Write()` methods. + +### `ignore` behavior + +When using the `ignore` setting for the `startup_error_behavior` option Telegraf +must *not* fail on startup errors and should continue running. On startup error, +Telegraf must ignore the plugin as-if it was not configured at all, i.e. the +plugin must be completely removed from processing. + +### `probe` behavior + +When using the `probe` setting for the `startup_error_behavior` option Telegraf +must *not* fail on startup errors and should continue running. On startup error, +Telegraf must ignore the plugin as-if it was not configured at all, i.e. the +plugin must be completely removed from processing, similar to the `ignore` +behavior. Additionally, Telegraf must probe the plugin (as defined in +[TSD-009][tsd_009]) after startup, if it implements the `ProbePlugin` interface. +If probing is available *and* returns an error Telegraf must *ignore* the +plugin as-if it was not configured at all. + +[tsd_009]: /docs/specs/tsd-009-probe-on-startup.md + +## Plugin Requirements + +Plugins participating in handling startup errors must implement the `Start()` +or `Connect()` method for inputs and outputs respectively. Those methods must be +safe to be called multiple times during retries without leaking resources or +causing issues in the service used. + +Furthermore, the `Close()` method of the plugins must be safe to be called for +cases where the startup failed without causing panics. + +The plugins should return a `nil` error during startup to indicate a successful +startup or a retriable error (via predefined error type) to enable the defined +startup error behaviors. A non-retriable error (via predefined error type) or +a generic error will bypass the startup error behaviors and Telegraf must fail +and exit in the startup phase. + +## Related Issues + +- [#8586](https://github.com/influxdata/telegraf/issues/8586) `inputs.postgresql` +- [#9778](https://github.com/influxdata/telegraf/issues/9778) `outputs.kafka` +- [#13278](https://github.com/influxdata/telegraf/issues/13278) `outputs.cratedb` +- [#13746](https://github.com/influxdata/telegraf/issues/13746) `inputs.amqp_consumer` +- [#14365](https://github.com/influxdata/telegraf/issues/14365) `outputs.postgresql` +- [#14603](https://github.com/influxdata/telegraf/issues/14603) `inputs.nvidia-smi` +- [#14603](https://github.com/influxdata/telegraf/issues/14603) `inputs.rocm-smi` diff --git a/docs/specs/tsd-007-url-config-behavior.md b/docs/specs/tsd-007-url-config-behavior.md new file mode 100644 index 0000000..c0f806d --- /dev/null +++ b/docs/specs/tsd-007-url-config-behavior.md @@ -0,0 +1,75 @@ +# URL-Based Config Behavior + +## Objective + +Define the retry and reload behavior of remote URLs that are passed as config to +Telegraf. In terms of retry, currently Telegraf will attempt to load a remote +URL three times and then exit. In terms of reload, Telegraf does not have the +capability to reload remote URL based configs. This spec seeks to allow for +options for the user to further these capabilities. + +## Keywords + +config, error, retry, reload + +## Overview + +Telegraf allows for loading configurations from local files, directories, and +files via a URL. In order to allow situations where a configuration file is not +yet available or due to a flaky network, the first proposal is to introduce a +new CLI flag: `--url-config-retry-attempts`. This flag would continue to default +to three and would specify the number of retries to attempt to get a remote URL +during the initial startup of Telegraf. + +```sh +--config-url-retry-attempts=3 Number of times to attempt to obtain a remote + configuration via a URL during startup. Set to + -1 for unlimited attempts. +``` + +These attempts would block Telegraf from starting up completely until success or +until we have run out of attempts and exit. + +Once Telegraf is up and running, users can use the `--watch` flag to enable +watching local files for changes and if/when changes are made, then reload +Telegraf with the new configuration. For remote URLs, I propose a new CLI flag: +`--url-config-check-interval`. This flag would set an internal timer that when +it goes off, would check for an update to a remote URL file. + +```sh +--config-url-watch-interval=0s Time duration to check for updates to URL based + configuration files. Disabled by default. +``` + +At each interval, Telegraf would send an HTTP HEAD request to the configuration +URL, here is an example curl HEAD request and output: + +```sh +$ curl --head http://localhost:8000/config.toml +HTTP/1.0 200 OK +Server: SimpleHTTP/0.6 Python/3.12.3 +Date: Mon, 29 Apr 2024 18:18:56 GMT +Content-type: application/octet-stream +Content-Length: 1336 +Last-Modified: Mon, 29 Apr 2024 11:44:19 GMT +``` + +The proposal then is to store the last-modified value when we first obtain the +file and compare the value at each interval. No need to parse the value, just +store the raw string. If there is a difference, trigger a reload. + +If anything other than 2xx response code is returned from the HEAD request, +Telegraf would print a warning message and retry at the next interval. Telegraf +will continue to run the existing configuration with no change. + +If the value of last-modified is empty, while very unlikely, then Telegraf would +ignore this configuration file. Telegraf will print a warning message once about +the missing field. + +## Relevant Issues + +* Configuration capabilities to retry for loading config via URL #[8854][] +* Telegraf reloads URL-based/remote config on a specified interval #[8730][] + +[8854]: https://github.com/influxdata/telegraf/issues/8854 +[8730]: https://github.com/influxdata/telegraf/issues/8730 diff --git a/docs/specs/tsd-008-partial-write-error-handling.md b/docs/specs/tsd-008-partial-write-error-handling.md new file mode 100644 index 0000000..4b65e89 --- /dev/null +++ b/docs/specs/tsd-008-partial-write-error-handling.md @@ -0,0 +1,78 @@ +# Partial write error handling + +## Objective + +Provide a way to pass information about partial metric write errors from an +output to the output model. + +## Keywords + +output plugins, write, error, output model, metric, buffer + +## Overview + +The output model wrapping each output plugin buffers metrics to be able to batch +those metrics for more efficient sending. In each flush cycle, the model +collects a batch of metrics and hands it over to the output plugin for writing +through the `Write` method. Currently, if writing succeeds (i.e. no error is +returned), _all metrics of the batch_ are removed from the buffer and are marked +as __accepted__ both in terms of statistics as well as in tracking-metric terms. +If writing fails (i.e. any error is returned), _all metrics of the batch_ are +__kept__ in the buffer for requeueing them in the next write cycle. + +Issues arise when an output plugin cannot write all metrics of a batch bit only +some to its service endpoint, e.g. due to the metrics being serializable or if +metrics are selectively rejected by the service on the server side. This might +happen when reaching submission limits, violating service constraints e.g. +by out-of-order sends, or due to invalid characters in the serialited metric. +In those cases, an output currently is only able to accept or reject the +_complete batch of metrics_ as there is no mechanism to inform the model (and +in turn the buffer) that only _some_ of the metrics in the batch were failing. + +As a consequence, outputs often _accept_ the batch to avoid a requeueing of the +failing metrics for the next flush interval. This distorts statistics of +accepted metrics and causes misleading log messages saying all metrics were +written sucessfully which is not true. Even worse, for outputs ending-up with +partial writes, e.g. only the first half of the metrics can be written to the +service, there is no way of telling the model to selectively accept the actually +written metrics and in turn those outputs must internally buffer the remaining, +unwritten metrics leading to a duplication of buffering logic and adding to code +complexity. + +This specification aims at defining the handling of partially successful writes +and introduces the concept of a special _partial write error_ type to reflect +partial writes and partial serialization overcoming the aforementioned issues +and limitations. + +To do so, the _partial write error_ error type must contain a list of +successfully written metrics, to be marked __accepted__, both in terms of +statistics as well as in terms of metric tracking, and must be removed from the +buffer. Furthermore, the error must contain a list of metrics that cannot be +sent or serialized and cannot be retried. These metrics must be marked as +__rejected__, both in terms of statistics as well as in terms of metric +tracking, and must be removed from the buffer. + +The error may contain a list of metrics not-yet written to be __kept__ for the +next write cylce. Those metrics must not be marked and must be kept in the +buffer. If the error does not contain the list of not-yet written metrics, this +list must be inferred using the accept and reject lists mentioned above. + +To allow the model and the buffer to correctly handle tracking metrics ending up +in the buffer and output the tracking information must be preserved during +communication between the output plugin, the model and the buffer through the +specified error. To do so, all metric lists should be communicated as indices +into the batch to be able to handle tracking metrics correctly. + +For backward compatibility and simplicity output plugins can return a `nil` +error to indicate that __all__ metrics of the batch are __accepted__. Similarly, +returing an error _not_ being a _partial write error_ indicates that __all__ +metrics of the batch should be __kept__ in the buffer for the next write cycle. + +## Related Issues + +- [issue #11942](https://github.com/influxdata/telegraf/issues/11942) for + contradicting log messages +- [issue #14802](https://github.com/influxdata/telegraf/issues/14802) for + rate-limiting multiple batch sends +- [issue #15908](https://github.com/influxdata/telegraf/issues/15908) for + infinite loop if single metrics cannot be written diff --git a/docs/specs/tsd-009-probe-on-startup.md b/docs/specs/tsd-009-probe-on-startup.md new file mode 100644 index 0000000..99eec04 --- /dev/null +++ b/docs/specs/tsd-009-probe-on-startup.md @@ -0,0 +1,68 @@ +# Probing plugins after startup + +## Objective + +Allow Telegraf to probe plugins during startup to enable enhanced plugin error +detection like availability of hardware or services + +## Keywords + +inputs, outputs, startup, probe, error, ignore, behavior + +## Overview + +When plugins are first instantiated, Telegraf will call the plugin's `Start()` +method (for inputs) or `Connect()` (for outputs) which will initialize its +configuration based off of config options and the running environment. It is +sometimes the case that while the initialization step succeeds, the upstream +service in which the plugin relies on is not actually running, or is not capable +of being communicated with due to incorrect configuration or environmental +problems. In situations like this, Telegraf does not detect that the plugin's +upstream service is not functioning properly, and thus it will continually call +the plugin during each `Gather()` iteration. This often has the effect of +polluting journald and system logs with voluminous error messages, which creates +issues for system administrators who rely on such logs to identify other +unrelated system problems. + +More background discussion on this option, including other possible avenues, can +be viewed [here](https://github.com/influxdata/telegraf/issues/16028). + +## Probing + +Probing is an action whereby the plugin should ensure that the plugin will be +fully functional on a best effort basis. This may comprise communicating with +its external service, trying to access required devices, entities or executables +etc to ensure that the plugin will not produce errors during e.g. data collection +or data output. Probing must *not* produce, process or output any metrics. + +Plugins that support probing must implement the `ProbePlugin` interface. Such +plugins must behave in the following manner: + +1. Return an error if the external dependencies (hardware, services, +executables, etc.) of the plugin are not available. +2. Return an error if information cannot be gathered (in the case of inputs) or +sent (in the case of outputs) due to unrecoverable issues. For example, invalid +authentication, missing permissions, or non-existent endpoints. +3. Otherwise, return `nil` indicating the plugin will be fully functional. + +## Plugin Requirements + +Plugins that allow probing must implement the `ProbePlugin` interface. The +exact implementation depends on the plugin's functionality and requirements, +but generally it should take the same actions as it would during normal operation +e.g. calling `Gather()` or `Write()` and check if errors occur. If probing fails, +it must be safe to call the plugin's `Close()` method. + +Input plugins must *not* produce metrics, output plugins must *not* send any +metrics to the service. Plugins must *not* influence the later data processing or +collection by modifying the internal state of the plugin or the external state of the +service or hardware. For example, file-offsets or other service states must be +reset to not lose data during the first gather or write cycle. + +Plugins must return `nil` upon successful probing or an error otherwise. + +## Related Issues + +- [#16028](https://github.com/influxdata/telegraf/issues/16028) +- [#15916](https://github.com/influxdata/telegraf/pull/15916) +- [#16001](https://github.com/influxdata/telegraf/pull/16001) diff --git a/etc/logrotate.d/telegraf b/etc/logrotate.d/telegraf new file mode 100644 index 0000000..f34017f --- /dev/null +++ b/etc/logrotate.d/telegraf @@ -0,0 +1,11 @@ +/var/log/telegraf/telegraf.log +{ + rotate 6 + daily + missingok + dateext + copytruncate + notifempty + compress +} + diff --git a/filter/filter.go b/filter/filter.go new file mode 100644 index 0000000..d6ba9b1 --- /dev/null +++ b/filter/filter.go @@ -0,0 +1,140 @@ +package filter + +import ( + "strings" + + "github.com/gobwas/glob" +) + +type Filter interface { + Match(string) bool +} + +// Compile takes a list of string filters and returns a Filter interface +// for matching a given string against the filter list. The filter list +// supports glob matching with separators too, ie: +// +// f, _ := Compile([]string{"cpu", "mem", "net*"}) +// f.Match("cpu") // true +// f.Match("network") // true +// f.Match("memory") // false +// +// separators are only to be used for globbing filters, ie: +// +// f, _ := Compile([]string{"cpu.*.count"}, '.') +// f.Match("cpu.count") // false +// f.Match("cpu.measurement.count") // true +// f.Match("cpu.field.measurement.count") // false +// +// Compile will return nil if the filter list is empty. +func Compile(filters []string, separators ...rune) (Filter, error) { + // return if there is nothing to compile + if len(filters) == 0 { + return nil, nil + } + + // check if we can compile a non-glob filter + noGlob := len(separators) == 0 + for _, filter := range filters { + if hasMeta(filter) { + noGlob = false + break + } + } + + switch { + case noGlob: + // return non-globbing filter if not needed. + return compileFilterNoGlob(filters), nil + case len(filters) == 1: + return glob.Compile(filters[0], separators...) + default: + return glob.Compile("{"+strings.Join(filters, ",")+"}", separators...) + } +} + +func MustCompile(filters []string, separators ...rune) Filter { + f, err := Compile(filters, separators...) + if err != nil { + panic(err) + } + return f +} + +// hasMeta reports whether path contains any magic glob characters. +func hasMeta(s string) bool { + return strings.ContainsAny(s, "*?[") +} + +type filter struct { + m map[string]struct{} +} + +func (f *filter) Match(s string) bool { + _, ok := f.m[s] + return ok +} + +type filtersingle struct { + s string +} + +func (f *filtersingle) Match(s string) bool { + return f.s == s +} + +func compileFilterNoGlob(filters []string) Filter { + if len(filters) == 1 { + return &filtersingle{s: filters[0]} + } + out := filter{m: make(map[string]struct{})} + for _, filter := range filters { + out.m[filter] = struct{}{} + } + return &out +} + +type IncludeExcludeFilter struct { + include Filter + exclude Filter + includeDefault bool + excludeDefault bool +} + +func NewIncludeExcludeFilter(include, exclude []string) (Filter, error) { + return NewIncludeExcludeFilterDefaults(include, exclude, true, false) +} + +func NewIncludeExcludeFilterDefaults(include, exclude []string, includeDefault, excludeDefault bool) (Filter, error) { + in, err := Compile(include) + if err != nil { + return nil, err + } + + ex, err := Compile(exclude) + if err != nil { + return nil, err + } + + return &IncludeExcludeFilter{in, ex, includeDefault, excludeDefault}, nil +} + +func (f *IncludeExcludeFilter) Match(s string) bool { + if f.include != nil { + if !f.include.Match(s) { + return false + } + } else if !f.includeDefault { + return false + } + + if f.exclude != nil { + if f.exclude.Match(s) { + return false + } + } else if f.excludeDefault { + return false + } + + return true +} diff --git a/filter/filter_test.go b/filter/filter_test.go new file mode 100644 index 0000000..8842d2a --- /dev/null +++ b/filter/filter_test.go @@ -0,0 +1,132 @@ +package filter + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCompile(t *testing.T) { + f, err := Compile(nil) + require.NoError(t, err) + require.Nil(t, f) + + f, err = Compile([]string{"cpu"}) + require.NoError(t, err) + require.True(t, f.Match("cpu")) + require.False(t, f.Match("cpu0")) + require.False(t, f.Match("mem")) + + f, err = Compile([]string{"cpu*"}) + require.NoError(t, err) + require.True(t, f.Match("cpu")) + require.True(t, f.Match("cpu0")) + require.False(t, f.Match("mem")) + + f, err = Compile([]string{"cpu", "mem"}) + require.NoError(t, err) + require.True(t, f.Match("cpu")) + require.False(t, f.Match("cpu0")) + require.True(t, f.Match("mem")) + + f, err = Compile([]string{"cpu", "mem", "net*"}) + require.NoError(t, err) + require.True(t, f.Match("cpu")) + require.False(t, f.Match("cpu0")) + require.True(t, f.Match("mem")) + require.True(t, f.Match("network")) + + f, err = Compile([]string{"cpu.*.count"}, '.') + require.NoError(t, err) + require.False(t, f.Match("cpu.count")) + require.True(t, f.Match("cpu.measurement.count")) + require.False(t, f.Match("cpu.field.measurement.count")) + + f, err = Compile([]string{"cpu.*.count"}, '.', ',') + require.NoError(t, err) + require.True(t, f.Match("cpu.measurement.count")) + require.False(t, f.Match("cpu.,.count")) // ',' is not considered under * as it is specified as a separator + require.False(t, f.Match("cpu.field,measurement.count")) +} + +func TestIncludeExclude(t *testing.T) { + labels := []string{"best", "com_influxdata", "timeseries", "com_influxdata_telegraf", "ever"} + tags := make([]string, 0, len(labels)) + + filter, err := NewIncludeExcludeFilter(nil, []string{"com_influx*"}) + if err != nil { + t.Fatalf("Failed to create include/exclude filter - %v", err) + } + + for i := range labels { + if filter.Match(labels[i]) { + tags = append(tags, labels[i]) + } + } + + require.Equal(t, []string{"best", "timeseries", "ever"}, tags) +} + +var benchbool bool + +func BenchmarkFilterSingleNoGlobFalse(b *testing.B) { + f, err := Compile([]string{"cpu"}) + require.NoError(b, err) + var tmp bool + for n := 0; n < b.N; n++ { + tmp = f.Match("network") + } + benchbool = tmp +} + +func BenchmarkFilterSingleNoGlobTrue(b *testing.B) { + f, err := Compile([]string{"cpu"}) + require.NoError(b, err) + var tmp bool + for n := 0; n < b.N; n++ { + tmp = f.Match("cpu") + } + benchbool = tmp +} + +func BenchmarkFilter(b *testing.B) { + f, err := Compile([]string{"cpu", "mem", "net*"}) + require.NoError(b, err) + var tmp bool + for n := 0; n < b.N; n++ { + tmp = f.Match("network") + } + benchbool = tmp +} + +func BenchmarkFilterNoGlob(b *testing.B) { + f, err := Compile([]string{"cpu", "mem", "net"}) + require.NoError(b, err) + var tmp bool + for n := 0; n < b.N; n++ { + tmp = f.Match("net") + } + benchbool = tmp +} + +func BenchmarkFilter2(b *testing.B) { + f, err := Compile([]string{"aa", "bb", "c", "ad", "ar", "at", "aq", + "aw", "az", "axxx", "ab", "cpu", "mem", "net*"}) + require.NoError(b, err) + var tmp bool + for n := 0; n < b.N; n++ { + tmp = f.Match("network") + } + benchbool = tmp +} + +func BenchmarkFilter2NoGlob(b *testing.B) { + f, err := Compile([]string{"aa", "bb", "c", "ad", "ar", "at", "aq", + "aw", "az", "axxx", "ab", "cpu", "mem", "net"}) + require.NoError(b, err) + var tmp bool + for n := 0; n < b.N; n++ { + tmp = f.Match("net") + } + benchbool = tmp +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..39627ee --- /dev/null +++ b/go.mod @@ -0,0 +1,549 @@ +module github.com/influxdata/telegraf + +go 1.24.0 + +godebug x509negativeserial=1 + +require ( + cloud.google.com/go/bigquery v1.68.0 + cloud.google.com/go/monitoring v1.24.2 + cloud.google.com/go/pubsub v1.49.0 + cloud.google.com/go/storage v1.53.0 + collectd.org v0.6.0 + github.com/99designs/keyring v1.2.2 + github.com/Azure/azure-event-hubs-go/v3 v3.6.2 + github.com/Azure/azure-kusto-go v0.16.1 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 + github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs v1.3.2 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor v0.11.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 + github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue v1.0.1 + github.com/Azure/go-autorest/autorest v0.11.30 + github.com/Azure/go-autorest/autorest/adal v0.9.24 + github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 + github.com/BurntSushi/toml v1.5.0 + github.com/ClickHouse/clickhouse-go/v2 v2.34.0 + github.com/DATA-DOG/go-sqlmock v1.5.2 + github.com/IBM/nzgo/v12 v12.0.9 + github.com/IBM/sarama v1.45.1 + github.com/Masterminds/semver/v3 v3.3.1 + github.com/Masterminds/sprig v2.22.0+incompatible + github.com/Masterminds/sprig/v3 v3.3.0 + github.com/Mellanox/rdmamap v1.1.0 + github.com/PaesslerAG/gval v1.2.4 + github.com/SAP/go-hdb v1.13.6 + github.com/aerospike/aerospike-client-go/v5 v5.11.0 + github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 + github.com/alitto/pond v1.9.2 + github.com/aliyun/alibaba-cloud-sdk-go v1.63.107 + github.com/amir/raidman v0.0.0-20170415203553-1ccc43bfb9c9 + github.com/antchfx/jsonquery v1.3.6 + github.com/antchfx/xmlquery v1.4.4 + github.com/antchfx/xpath v1.3.4 + github.com/apache/arrow-go/v18 v18.3.0 + github.com/apache/iotdb-client-go v1.3.4 + github.com/apache/thrift v0.21.0 + github.com/aristanetworks/goarista v0.0.0-20190325233358-a123909ec740 + github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 + github.com/awnumar/memguard v0.22.5 + github.com/aws/aws-sdk-go-v2 v1.36.3 + github.com/aws/aws-sdk-go-v2/config v1.29.14 + github.com/aws/aws-sdk-go-v2/credentials v1.17.67 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 + github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.44.3 + github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.49.0 + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.43.1 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.218.0 + github.com/aws/aws-sdk-go-v2/service/kinesis v1.35.0 + github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 + github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.31.0 + github.com/aws/smithy-go v1.22.3 + github.com/benbjohnson/clock v1.3.5 + github.com/blues/jsonata-go v1.5.4 + github.com/bmatcuk/doublestar/v3 v3.0.0 + github.com/boschrexroth/ctrlx-datalayer-golang v1.3.1 + github.com/caio/go-tdigest v3.1.0+incompatible + github.com/cisco-ie/nx-telemetry-proto v0.0.0-20230117155933-f64c045c77df + github.com/clarify/clarify-go v0.4.0 + github.com/cloudevents/sdk-go/v2 v2.16.0 + github.com/compose-spec/compose-go v1.20.2 + github.com/coocood/freecache v1.2.4 + github.com/coreos/go-semver v0.3.1 + github.com/coreos/go-systemd/v22 v22.5.0 + github.com/couchbase/go-couchbase v0.1.1 + github.com/datadope-io/go-zabbix/v2 v2.0.1 + github.com/digitalocean/go-libvirt v0.0.0-20250417173424-a6a66ef779d6 + github.com/dimchansky/utfbom v1.1.1 + github.com/djherbis/times v1.6.0 + github.com/docker/docker v28.1.1+incompatible + github.com/docker/go-connections v0.5.0 + github.com/dustin/go-humanize v1.0.1 + github.com/dynatrace-oss/dynatrace-metric-utils-go v0.5.0 + github.com/eclipse/paho.golang v0.22.0 + github.com/eclipse/paho.mqtt.golang v1.5.0 + github.com/facebook/time v0.0.0-20240626113945-18207c5d8ddc + github.com/fatih/color v1.18.0 + github.com/go-ldap/ldap/v3 v3.4.11 + github.com/go-logfmt/logfmt v0.6.0 + github.com/go-ole/go-ole v1.3.0 + github.com/go-redis/redis/v7 v7.4.1 + github.com/go-redis/redis/v8 v8.11.5 + github.com/go-sql-driver/mysql v1.9.2 + github.com/go-stomp/stomp v2.1.4+incompatible + github.com/gobwas/glob v0.2.3 + github.com/gofrs/uuid/v5 v5.3.2 + github.com/gogo/protobuf v1.3.2 + github.com/golang-jwt/jwt/v5 v5.2.2 + github.com/golang/geo v0.0.0-20190916061304-5b978397cfec + github.com/golang/snappy v1.0.0 + github.com/google/cel-go v0.25.0 + github.com/google/gnxi v0.0.0-20231026134436-d82d9936af15 + github.com/google/go-cmp v0.7.0 + github.com/google/go-github/v32 v32.1.0 + github.com/google/licensecheck v0.3.1 + github.com/google/uuid v1.6.0 + github.com/gopacket/gopacket v1.3.1 + github.com/gopcua/opcua v0.8.0 + github.com/gophercloud/gophercloud/v2 v2.7.0 + github.com/gorcon/rcon v1.4.0 + github.com/gorilla/mux v1.8.1 + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 + github.com/gosnmp/gosnmp v1.40.0 + github.com/grid-x/modbus v0.0.0-20240503115206-582f2ab60a18 + github.com/gwos/tcg/sdk v0.0.0-20240830123415-f8a34bba6358 + github.com/hashicorp/consul/api v1.32.1 + github.com/hashicorp/go-uuid v1.0.3 + github.com/hashicorp/golang-lru/v2 v2.0.7 + github.com/influxdata/influxdb-observability/common v0.5.12 + github.com/influxdata/influxdb-observability/influx2otel v0.5.12 + github.com/influxdata/influxdb-observability/otel2influx v0.5.12 + github.com/influxdata/line-protocol/v2 v2.2.1 + github.com/influxdata/tail v1.0.1-0.20241014115250-3e0015cb677a + github.com/influxdata/toml v0.0.0-20190415235208-270119a8ce65 + github.com/intel/iaevents v1.1.0 + github.com/intel/powertelemetry v1.0.2 + github.com/jackc/pgconn v1.14.3 + github.com/jackc/pgio v1.0.0 + github.com/jackc/pgtype v1.14.4 + github.com/jackc/pgx/v4 v4.18.3 + github.com/jedib0t/go-pretty/v6 v6.6.7 + github.com/jeremywohl/flatten/v2 v2.0.0-20211013061545-07e4a09fb8e4 + github.com/jmespath/go-jmespath v0.4.0 + github.com/karrick/godirwalk v1.16.2 + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 + github.com/klauspost/compress v1.18.0 + github.com/klauspost/pgzip v1.2.6 + github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b + github.com/leodido/go-syslog/v4 v4.2.0 + github.com/linkedin/goavro/v2 v2.13.1 + github.com/logzio/azure-monitor-metrics-receiver v1.1.0 + github.com/lxc/incus/v6 v6.12.0 + github.com/mdlayher/apcupsd v0.0.0-20220319200143-473c7b5f3c6a + github.com/mdlayher/vsock v1.2.1 + github.com/microsoft/ApplicationInsights-Go v0.4.4 + github.com/microsoft/go-mssqldb v1.8.1 + github.com/miekg/dns v1.1.66 + github.com/moby/ipvs v1.1.0 + github.com/multiplay/go-ts3 v1.2.0 + github.com/nats-io/nats-server/v2 v2.11.3 + github.com/nats-io/nats.go v1.42.0 + github.com/netsampler/goflow2/v2 v2.2.2 + github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1 + github.com/nsqio/go-nsq v1.1.0 + github.com/nwaples/tacplus v0.0.3 + github.com/olivere/elastic v6.2.37+incompatible + github.com/openconfig/gnmi v0.14.1 + github.com/openconfig/goyang v1.6.2 + github.com/opensearch-project/opensearch-go/v2 v2.3.0 + github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b + github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0 + github.com/openzipkin/zipkin-go v0.4.3 + github.com/p4lang/p4runtime v1.4.1 + github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0 + github.com/pborman/ansi v1.0.0 + github.com/pcolladosoto/goslurm v0.1.0 + github.com/peterbourgon/unixtransport v0.0.4 + github.com/pion/dtls/v2 v2.2.12 + github.com/prometheus-community/pro-bing v0.7.0 + github.com/prometheus/client_golang v1.22.0 + github.com/prometheus/client_model v0.6.2 + github.com/prometheus/common v0.63.0 + github.com/prometheus/procfs v0.16.1 + github.com/prometheus/prometheus v0.54.1 + github.com/rabbitmq/amqp091-go v1.10.0 + github.com/rclone/rclone v1.69.2 + github.com/redis/go-redis/v9 v9.8.0 + github.com/riemann/riemann-go-client v0.5.1-0.20211206220514-f58f10cdce16 + github.com/robbiet480/go.nut v0.0.0-20220219091450-bd8f121e1fa1 + github.com/robinson/gos7 v0.0.0-20240315073918-1f14519e4846 + github.com/safchain/ethtool v0.5.10 + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 + github.com/seancfoley/ipaddress-go v1.7.1 + github.com/sensu/sensu-go/api/core/v2 v2.16.0 + github.com/shirou/gopsutil/v4 v4.25.4 + github.com/showwin/speedtest-go v1.7.10 + github.com/signalfx/golib/v3 v3.3.54 + github.com/sijms/go-ora/v2 v2.8.24 + github.com/sirupsen/logrus v1.9.3 + github.com/sleepinggenius2/gosmi v0.4.4 + github.com/snowflakedb/gosnowflake v1.14.0 + github.com/srebhan/cborquery v1.0.4 + github.com/srebhan/protobufquery v1.0.4 + github.com/stretchr/testify v1.10.0 + github.com/tbrandon/mbserver v0.0.0-20170611213546-993e1772cc62 + github.com/tdrn-org/go-hue v0.3.0 + github.com/testcontainers/testcontainers-go v0.37.0 + github.com/testcontainers/testcontainers-go/modules/azure v0.37.0 + github.com/testcontainers/testcontainers-go/modules/kafka v0.37.0 + github.com/thomasklein94/packer-plugin-libvirt v0.5.0 + github.com/tidwall/gjson v1.18.0 + github.com/tidwall/wal v1.1.8 + github.com/tinylib/msgp v1.2.5 + github.com/urfave/cli/v2 v2.27.6 + github.com/vapourismo/knx-go v0.0.0-20240915133544-a6ab43471c11 + github.com/vishvananda/netlink v1.3.1 + github.com/vishvananda/netns v0.0.5 + github.com/vjeantet/grok v1.0.1 + github.com/vmware/govmomi v0.50.0 + github.com/wavefronthq/wavefront-sdk-go v0.15.0 + github.com/x448/float16 v0.8.4 + github.com/xdg/scram v1.0.5 + github.com/yuin/goldmark v1.7.11 + go.mongodb.org/mongo-driver v1.17.3 + go.opentelemetry.io/collector/pdata v1.31.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 + go.opentelemetry.io/otel/sdk/metric v1.35.0 + go.opentelemetry.io/proto/otlp v1.3.1 + go.starlark.net v0.0.0-20250417143717-f57e51f710eb + go.step.sm/crypto v0.63.0 + golang.org/x/crypto v0.38.0 + golang.org/x/mod v0.24.0 + golang.org/x/net v0.40.0 + golang.org/x/oauth2 v0.30.0 + golang.org/x/sync v0.14.0 + golang.org/x/sys v0.33.0 + golang.org/x/term v0.32.0 + golang.org/x/text v0.25.0 + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20211230205640-daad0b7ba671 + gonum.org/v1/gonum v0.16.0 + google.golang.org/api v0.232.0 + google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 + google.golang.org/grpc v1.72.0 + google.golang.org/protobuf v1.36.6 + gopkg.in/gorethink/gorethink.v3 v3.0.5 + gopkg.in/olivere/elastic.v5 v5.0.86 + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 + gopkg.in/yaml.v2 v2.4.0 + k8s.io/api v0.33.0 + k8s.io/apimachinery v0.33.0 + k8s.io/client-go v0.33.0 + layeh.com/radius v0.0.0-20221205141417-e7fbddd11d68 + modernc.org/sqlite v1.37.0 + software.sslmate.com/src/go-pkcs12 v0.5.0 +) + +require ( + cel.dev/expr v0.23.1 // indirect + cloud.google.com/go v0.121.0 // indirect + cloud.google.com/go/auth v0.16.1 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect + cloud.google.com/go/compute/metadata v0.6.0 // indirect + cloud.google.com/go/iam v1.5.2 // indirect + code.cloudfoundry.org/clock v1.2.0 // indirect + dario.cat/mergo v1.0.1 // indirect + filippo.io/edwards25519 v1.1.0 // indirect + github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect + github.com/Azure/azure-amqp-common-go/v4 v4.2.0 // indirect + github.com/Azure/azure-pipeline-go v0.2.3 // indirect + github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0 // indirect + github.com/Azure/azure-storage-queue-go v0.0.0-20230531184854-c06a8eff66fe // indirect + github.com/Azure/go-amqp v1.4.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect + github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect + github.com/ClickHouse/ch-go v0.65.1 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver v1.5.0 // indirect + github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/abbot/go-http-auth v0.4.0 // indirect + github.com/alecthomas/participle v0.4.1 // indirect + github.com/andybalholm/brotli v1.1.1 // indirect + github.com/antlr4-go/antlr/v4 v4.13.1 // indirect + github.com/apache/arrow/go/v15 v15.0.2 // indirect + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect + github.com/aristanetworks/glog v0.0.0-20191112221043-67e8567f59f3 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/awnumar/memcall v0.3.0 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.43 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.25 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.6 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.6 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bitly/go-hostpool v0.1.0 // indirect + github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect + github.com/brutella/dnssd v1.2.14 // indirect + github.com/bufbuild/protocompile v0.14.1 + github.com/caio/go-tdigest/v4 v4.0.1 // indirect + github.com/cenkalti/backoff v2.2.1+incompatible // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/couchbase/gomemcached v0.1.3 // indirect + github.com/couchbase/goutils v0.1.0 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect + github.com/danieljoos/wincred v1.2.2 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/devigned/tab v0.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/dvsekhvalnov/jose2go v1.6.0 // indirect + github.com/eapache/go-resiliency v1.7.0 // indirect + github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect + github.com/eapache/queue v1.1.0 // indirect + github.com/ebitengine/purego v0.8.3 // indirect + github.com/echlebek/timeproxy v1.0.0 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect + github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fxamacker/cbor/v2 v2.8.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.7 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect + github.com/go-chi/chi/v5 v5.2.1 // indirect + github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348 // indirect + github.com/go-faster/city v1.0.1 // indirect + github.com/go-faster/errors v0.7.1 // indirect + github.com/go-git/go-billy/v5 v5.6.0 // indirect + github.com/go-jose/go-jose/v4 v4.0.5 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.20.4 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-stack/stack v1.8.1 // indirect + github.com/goburrow/modbus v0.1.0 // indirect + github.com/goburrow/serial v0.1.1-0.20211022031912-bfb69110f8dd // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect + github.com/golang-jwt/jwt/v4 v4.5.2 // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/flatbuffers v25.2.10+incompatible // indirect + github.com/google/gnostic-models v0.6.9 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/google/go-tpm v0.9.4 // indirect + github.com/google/s2a-go v0.1.9 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect + github.com/googleapis/gax-go/v2 v2.14.1 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect + github.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect + github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/hashicorp/packer-plugin-sdk v0.3.2 // indirect + github.com/hashicorp/serf v0.10.1 // indirect + github.com/huandu/xstrings v1.5.0 // indirect + github.com/imdario/mergo v0.3.16 // indirect + github.com/jackc/chunkreader/v2 v2.0.1 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.3 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/puddle v1.3.0 // indirect + github.com/jaegertracing/jaeger v1.47.0 // indirect + github.com/jcmturner/aescts/v2 v2.0.0 // indirect + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect + github.com/jcmturner/gofork v1.7.6 // indirect + github.com/jcmturner/goidentity/v6 v6.0.1 // indirect + github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect + github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/jmhodges/clock v1.2.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/josharian/native v1.1.0 // indirect + github.com/jpillora/backoff v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 // indirect + github.com/klauspost/asmfmt v1.3.2 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/kr/fs v0.1.0 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect + github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b // indirect + github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a // indirect + github.com/magiconair/properties v1.8.10 // indirect + github.com/mailru/easyjson v0.9.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-ieproxy v0.0.11 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mdlayher/genetlink v1.2.0 // indirect + github.com/mdlayher/netlink v1.7.2 // indirect + github.com/mdlayher/socket v0.5.1 // indirect + github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect + github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect + github.com/minio/highwayhash v1.0.3 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/go-archive v0.1.0 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/atomicwriter v0.1.0 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/sys/user v0.4.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/montanaflynn/stats v0.7.1 // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/mtibben/percent v0.2.1 // indirect + github.com/muhlemmer/gu v0.3.1 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/naoina/go-stringutil v0.1.0 // indirect + github.com/nats-io/jwt/v2 v2.7.4 // indirect + github.com/nats-io/nkeys v0.4.11 // indirect + github.com/nats-io/nuid v1.0.1 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/ncw/swift/v2 v2.0.3 // indirect + github.com/oapi-codegen/runtime v1.1.1 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.101.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect + github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect + github.com/paulmach/orb v0.11.1 // indirect + github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect + github.com/pierrec/lz4/v4 v4.1.22 // indirect + github.com/pion/logging v0.2.2 // indirect + github.com/pion/transport/v2 v2.2.4 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pkg/sftp v1.13.9 // indirect + github.com/pkg/xattr v0.4.10 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/rfjakob/eme v1.1.2 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/samber/lo v1.47.0 // indirect + github.com/seancfoley/bintree v1.3.1 // indirect + github.com/segmentio/asm v1.2.0 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/signalfx/com_signalfx_metrics_protobuf v0.0.3 // indirect + github.com/signalfx/gohistogram v0.0.0-20160107210732-1ccfd2ff5083 // indirect + github.com/signalfx/sapm-proto v0.12.0 // indirect + github.com/spf13/cast v1.7.1 // indirect + github.com/spf13/pflag v1.0.6 // indirect + github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect + github.com/stoewer/go-strcase v1.3.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/tdrn-org/go-nsdp v0.5.0 + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.1 // indirect + github.com/tidwall/tinylru v1.2.1 // indirect + github.com/tklauser/go-sysconf v0.3.13 // indirect + github.com/tklauser/numcpus v0.7.0 // indirect + github.com/twmb/murmur3 v1.1.7 // indirect + github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect + github.com/uber/jaeger-lib v2.4.1+incompatible // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/xdg/stringprep v1.0.3 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect + github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect + github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + github.com/zeebo/assert v1.3.1 // indirect + github.com/zeebo/errs v1.4.0 // indirect + github.com/zeebo/xxh3 v1.0.2 // indirect + github.com/zitadel/logging v0.6.2 // indirect + github.com/zitadel/oidc/v3 v3.37.0 // indirect + github.com/zitadel/schema v1.3.1 // indirect + go.etcd.io/etcd/api/v3 v3.5.4 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/collector/consumer v0.101.0 // indirect + go.opentelemetry.io/collector/semconv v0.105.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.35.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/sdk v1.35.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect + golang.org/x/time v0.11.0 // indirect + golang.org/x/tools v0.32.0 // indirect + golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect + golang.zx2c4.com/wireguard v0.0.0-20211209221555-9c9e7e272434 // indirect + google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + gopkg.in/fatih/pool.v2 v2.0.0 // indirect + gopkg.in/fsnotify.v1 v1.4.7 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/sourcemap.v1 v1.0.5 // indirect + gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + honnef.co/go/tools v0.2.2 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect + k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e // indirect + modernc.org/libc v1.62.1 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.9.1 // indirect + sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..bcc4449 --- /dev/null +++ b/go.sum @@ -0,0 +1,3497 @@ +cel.dev/expr v0.23.1 h1:K4KOtPCJQjVggkARsjG9RWXP6O4R73aHeJMa/dmCQQg= +cel.dev/expr v0.23.1/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go v0.121.0 h1:pgfwva8nGw7vivjZiRfrmglGWiCJBP+0OmDpenG/Fwg= +cloud.google.com/go v0.121.0/go.mod h1:rS7Kytwheu/y9buoDmu5EIpMMCI4Mb8ND4aeN4Vwj7Q= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= +cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= +cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= +cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= +cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= +cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU= +cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= +cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= +cloud.google.com/go/bigquery v1.68.0 h1:F+CPqdcMxZGUDBACzGtOJ1E6E0MWSYcKeFthxnhpYIU= +cloud.google.com/go/bigquery v1.68.0/go.mod h1:1UAksG8IFXJomQV38xUsRB+2m2c1H9U0etvoGHgyhDk= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= +cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= +cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= +cloud.google.com/go/datacatalog v1.26.0 h1:eFgygb3DTufTWWUB8ARk+dSuXz+aefNJXTlkWlQcWwE= +cloud.google.com/go/datacatalog v1.26.0/go.mod h1:bLN2HLBAwB3kLTFT5ZKLHVPj/weNz6bR0c7nYp0LE14= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= +cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8= +cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= +cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= +cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= +cloud.google.com/go/kms v1.21.2 h1:c/PRUSMNQ8zXrc1sdAUnsenWWaNXN+PzTXfXOcSFdoE= +cloud.google.com/go/kms v1.21.2/go.mod h1:8wkMtHV/9Z8mLXEXr1GK7xPSBdi6knuLXIhqjuWcI6w= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= +cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE= +cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= +cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM= +cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= +cloud.google.com/go/pubsub v1.49.0 h1:5054IkbslnrMCgA2MAEPcsN3Ky+AyMpEZcii/DoySPo= +cloud.google.com/go/pubsub v1.49.0/go.mod h1:K1FswTWP+C1tI/nfi3HQecoVeFvL4HUOB1tdaNXKhUY= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= +cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= +cloud.google.com/go/storage v1.53.0 h1:gg0ERZwL17pJ+Cz3cD2qS60w1WMDnwcm5YPAIQBHUAw= +cloud.google.com/go/storage v1.53.0/go.mod h1:7/eO2a/srr9ImZW9k5uufcNahT2+fPb8w5it1i5boaA= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= +cloud.google.com/go/trace v1.11.3 h1:c+I4YFjxRQjvAhRmSsmjpASUKq88chOX854ied0K/pE= +cloud.google.com/go/trace v1.11.3/go.mod h1:pt7zCYiDSQjC9Y2oqCsh9jF4GStB/hmjrYLsxRR27q8= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8= +code.cloudfoundry.org/clock v1.2.0 h1:1swXS7yPmQmhAdkTb1nJ2c0geOdf4LvibUleNCo2HjA= +code.cloudfoundry.org/clock v1.2.0/go.mod h1:foDbmVp5RIuIGlota90ot4FkJtx5m4+oKoWiVuu2FDg= +collectd.org v0.6.0 h1:wDTcB13Zork7m9bEHmU2sVL4z+hxBmm8EyeMjjxtW7s= +collectd.org v0.6.0/go.mod h1:fXcRZb1qBKshIHJa2T8qBS7Xew/I43iMutefnTdGeYo= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= +github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0= +github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/azure-amqp-common-go/v4 v4.2.0 h1:q/jLx1KJ8xeI8XGfkOWMN9XrXzAfVTkyvCxPvHCjd2I= +github.com/Azure/azure-amqp-common-go/v4 v4.2.0/go.mod h1:GD3m/WPPma+621UaU6KNjKEo5Hl09z86viKwQjTpV0Q= +github.com/Azure/azure-event-hubs-go/v3 v3.6.2 h1:7rNj1/iqS/i3mUKokA2n2eMYO72TB7lO7OmpbKoakKY= +github.com/Azure/azure-event-hubs-go/v3 v3.6.2/go.mod h1:n+ocYr9j2JCLYqUqz9eI+lx/TEAtL/g6rZzyTFSuIpc= +github.com/Azure/azure-kusto-go v0.16.1 h1:vCBWcQghmC1qIErUUgVNWHxGhZVStu1U/hki6iBA14k= +github.com/Azure/azure-kusto-go v0.16.1/go.mod h1:9F2zvXH8B6eWzgI1S4k1ZXAIufnBZ1bv1cW1kB1n3D0= +github.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= +github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= +github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 h1:OVoM452qUFBrX+URdH3VpR299ma4kfom0yB0URYky9g= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0/go.mod h1:kUjrAo8bgEwLeZ/CmHqNl3Z/kPm7y6FKfxxK0izYUg4= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= +github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.3.0 h1:NnE8y/opvxowwNcSNHubQUiSSEhfk3dmooLGAOmPuKs= +github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.3.0/go.mod h1:GhHzPHiiHxZloo6WvKu9X7krmSAKTyGoIwoKMbrKTTA= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA= +github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs v1.3.2 h1:Hr35UBihxDesuh4JDMu/PcgAyIEmvoUl1IPfQnrK0YI= +github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs v1.3.2/go.mod h1:PNuUXQzL07VmB7IR63Qkh0htSOBzmuYYmu2cWVneFDY= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/eventhub/armeventhub v1.3.0 h1:4hGvxD72TluuFIXVr8f4XkKZfqAa7Pj61t0jmQ7+kes= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/eventhub/armeventhub v1.3.0/go.mod h1:TSH7DcFItwAufy0Lz+Ft2cyopExCpxbOxI5SkH4dRNo= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups v1.0.0 h1:pPvTJ1dY0sA35JOeFq6TsY2xj6Z85Yo23Pj4wCCvu4o= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups v1.0.0/go.mod h1:mLfWfj8v3jfWKsL9G4eoBoXVcsqcIUTapmdKy7uGOp0= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor v0.11.0 h1:Ds0KRF8ggpEGg4Vo42oX1cIt/IfOhHWJBikksZbVxeg= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor v0.11.0/go.mod h1:jj6P8ybImR+5topJ+eH6fgcemSFBmU6/6bFF8KkwuDI= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 h1:PiSrjRPpkQNjrM8H0WwKMnZUdu1RGMtd/LdGKUrOo+c= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0/go.mod h1:oDrbWx4ewMylP7xHivfgixbfGBT6APAwsSoHRKotnIc= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0 h1:UXT0o77lXQrikd1kgwIPQOUect7EoR/+sbP4wQKdzxM= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0/go.mod h1:cTvi54pg19DoT07ekoeMgE/taAwNtCShVeZqA+Iv2xI= +github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.4.0 h1:mJVYrRyo7/ISs3MLMHphqssqbS1vLJ3uiwo1+fY8OUQ= +github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.4.0/go.mod h1:QXy84HaR0FHLPWaGQDBrZZbdCPTshwGl3gQ64uR/Zrc= +github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue v1.0.1 h1:qvrrnQ2mIjwY7IVlQuNB0ma43Nr74+9ZTZJ60KlmlV4= +github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue v1.0.1/go.mod h1:FkF/Az07vR3S4sBdjCuisznWfFWOD8u6Ibm/g/oyDAk= +github.com/Azure/azure-storage-queue-go v0.0.0-20230531184854-c06a8eff66fe h1:HGuouUM1533rBXmMtR7qh5pYNSSjUZG90b/MgJAnb/A= +github.com/Azure/azure-storage-queue-go v0.0.0-20230531184854-c06a8eff66fe/go.mod h1:K6am8mT+5iFXgingS9LUc7TmbsW6XBw3nxaRyaMyWc8= +github.com/Azure/go-amqp v1.4.0 h1:Xj3caqi4comOF/L1Uc5iuBxR/pB6KumejC01YQOqOR4= +github.com/Azure/go-amqp v1.4.0/go.mod h1:vZAogwdrkbyK3Mla8m/CxSc/aKdnTZ4IbPxl51Y5WZE= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA= +github.com/Azure/go-autorest/autorest v0.11.30 h1:iaZ1RGz/ALZtN5eq4Nr1SOFSlf2E4pDI3Tcsl+dZPVE= +github.com/Azure/go-autorest/autorest v0.11.30/go.mod h1:t1kpPIOpIVX7annvothKvb0stsrXa37i7b+xpmBW8Fs= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk= +github.com/Azure/go-autorest/autorest/adal v0.9.24 h1:BHZfgGsGwdkHDyZdtQRQk1WeUdW0m2WPAwuHZwUi5i4= +github.com/Azure/go-autorest/autorest/adal v0.9.24/go.mod h1:7T1+g0PYFmACYW5LlG2fcoPiPlFHjClyRGL7dRlP5c8= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 h1:Ov8avRZi2vmrE2JcXw+tu5K/yB41r7xK9GZDiBF7NdM= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.13/go.mod h1:5BAVfWLWXihP47vYrPuBKKf4cS0bXI+KM9Qx6ETDJYo= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 h1:w77/uPk80ZET2F+AfQExZyEWtn+0Rk/uw17m9fv5Ajc= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= +github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= +github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= +github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac= +github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/ClickHouse/ch-go v0.65.1 h1:SLuxmLl5Mjj44/XbINsK2HFvzqup0s6rwKLFH347ZhU= +github.com/ClickHouse/ch-go v0.65.1/go.mod h1:bsodgURwmrkvkBe5jw1qnGDgyITsYErfONKAHn05nv4= +github.com/ClickHouse/clickhouse-go/v2 v2.34.0 h1:Y4rqkdrRHgExvC4o/NTbLdY5LFQ3LHS77/RNFxFX3Co= +github.com/ClickHouse/clickhouse-go/v2 v2.34.0/go.mod h1:yioSINoRLVZkLyDzdMXPLRIqhDvel8iLBlwh6Iefso8= +github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= +github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/Files-com/files-sdk-go/v3 v3.2.97 h1:c+mQoiES/21JrHDAxJLCYICJO+bu8Clv0ZDNZe7Ndyk= +github.com/Files-com/files-sdk-go/v3 v3.2.97/go.mod h1:Y/bCHoPJNPKz2hw1ADXjQXJP378HODwK+g/5SR2gqfU= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 h1:fYE9p3esPxA/C0rQ0AHhP0drtPXDRhaWiwg1DPqO7IU= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0 h1:OqVGm6Ei3x5+yZmSJG1Mh2NwHvpVmZ08CB5qJhT9Nuk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0/go.mod h1:SZiPHWGOOk3bl8tkevxkoiwPgsIl6CwrWcbwjfHZpdM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 h1:6/0iUd0xrnX7qt+mLNRwg5c0PGv8wpE8K90ryANQwMI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0= +github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/IBM/nzgo/v12 v12.0.9 h1:SwzYFU5ooXsTZsQhU6OsbUhs/fQyLvCtlJYSEZ58mN0= +github.com/IBM/nzgo/v12 v12.0.9/go.mod h1:4pvfEkfsrAdqlljsp8HNwv/uzNKy2fzoXBB1aRIssJg= +github.com/IBM/sarama v1.45.1 h1:nY30XqYpqyXOXSNoe2XCgjj9jklGM1Ye94ierUb1jQ0= +github.com/IBM/sarama v1.45.1/go.mod h1:qifDhA3VWSrQ1TjSMyxDl3nYL3oX2C83u+G6L79sq4w= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= +github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= +github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd h1:nzE1YQBdx1bq9IlZinHa+HVffy+NmVRoKr+wHN8fpLE= +github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd/go.mod h1:C8yoIfvESpM3GD07OCHU7fqI7lhwyZ2Td1rbNbTAhnc= +github.com/Mellanox/rdmamap v1.1.0 h1:A/W1wAXw+6vm58f3VklrIylgV+eDJlPVIMaIKuxgUT4= +github.com/Mellanox/rdmamap v1.1.0/go.mod h1:fN+/V9lf10ABnDCwTaXRjeeWijLt2iVLETnK+sx/LY8= +github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PaesslerAG/gval v1.2.4 h1:rhX7MpjJlcxYwL2eTTYIOBUyEKZ+A96T9vQySWkVUiU= +github.com/PaesslerAG/gval v1.2.4/go.mod h1:XRFLwvmkTEdYziLdaCeCa5ImcGVrfQbeNUbVR+C6xac= +github.com/PaesslerAG/jsonpath v0.1.0 h1:gADYeifvlqK3R3i2cR5B4DGgxLXIPb3TRTH1mGi0jPI= +github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8= +github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs69zUkSzubzjBbL+cmOXgnmt9Fyd9ug= +github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo= +github.com/ProtonMail/gluon v0.17.1-0.20230724134000-308be39be96e h1:lCsqUUACrcMC83lg5rTo9Y0PnPItE61JSfvMyIcANwk= +github.com/ProtonMail/gluon v0.17.1-0.20230724134000-308be39be96e/go.mod h1:Og5/Dz1MiGpCJn51XujZwxiLG7WzvvjE5PRpZBQmAHo= +github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= +github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k= +github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw= +github.com/ProtonMail/go-srp v0.0.7 h1:Sos3Qk+th4tQR64vsxGIxYpN3rdnG9Wf9K4ZloC1JrI= +github.com/ProtonMail/go-srp v0.0.7/go.mod h1:giCp+7qRnMIcCvI6V6U3S1lDDXDQYx2ewJ6F/9wdlJk= +github.com/ProtonMail/gopenpgp/v2 v2.7.4 h1:Vz/8+HViFFnf2A6XX8JOvZMrA6F5puwNvvF21O1mRlo= +github.com/ProtonMail/gopenpgp/v2 v2.7.4/go.mod h1:IhkNEDaxec6NyzSI0PlxapinnwPVIESk8/76da3Ct3g= +github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= +github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= +github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= +github.com/SAP/go-hdb v1.13.6 h1:N4sP8/iYhQo2kAdm4R8h+b9JxKtGViTuxIu3do9Hzck= +github.com/SAP/go-hdb v1.13.6/go.mod h1:VOjW70GQ9fKstjYpOuzmWg0dFZ5iIwFeV0k4LH5PJcw= +github.com/aalpar/deheap v0.0.0-20210914013432-0cc84d79dec3 h1:hhdWprfSpFbN7lz3W1gM40vOgvSh1WCSMxYD6gGB4Hs= +github.com/aalpar/deheap v0.0.0-20210914013432-0cc84d79dec3/go.mod h1:XaUnRxSCYgL3kkgX0QHIV0D+znljPIDImxlv2kbGv0Y= +github.com/abbot/go-http-auth v0.4.0 h1:QjmvZ5gSC7jm3Zg54DqWE/T5m1t2AfDu6QlXJT0EVT0= +github.com/abbot/go-http-auth v0.4.0/go.mod h1:Cz6ARTIzApMJDzh5bRMSUou6UMSp0IEXg9km/ci7TJM= +github.com/aerospike/aerospike-client-go/v5 v5.11.0 h1:z3ZmDSm3I10VMXXIIrsFCFq3IenwFqTCnLNyvnFVzrk= +github.com/aerospike/aerospike-client-go/v5 v5.11.0/go.mod h1:e/zYeIoBg9We63fLKa+h+198+fT1GdoLfKa+Pu4QSpg= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= +github.com/alecthomas/go-thrift v0.0.0-20170109061633-7914173639b2/go.mod h1:CxCgO+NdpMdi9SsTlGbc0W+/UNxO3I0AabOEJZ3w61w= +github.com/alecthomas/kong v0.2.1/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI= +github.com/alecthomas/participle v0.4.1 h1:P2PJWzwrSpuCWXKnzqvw0b0phSfH1kJo4p2HvLynVsI= +github.com/alecthomas/participle v0.4.1/go.mod h1:T8u4bQOSMwrkTWOSyt8/jSFPEnRtd0FKFMjVfYBlqPs= +github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= +github.com/alecthomas/repr v0.0.0-20210301060118-828286944d6a/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 h1:t3eaIm0rUkzbrIewtiFmMK5RXHej2XnoXNhxVsAYUfg= +github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= +github.com/alitto/pond v1.9.2 h1:9Qb75z/scEZVCoSU+osVmQ0I0JOeLfdTDafrbcJ8CLs= +github.com/alitto/pond v1.9.2/go.mod h1:xQn3P/sHTYcU/1BR3i86IGIrilcrGC2LiS+E2+CJWsI= +github.com/aliyun/alibaba-cloud-sdk-go v1.63.107 h1:qagvUyrgOnBIlVRQWOyCZGVKUIYbMBdGdJ104vBpRFU= +github.com/aliyun/alibaba-cloud-sdk-go v1.63.107/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= +github.com/amir/raidman v0.0.0-20170415203553-1ccc43bfb9c9 h1:FXrPTd8Rdlc94dKccl7KPmdmIbVh/OjelJ8/vgMRzcQ= +github.com/amir/raidman v0.0.0-20170415203553-1ccc43bfb9c9/go.mod h1:eliMa/PW+RDr2QLWRmLH1R1ZA4RInpmvOzDDXtaIZkc= +github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= +github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= +github.com/antchfx/jsonquery v1.3.6 h1:TaSfeAh7n6T11I74bsZ1FswreIfrbJ0X+OyLflx6mx4= +github.com/antchfx/jsonquery v1.3.6/go.mod h1:fGzSGJn9Y826Qd3pC8Wx45avuUwpkePsACQJYy+58BU= +github.com/antchfx/xmlquery v1.4.4 h1:mxMEkdYP3pjKSftxss4nUHfjBhnMk4imGoR96FRY2dg= +github.com/antchfx/xmlquery v1.4.4/go.mod h1:AEPEEPYE9GnA2mj5Ur2L5Q5/2PycJ0N9Fusrx9b12fc= +github.com/antchfx/xpath v1.3.2/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= +github.com/antchfx/xpath v1.3.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= +github.com/antchfx/xpath v1.3.4 h1:1ixrW1VnXd4HurCj7qnqnR0jo14g8JMe20Fshg1Vgz4= +github.com/antchfx/xpath v1.3.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antithesishq/antithesis-sdk-go v0.4.3-default-no-op h1:+OSa/t11TFhqfrX0EOSqQBDJ0YlpmK0rDSiB19dg9M0= +github.com/antithesishq/antithesis-sdk-go v0.4.3-default-no-op/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= +github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= +github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= +github.com/apache/arrow-go/v18 v18.3.0 h1:Xq4A6dZj9Nu33sqZibzn012LNnewkTUlfKVUFD/RX/I= +github.com/apache/arrow-go/v18 v18.3.0/go.mod h1:eEM1DnUTHhgGAjf/ChvOAQbUQ+EPohtDrArffvUjPg8= +github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= +github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= +github.com/apache/arrow/go/v15 v15.0.2 h1:60IliRbiyTWCWjERBCkO1W4Qun9svcYoZrSLcyOsMLE= +github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA= +github.com/apache/iotdb-client-go v1.3.4 h1:F5vEGqXLoyrODm7ACd9QLgcjEz08s268GI4Zqn7dTa8= +github.com/apache/iotdb-client-go v1.3.4/go.mod h1:3D6QYkqRmASS/4HsjU+U/3fscyc5M9xKRfywZsKuoZY= +github.com/apache/thrift v0.15.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE= +github.com/apache/thrift v0.21.0/go.mod h1:W1H8aR/QRtYNvrPeFXBtobyRkd0/YVhTc6i07XIAgDw= +github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= +github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= +github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc h1:LoL75er+LKDHDUfU5tRvFwxH0LjPpZN8OoG8Ll+liGU= +github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc/go.mod h1:w648aMHEgFYS6xb0KVMMtZ2uMeemhiKCuD2vj6gY52A= +github.com/aristanetworks/glog v0.0.0-20191112221043-67e8567f59f3 h1:Bmjk+DjIi3tTAU0wxGaFbfjGUqlxxSXARq9A96Kgoos= +github.com/aristanetworks/glog v0.0.0-20191112221043-67e8567f59f3/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA= +github.com/aristanetworks/goarista v0.0.0-20190325233358-a123909ec740 h1:FD4/ikKOFxwP8muWDypbmBWc634+YcAs3eBrYAmRdZY= +github.com/aristanetworks/goarista v0.0.0-20190325233358-a123909ec740/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/awnumar/memcall v0.3.0 h1:8b/3Sptrtgejj2kLgL6M5F2r4OzTf19CTllO+gIXUg8= +github.com/awnumar/memcall v0.3.0/go.mod h1:8xOx1YbfyuCg3Fy6TO8DK0kZUua3V42/goA5Ru47E8w= +github.com/awnumar/memguard v0.22.5 h1:PH7sbUVERS5DdXh3+mLo8FDcl1eIeVjJVYMnyuYpvuI= +github.com/awnumar/memguard v0.22.5/go.mod h1:+APmZGThMBWjnMlKiSM1X7MVpbIVewen2MTkqWkA/zE= +github.com/aws/aws-sdk-go v1.29.11/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg= +github.com/aws/aws-sdk-go v1.44.263/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= +github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 h1:zAybnyUQXIZ5mok5Jqwlf58/TFE7uvd3IAsa1aF9cXs= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10/go.mod h1:qqvMj6gHLR/EXWZw4ZbqlPbQUyenf4h82UQUlKc+l14= +github.com/aws/aws-sdk-go-v2/config v1.18.25/go.mod h1:dZnYpD5wTW/dQF0rRNLVypB396zWCcPiBIvdvSWHEg4= +github.com/aws/aws-sdk-go-v2/config v1.29.14 h1:f+eEi/2cKCg9pqKBoAIwRGzVb70MRKqWX4dg1BDcSJM= +github.com/aws/aws-sdk-go-v2/config v1.29.14/go.mod h1:wVPHWcIFv3WO89w0rE10gzf17ZYy+UVS1Geq8Iei34g= +github.com/aws/aws-sdk-go-v2/credentials v1.13.24/go.mod h1:jYPYi99wUOPIFi0rhiOvXeSEReVOzBqFNOX5bXYoG2o= +github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.67/go.mod h1:p3C44m+cfnbv763s52gCqrjaqyPikj9Sg47kUVaNZQQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3/go.mod h1:4Q0UFP0YJf0NrsEuEYHpM9fTSEVnD16Z3uyEF7J9JGM= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.43 h1:iLdpkYZ4cXIQMO7ud+cqMWR1xK5ESbt1rvN77tRi1BY= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.43/go.mod h1:OgbsKPAswXDd5kxnR4vZov69p3oYjbvUyIRBAAV0y9o= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34/go.mod h1:Etz2dj6UHYuw+Xw830KfzCfWGMzqvUTCjUj5b76GVDc= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.25 h1:r67ps7oHCYnflpgDy2LZU0MAQtQbYIOqNNnqGO6xQkE= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.25/go.mod h1:GrGY+Q4fIokYLtjCVB/aFfCVL6hhGUFl8inD18fDalE= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.44.3 h1:sTFYiNh6kB1m+HODmfCAXgx7A54tsZVK5xbUlE7V6as= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.44.3/go.mod h1:HJlcOk+S/wjJuR/8jPa8GhnEKdKqqiQ5wjsE1PjuO1o= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.49.0 h1:9ZzkbHkNpjBKx6r9GlskIXTB8Nfvp0PSlKyIuWjY7Cg= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.49.0/go.mod h1:uo14VBn5cNk/BPGTPz3kyLBxgpgOObgO8lmz+H7Z4Ck= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.43.1 h1:YYjNTAyPL0425ECmq6Xm48NSXdT6hDVQmLOJZxyhNTM= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.43.1/go.mod h1:yYaWRnVSPyAmexW5t7G3TcuYoalYfT+xQwzWsvtUQ7M= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.218.0 h1:QPYsTfcPpPhkF+37pxLcl3xbQz2SRxsShQNB6VCkvLo= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.218.0/go.mod h1:ouvGEfHbLaIlWwpDpOVWPWR+YwO0HDv3vm5tYLq8ImY= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.6 h1:HCpPsWqmYQieU7SS6E9HXfdAMSud0pteVXieJmcpIRI= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.6/go.mod h1:ngUiVRCco++u+soRRVBIvBZxSMMvOVMXA4PJ36JLfSw= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15 h1:M1R1rud7HzDrfCdlBQ7NjnRsDNEhXO/vGhuD189Ggmk= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15/go.mod h1:uvFKBSq9yMPV4LGAi7N4awn4tLY+hKE35f8THes2mzQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27/go.mod h1:EOwBD4J4S5qYszS5/3DpkejfuK+Z5/1uzICfPaZLtqw= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.6 h1:BbGDtTi0T1DYlmjBiCr/le3wzhA37O8QTC5/Ab8+EXk= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.6/go.mod h1:hLMJt7Q8ePgViKupeymbqI0la+t9/iYFBjxQCFwuAwI= +github.com/aws/aws-sdk-go-v2/service/kinesis v1.35.0 h1:Y8ONhfuFKHfx+gvgKbrsN8lOgNCHcnyHRLldRmhaI/M= +github.com/aws/aws-sdk-go-v2/service/kinesis v1.35.0/go.mod h1:dJngkoVMrq0K7QvRkdRZYM4NUp6cdWa2GBdpm8zoY8U= +github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0 h1:nyuzXooUNJexRT0Oy0UQY6AhOzxPxhtt4DcBIHyCnmw= +github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0/go.mod h1:sT/iQz8JK3u/5gZkT+Hmr7GzVZehUMkRZpOaAwYXeGY= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.10/go.mod h1:ouy2P4z6sJN70fR3ka3wD3Ro3KezSxU6eKGQI2+2fjI= +github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8= +github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10/go.mod h1:AFvkxc8xfBe8XA+5St5XIHHrQQtkxqrRincx4hmMHOk= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs= +github.com/aws/aws-sdk-go-v2/service/sts v1.19.0/go.mod h1:BgQOMsg8av8jset59jelyPW7NoZcZXLVpDsXunGDrk8= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 h1:1XuUZ8mYJw9B6lzAkXhqHlJd/XvaX32evhproijJEZY= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.19/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4= +github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.31.0 h1:trJCeA/Lz3fBIp/0nYbB2SnH9XIlCEm1i5DbmSP+rh4= +github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.31.0/go.mod h1:ewPArLDYLkZVKFTkE5dwPk1i6AS3dVWIZ0UYdQVeYAE= +github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k= +github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-hostpool v0.1.0 h1:XKmsF6k5el6xHG3WPJ8U0Ku/ye7njX7W81Ng7O2ioR0= +github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blues/jsonata-go v1.5.4 h1:XCsXaVVMrt4lcpKeJw6mNJHqQpWU751cnHdCFUq3xd8= +github.com/blues/jsonata-go v1.5.4/go.mod h1:uns2jymDrnI7y+UFYCqsRTEiAH22GyHnNXrkupAVFWI= +github.com/bmatcuk/doublestar v1.1.1 h1:YroD6BJCZBYx06yYFEWvUuKVWQn3vLLQAVmDmvTSaiQ= +github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= +github.com/bmatcuk/doublestar/v3 v3.0.0 h1:TQtVPlDnAYwcrVNB2JiGuMc++H5qzWZd9PhkNo5WyHI= +github.com/bmatcuk/doublestar/v3 v3.0.0/go.mod h1:6PcTVMw80pCY1RVuoqu3V++99uQB3vsSYKPTd8AWA0k= +github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38= +github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boschrexroth/ctrlx-datalayer-golang v1.3.1 h1:7Se/SKFSyMfJh23QlebwmFJWku6ZAKNOgAWgOPWTfH0= +github.com/boschrexroth/ctrlx-datalayer-golang v1.3.1/go.mod h1:i0ex6o3HhWHDSS0KEmRuHZOk3FVdJamzyk+tp3qmxkg= +github.com/bradenaw/juniper v0.15.2 h1:0JdjBGEF2jP1pOxmlNIrPhAoQN7Ng5IMAY5D0PHMW4U= +github.com/bradenaw/juniper v0.15.2/go.mod h1:UX4FX57kVSaDp4TPqvSjkAAewmRFAfXf27BOs5z9dq8= +github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8= +github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og= +github.com/brutella/dnssd v1.2.14 h1:qLpTnRTm5peo2jA30hqMIbCuWn8x3sFg3e9o9ODOobw= +github.com/brutella/dnssd v1.2.14/go.mod h1:tG4GE8orv6+irE5rdsNgb6MJSxm6cyMUKdC5jmD22gk= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/buengese/sgzip v0.1.1 h1:ry+T8l1mlmiWEsDrH/YHZnCVWD2S3im1KLsyO+8ZmTU= +github.com/buengese/sgzip v0.1.1/go.mod h1:i5ZiXGF3fhV7gL1xaRRL1nDnmpNj0X061FQzOS8VMas= +github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= +github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= +github.com/caio/go-tdigest v3.1.0+incompatible h1:uoVMJ3Q5lXmVLCCqaMGHLBWnbGoN6Lpu7OAUPR60cds= +github.com/caio/go-tdigest v3.1.0+incompatible/go.mod h1:sHQM/ubZStBUmF1WbB8FAm8q9GjDajLC5T7ydxE3JHI= +github.com/caio/go-tdigest/v4 v4.0.1 h1:sx4ZxjmIEcLROUPs2j1BGe2WhOtHD6VSe6NNbBdKYh4= +github.com/caio/go-tdigest/v4 v4.0.1/go.mod h1:Wsa+f0EZnV2gShdj1adgl0tQSoXRxtM0QioTgukFw8U= +github.com/calebcase/tmpfile v1.0.3 h1:BZrOWZ79gJqQ3XbAQlihYZf/YCV0H4KPIdM5K5oMpJo= +github.com/calebcase/tmpfile v1.0.3/go.mod h1:UAUc01aHeC+pudPagY/lWvt2qS9ZO5Zzof6/tIUzqeI= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= +github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chilts/sid v0.0.0-20190607042430-660e94789ec9 h1:z0uK8UQqjMVYzvk4tiiu3obv2B44+XBsvgEJREQfnO8= +github.com/chilts/sid v0.0.0-20190607042430-660e94789ec9/go.mod h1:Jl2neWsQaDanWORdqZ4emBl50J4/aRBBS4FyyG9/PFo= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/cisco-ie/nx-telemetry-proto v0.0.0-20230117155933-f64c045c77df h1:GmrltUp5Qf5XhT+LmqMDizsgm/6VHTSxPWRdrq21yRo= +github.com/cisco-ie/nx-telemetry-proto v0.0.0-20230117155933-f64c045c77df/go.mod h1:rJDd05J5hqWVU9MjJ+5jw1CuLn/jRhvU0xtFEzzqjwM= +github.com/clarify/clarify-go v0.4.0 h1:t03lAE1fs6IBtrLhSC5ED/rJt0N4cDYhEfdcfSsfkf8= +github.com/clarify/clarify-go v0.4.0/go.mod h1:OTg3S1qDSzKnFG2igTQTZ5xiDUlGj6NmQJV15SMOmQY= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudevents/sdk-go/v2 v2.16.0 h1:wnunjgiLQCfYlyo+E4+mFlZtAh7pKn7vT8MMD3lSwCg= +github.com/cloudevents/sdk-go/v2 v2.16.0/go.mod h1:5YWqklyhDSmGzBK/JENKKXdulbPq0JFf3c/KEnMLqgg= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudinary/cloudinary-go/v2 v2.9.0 h1:8C76QklmuV4qmKAC7cUnu9D68X9kCkFMuLspPikECCo= +github.com/cloudinary/cloudinary-go/v2 v2.9.0/go.mod h1:ireC4gqVetsjVhYlwjUJwKTbZuWjEIynbR9zQTlqsvo= +github.com/cloudsoda/go-smb2 v0.0.0-20241223203758-52b943b88fd6 h1:mLY/79N73URZ2J/oRKTxmfhCgxThzBmjQ6XOjX5tYjI= +github.com/cloudsoda/go-smb2 v0.0.0-20241223203758-52b943b88fd6/go.mod h1:0aLYPsmguHbok591y6hI5yAqU0drbUzrPEO10ZpgTTw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 h1:Om6kYQYDUk5wWbT0t0q6pvyM49i9XZAv9dDrkDA7gjk= +github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE= +github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= +github.com/colinmarc/hdfs/v2 v2.4.0 h1:v6R8oBx/Wu9fHpdPoJJjpGSUxo8NhHIwrwsfhFvU9W0= +github.com/colinmarc/hdfs/v2 v2.4.0/go.mod h1:0NAO+/3knbMx6+5pCv+Hcbaz4xn/Zzbn9+WIib2rKVI= +github.com/compose-spec/compose-go v1.20.2 h1:u/yfZHn4EaHGdidrZycWpxXgFffjYULlTbRfJ51ykjQ= +github.com/compose-spec/compose-go v1.20.2/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/coocood/freecache v1.2.4 h1:UdR6Yz/X1HW4fZOuH0Z94KwG851GWOSknua5VUbb/5M= +github.com/coocood/freecache v1.2.4/go.mod h1:RBUWa/Cy+OHdfTGFEhEuE1pMCMX51Ncizj7rthiQ3vk= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/couchbase/go-couchbase v0.1.1 h1:ClFXELcKj/ojyoTYbsY34QUrrYCBi/1G749sXSCkdhk= +github.com/couchbase/go-couchbase v0.1.1/go.mod h1:+/bddYDxXsf9qt0xpDUtRR47A2GjaXmGGAqQ/k3GJ8A= +github.com/couchbase/gomemcached v0.1.3 h1:HIc5qMYNbuhB7zNaiEtj61DCYkquAwrQlf64q7JzdEY= +github.com/couchbase/gomemcached v0.1.3/go.mod h1:mxliKQxOv84gQ0bJWbI+w9Wxdpt9HjDvgW9MjCym5Vo= +github.com/couchbase/goutils v0.1.0 h1:0WLlKJilu7IBm98T8nS9+J36lBFVLRUSIUtyD/uWpAE= +github.com/couchbase/goutils v0.1.0/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk= +github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= +github.com/cronokirby/saferith v0.33.0 h1:TgoQlfsD4LIwx71+ChfRcIpjkw+RPOapDEVxa+LhwLo= +github.com/cronokirby/saferith v0.33.0/go.mod h1:QKJhjoqUtBsXCAVEjw38mFqoi7DebT7kthcD7UzbnoA= +github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0= +github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8= +github.com/datadope-io/go-zabbix/v2 v2.0.1 h1:kGlyzfFqbwhMph4Mo0hpYxxBHI14eHuV5TVy+7uNonE= +github.com/datadope-io/go-zabbix/v2 v2.0.1/go.mod h1:hRbQWszykTUPoR6g5fJXfNwPFZpP3nDNSZ9HrEKuKCM= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/devigned/tab v0.1.1 h1:3mD6Kb1mUOYeLpJvTVSDwSg5ZsfSxfvxGRTxRsJsITA= +github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/digitalocean/go-libvirt v0.0.0-20250417173424-a6a66ef779d6 h1:jk2z9emvvDmaTwTdVOvQCK3POtH6+fEvWUtqMBjvnq0= +github.com/digitalocean/go-libvirt v0.0.0-20250417173424-a6a66ef779d6/go.mod h1:vumyuXRJJvjCdabRsu/BvoCirqGHC5bakkC9G0V3Mgw= +github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= +github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= +github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswggs8AdFmXQw51I= +github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dropbox/dropbox-sdk-go-unofficial/v6 v6.0.5 h1:FT+t0UEDykcor4y3dMVKXIiWJETBpRgERYTGlmMd7HU= +github.com/dropbox/dropbox-sdk-go-unofficial/v6 v6.0.5/go.mod h1:rSS3kM9XMzSQ6pw91Qgd6yB5jdt70N4OdtrAf74As5M= +github.com/dropbox/godropbox v0.0.0-20180512210157-31879d3884b9 h1:NAvZb7gqQfLSNBPzVsvI7eZMosXtg2g2kxXrei90CtU= +github.com/dropbox/godropbox v0.0.0-20180512210157-31879d3884b9/go.mod h1:glr97hP/JuXb+WMYCizc4PIFuzw1lCR97mwbe1VVXhQ= +github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA2EjTY= +github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/dynatrace-oss/dynatrace-metric-utils-go v0.5.0 h1:wHGPJSXvwKQVf/XfhjUPyrhpcPKWNy8F3ikH+eiwoBg= +github.com/dynatrace-oss/dynatrace-metric-utils-go v0.5.0/go.mod h1:PseHFo8Leko7J4A/TfZ6kkHdkzKBLUta6hRZR/OEbbc= +github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA= +github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= +github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws= +github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc= +github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/echlebek/crock v1.0.1 h1:KbzamClMIfVIkkjq/GTXf+N16KylYBpiaTitO3f1ujg= +github.com/echlebek/crock v1.0.1/go.mod h1:/kvwHRX3ZXHj/kHWJkjXDmzzRow54EJuHtQ/PapL/HI= +github.com/echlebek/timeproxy v1.0.0 h1:V41/v8tmmMDNMA2GrBPI45nlXb3F7+OY+nJz1BqKsCk= +github.com/echlebek/timeproxy v1.0.0/go.mod h1:0dg2Lnb8no/jFwoMQKMTU6iAivgoMptGqSTprhnrRtk= +github.com/eclipse/paho.golang v0.22.0 h1:JhhUngr8TBlyUZDZw/L6WVayPi9qmSmdWeki48i5AVE= +github.com/eclipse/paho.golang v0.22.0/go.mod h1:9ZiYJ93iEfGRJri8tErNeStPKLXIGBHiqbHV74t5pqI= +github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o= +github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk= +github.com/emersion/go-message v0.18.0 h1:7LxAXHRpSeoO/Wom3ZApVZYG7c3d17yCScYce8WiXA8= +github.com/emersion/go-message v0.18.0/go.mod h1:Zi69ACvzaoV/MBnrxfVBPV3xWEuCmC2nEN39oJF4B8A= +github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 h1:IbFBtwoTQyw0fIM5xv1HF+Y+3ZijDR839WMulgxCcUY= +github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U= +github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 h1:ATgqloALX6cHCranzkLb8/zjivwQ9DWWDCQRnxTPfaA= +github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= +github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= +github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= +github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= +github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= +github.com/facebook/time v0.0.0-20240626113945-18207c5d8ddc h1:0VQsg5ZXW9MPUxzemUHW7UBK8gfIO8K+YJGbdv4kBIM= +github.com/facebook/time v0.0.0-20240626113945-18207c5d8ddc/go.mod h1:2UFAomOuD2vAK1x68czUtCVjAqmyWCEnAXOlmGqf+G0= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= +github.com/facebookgo/stackerr v0.0.0-20150612192056-c2fcf88613f4 h1:fP04zlkPjAGpsduG7xN3rRkxjAqkJaIQnnkNYYw/pAk= +github.com/facebookgo/stackerr v0.0.0-20150612192056-c2fcf88613f4/go.mod h1:SBHk9aNQtiw4R4bEuzHjVmZikkUKCnO1v3lPQ21HZGk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/flynn/noise v1.0.1 h1:vPp/jdQLXC6ppsXSj/pM3W1BIJ5FEHE2TulSJBpb43Y= +github.com/flynn/noise v1.0.1/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.11.0/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s= +github.com/frankban/quicktest v1.11.2/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU= +github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA= +github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU= +github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w= +github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo= +github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= +github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348 h1:JnrjqG5iR07/8k7NqrLNilRsl3s1EPRQEGvbPyOce68= +github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348/go.mod h1:Czxo/d1g948LtrALAZdL04TL/HnkopquAjxYUuI02bo= +github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= +github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw= +github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg= +github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8= +github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= +github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU= +github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= +github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-redis/redis/v7 v7.4.1 h1:PASvf36gyUpr2zdOUS/9Zqc80GbM+9BDyiJSJDDOrTI= +github.com/go-redis/redis/v7 v7.4.1/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-resty/resty/v2 v2.13.1 h1:x+LHXBI2nMB1vqndymf26quycC4aggYJ7DECYbiz03g= +github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96ORAI6Q7d+0= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU= +github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-stomp/stomp v2.1.4+incompatible h1:D3SheUVDOz9RsjVWkoh/1iCOwD0qWjyeTZMUZ0EXg2Y= +github.com/go-stomp/stomp v2.1.4+incompatible/go.mod h1:VqCtqNZv1226A1/79yh+rMiFUcfY3R109np+7ke4n0c= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/goburrow/modbus v0.1.0 h1:DejRZY73nEM6+bt5JSP6IsFolJ9dVcqxsYbpLbeW/ro= +github.com/goburrow/modbus v0.1.0/go.mod h1:Kx552D5rLIS8E7TyUwQ/UdHEqvX5T8tyiGBTlzMcZBg= +github.com/goburrow/serial v0.1.1-0.20211022031912-bfb69110f8dd h1:qJthTC7IG7e/QYR4i2QHxcDmDdB72FXsaGo4CUQvsPo= +github.com/goburrow/serial v0.1.1-0.20211022031912-bfb69110f8dd/go.mod h1:sAiqG0nRVswsm1C97xsttiYCzSLBmUZ/VSlVLZJ8haA= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid/v5 v5.3.2 h1:2jfO8j3XgSwlz/wHqemAEugfnTlikAYHhnqQ8Xh4fE0= +github.com/gofrs/uuid/v5 v5.3.2/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/geo v0.0.0-20190916061304-5b978397cfec h1:lJwO/92dFXWeXOZdoGXgptLmNLwynMSHUmU6besqtiw= +github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.25.0 h1:jsFw9Fhn+3y2kBbltZR4VEz5xKkcIFRPDnuEzAGv5GY= +github.com/google/cel-go v0.25.0/go.mod h1:hjEb6r5SuOSlhCHmFoLzu8HGCERvIsDAbxDAyNU/MmI= +github.com/google/flatbuffers v1.12.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= +github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= +github.com/google/gnxi v0.0.0-20231026134436-d82d9936af15 h1:EETGSLGKBReUUYZdztSp45EzTE6CHw2qMKIfyPrgp6c= +github.com/google/gnxi v0.0.0-20231026134436-d82d9936af15/go.mod h1:w8XuCWhpJuVsGdFLU9bLN9CBLROXSDp9tO1SFgg2l+4= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II= +github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/go-tpm v0.9.4 h1:awZRf9FwOeTunQmHoDYSHJps3ie6f1UlhS1fOdPEt1I= +github.com/google/go-tpm v0.9.4/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs= +github.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= +github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/protobuf v3.11.4+incompatible/go.mod h1:lUQ9D1ePzbH2PrIS7ob/bjm9HXyH5WHB0Akwh7URreM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= +github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= +github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopacket/gopacket v1.3.1 h1:ZppWyLrOJNZPe5XkdjLbtuTkfQoxQ0xyMJzQCqtqaPU= +github.com/gopacket/gopacket v1.3.1/go.mod h1:3I13qcqSpB2R9fFQg866OOgzylYkZxLTmkvcXhvf6qg= +github.com/gopcua/opcua v0.8.0 h1:nB9vDewEmuXmSQf1C9inCHPblFwsH21FeB2Kk6o6Y7U= +github.com/gopcua/opcua v0.8.0/go.mod h1:Z6aellk0gIzznZd2UX+Syd/hUMBt65gRlTakpGo6se8= +github.com/gophercloud/gophercloud/v2 v2.7.0 h1:o0m4kgVcPgHlcXiWAjoVxGd8QCmvM5VU+YM71pFbn0E= +github.com/gophercloud/gophercloud/v2 v2.7.0/go.mod h1:Ki/ILhYZr/5EPebrPL9Ej+tUg4lqx71/YH2JWVeU+Qk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorcon/rcon v1.4.0 h1:pYwZ8Rhcgfh/LhdPBncecuEo5thoFvPIuMSWovz1FME= +github.com/gorcon/rcon v1.4.0/go.mod h1:M6v6sNmr/NET9YIf+2rq+cIjTBridoy62uzQ58WgC1I= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E= +github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= +github.com/gosnmp/gosnmp v1.40.0 h1:MvSqHZaNnhMKdn5IVhyYzCsVfXV1lgg6ZgLRku7FVcM= +github.com/gosnmp/gosnmp v1.40.0/go.mod h1:CxVS6bXqmWZlafUj9pZUnQX5e4fAltqPcijxWpCitDo= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= +github.com/grid-x/modbus v0.0.0-20240503115206-582f2ab60a18 h1:8V5xRtdD70kGC4/IHqFq+kcBSWr4k6nscAUgWwJ6A5k= +github.com/grid-x/modbus v0.0.0-20240503115206-582f2ab60a18/go.mod h1:WpbUAyptAAi0VAriSRopZa6uhiJOJCTz7KFvgGtNRXc= +github.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa h1:Rsn6ARgNkXrsXJIzhkE4vQr5Gbx2LvtEMv4BJOK4LyU= +github.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa/go.mod h1:kdOd86/VGFWRrtkNwf1MPk0u1gIjc4Y7R2j7nhwc7Rk= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/gwos/tcg/sdk v0.0.0-20240830123415-f8a34bba6358 h1:QmKzhYk6KMjUutu9Sy4DyOkRgj1Dv+iFnea4t8KrCZg= +github.com/gwos/tcg/sdk v0.0.0-20240830123415-f8a34bba6358/go.mod h1:h40FJV0HuULqXSSKf7kfCbOxEcQAD74a5e2LC2+rYiQ= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.32.1 h1:0+osr/3t/aZNAdJX558crU3PEjVrG4x6715aZHRgceE= +github.com/hashicorp/consul/api v1.32.1/go.mod h1:mXUWLnxftwTmDv4W3lzxYCPD199iNLLUyLfLGFJbtl4= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg= +github.com/hashicorp/consul/sdk v0.16.1/go.mod h1:fSXvwxB2hmh1FMZCNl6PwX0Q/1wdWtHJcZ7Ea5tns0s= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= +github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= +github.com/hashicorp/packer-plugin-sdk v0.3.2 h1:4Kqq7B8CRDMbfZmkloyz11t1hfqazJuBbW8ZFo4QlN4= +github.com/hashicorp/packer-plugin-sdk v0.3.2/go.mod h1:XZRvL9kRqJJtB6rf9Lu2zWLJbf2/4ImWXDjp9O9UQGE= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= +github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/henrybear327/Proton-API-Bridge v1.0.0 h1:gjKAaWfKu++77WsZTHg6FUyPC5W0LTKWQciUm8PMZb0= +github.com/henrybear327/Proton-API-Bridge v1.0.0/go.mod h1:gunH16hf6U74W2b9CGDaWRadiLICsoJ6KRkSt53zLts= +github.com/henrybear327/go-proton-api v1.0.0 h1:zYi/IbjLwFAW7ltCeqXneUGJey0TN//Xo851a/BgLXw= +github.com/henrybear327/go-proton-api v1.0.0/go.mod h1:w63MZuzufKcIZ93pwRgiOtxMXYafI8H74D77AxytOBc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/influxdata/influxdb-observability/common v0.5.12 h1:4YwZ+vsodz6VfoiX+ZqVotmnyCa9vCCPksSBK/WLjBs= +github.com/influxdata/influxdb-observability/common v0.5.12/go.mod h1:u+CABnGO/F1IK51pDlZQroh4+igJNo695XrbLGDBhVc= +github.com/influxdata/influxdb-observability/influx2otel v0.5.12 h1:u0lNE3+63rILk4mtmCYsNyczH/1wEXnM+1aBzBe5akk= +github.com/influxdata/influxdb-observability/influx2otel v0.5.12/go.mod h1:bM407XIJYnrJYJ9Q3q2ytDSOyFhiYmGm0Sz1Qf48RPk= +github.com/influxdata/influxdb-observability/otel2influx v0.5.12 h1:t9gmVOOHbZyEAvIYSoO97Tde1KArVtiYdM0/0Dhmuio= +github.com/influxdata/influxdb-observability/otel2influx v0.5.12/go.mod h1:YGsb8xYfjHvcr2y0+Nj7kOHMTw7fWDbAA4g/qJKkvaU= +github.com/influxdata/line-protocol-corpus v0.0.0-20210519164801-ca6fa5da0184/go.mod h1:03nmhxzZ7Xk2pdG+lmMd7mHDfeVOYFyhOgwO61qWU98= +github.com/influxdata/line-protocol-corpus v0.0.0-20210922080147-aa28ccfb8937 h1:MHJNQ+p99hFATQm6ORoLmpUCF7ovjwEFshs/NHzAbig= +github.com/influxdata/line-protocol-corpus v0.0.0-20210922080147-aa28ccfb8937/go.mod h1:BKR9c0uHSmRgM/se9JhFHtTT7JTO67X23MtKMHtZcpo= +github.com/influxdata/line-protocol/v2 v2.0.0-20210312151457-c52fdecb625a/go.mod h1:6+9Xt5Sq1rWx+glMgxhcg2c0DUaehK+5TDcPZ76GypY= +github.com/influxdata/line-protocol/v2 v2.1.0/go.mod h1:QKw43hdUBg3GTk2iC3iyCxksNj7PX9aUSeYOYE/ceHY= +github.com/influxdata/line-protocol/v2 v2.2.1 h1:EAPkqJ9Km4uAxtMRgUubJyqAr6zgWM0dznKMLRauQRE= +github.com/influxdata/line-protocol/v2 v2.2.1/go.mod h1:DmB3Cnh+3oxmG6LOBIxce4oaL4CPj3OmMPgvauXh+tM= +github.com/influxdata/tail v1.0.1-0.20241014115250-3e0015cb677a h1:IJBVizlP2eArwAurfli2Em5N7pTK1YCbDsdDtnou024= +github.com/influxdata/tail v1.0.1-0.20241014115250-3e0015cb677a/go.mod h1:VeiWgI3qaGdJWust2fP27a6J+koITo/1c/UhxeOxgaM= +github.com/influxdata/toml v0.0.0-20190415235208-270119a8ce65 h1:vvyMtD5LTJc1W9sQKjDkAWdcg0478CszSdzlHtiAXCY= +github.com/influxdata/toml v0.0.0-20190415235208-270119a8ce65/go.mod h1:zApaNFpP/bTpQItGZNNUMISDMDAnTXu9UqJ4yT3ocz8= +github.com/intel/iaevents v1.1.0 h1:FzxMBfXk/apG2EUXUCfaq3gUQ+q+TgZ1HNMjjUILUGE= +github.com/intel/iaevents v1.1.0/go.mod h1:CyUUzXw0lHRCsmyyF7Pwco9Y7NiTNQUUlcJ7RJAazKs= +github.com/intel/powertelemetry v1.0.2 h1:092xOflYu+YXzY3c/fQ2DpK1ePy9q9ulbm5yiNYrVkc= +github.com/intel/powertelemetry v1.0.2/go.mod h1:+PHKI9RElL7J1sTjgg3DGxtscD+IiLNmUzV1MOSCZt4= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= +github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= +github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.14.4 h1:fKuNiCumbKTAIxQwXfB/nsrnkEI6bPJrrSiMKgbJ2j8= +github.com/jackc/pgtype v1.14.4/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= +github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= +github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= +github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= +github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jaegertracing/jaeger v1.47.0 h1:XXxTMO+GxX930gxKWsg90rFr6RswkCRIW0AgWFnTYsg= +github.com/jaegertracing/jaeger v1.47.0/go.mod h1:mHU/OHFML51CijQql4+rLfgPOcIb9MhxOMn+RKQwrJc= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jedib0t/go-pretty/v6 v6.6.7 h1:m+LbHpm0aIAPLzLbMfn8dc3Ht8MW7lsSO4MPItz/Uuo= +github.com/jedib0t/go-pretty/v6 v6.6.7/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU= +github.com/jeremija/gosubmit v0.2.8 h1:mmSITBz9JxVtu8eqbN+zmmwX7Ij2RidQxhcwRVI4wqA= +github.com/jeremija/gosubmit v0.2.8/go.mod h1:Ui+HS073lCFREXBbdfrJzMB57OI/bdxTiLtrDHHhFPI= +github.com/jeremywohl/flatten/v2 v2.0.0-20211013061545-07e4a09fb8e4 h1:eA9wi6ZzpIRobvXkn/S2Lyw1hr2pc71zxzOPl7Xjs4w= +github.com/jeremywohl/flatten/v2 v2.0.0-20211013061545-07e4a09fb8e4/go.mod h1:s9g9Dfls+aEgucKXKW+i8MRZuLXT2MrD/WjYpMnWfOw= +github.com/jlaffaye/ftp v0.2.1-0.20240918233326-1b970516f5d3 h1:ZxO6Qr2GOXPdcW80Mcn3nemvilMPvpWqxrNfK2ZnNNs= +github.com/jlaffaye/ftp v0.2.1-0.20240918233326-1b970516f5d3/go.mod h1:dvLUr/8Fs9a2OBrEnCC5duphbkz/k/mSy5OkXg3PAgI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= +github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= +github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= +github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= +github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= +github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= +github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= +github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= +github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= +github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo= +github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolio/noiseconn v0.0.0-20231127013910-f6d9ecbf1de7 h1:JcltaO1HXM5S2KYOYcKgAV7slU0xPy1OcvrVgn98sRQ= +github.com/jtolio/noiseconn v0.0.0-20231127013910-f6d9ecbf1de7/go.mod h1:MEkhEPFwP3yudWO0lj6vfYpLIB+3eIcuIW+e0AZzUQk= +github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 h1:G+9t9cEtnC9jFiTxyptEKuNIAbiN5ZCQzX2a74lj3xg= +github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004/go.mod h1:KmHnJWQrgEvbuy0vcvj00gtMqbvNn1L+3YUZLK/B92c= +github.com/karrick/godirwalk v1.16.2 h1:eY2INUWoB2ZfpF/kXasyjWJ3Ncuof6qZuNWYZFN3kAI= +github.com/karrick/godirwalk v1.16.2/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= +github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= +github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= +github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= +github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/koofr/go-httpclient v0.0.0-20240520111329-e20f8f203988 h1:CjEMN21Xkr9+zwPmZPaJJw+apzVbjGL5uK/6g9Q2jGU= +github.com/koofr/go-httpclient v0.0.0-20240520111329-e20f8f203988/go.mod h1:/agobYum3uo/8V6yPVnq+R82pyVGCeuWW5arT4Txn8A= +github.com/koofr/go-koofrclient v0.0.0-20221207135200-cbd7fc9ad6a6 h1:FHVoZMOVRA+6/y4yRlbiR3WvsrOcKBd/f64H7YiWR2U= +github.com/koofr/go-koofrclient v0.0.0-20221207135200-cbd7fc9ad6a6/go.mod h1:MRAz4Gsxd+OzrZ0owwrUHc0zLESL+1Y5syqK/sJxK2A= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353 h1:X/79QL0b4YJVO5+OsPH9rF2u428CIrGL/jLmPsoOQQ4= +github.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353/go.mod h1:N0SVk0uhy+E1PZ3C9ctsPRlvOPAFPkCNlcPBDkt0N3U= +github.com/leodido/go-syslog/v4 v4.2.0 h1:A7vpbYxsO4e2E8udaurkLlxP5LDpDbmPMsGnuhb7jVk= +github.com/leodido/go-syslog/v4 v4.2.0/go.mod h1:eJ8rUfDN5OS6dOkCOBYlg2a+hbAg6pJa99QXXgMrd98= +github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b h1:11UHH39z1RhZ5dc4y4r/4koJo6IYFgTRMe/LlwRTEw0= +github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b/go.mod h1:WZxr2/6a/Ar9bMDc2rN/LJrE/hF6bXE4LPyDSIxwAfg= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/linkedin/goavro/v2 v2.13.1 h1:4qZ5M0QzQFDRqccsroJlgOJznqAS/TpdvXg55h429+I= +github.com/linkedin/goavro/v2 v2.13.1/go.mod h1:KXx+erlq+RPlGSPmLF7xGo6SAbh8sCQ53x064+ioxhk= +github.com/logzio/azure-monitor-metrics-receiver v1.1.0 h1:L2LU/jWTOFibZeSKUeEDBdPY6iFL1gkSE3A/9mnk/Ms= +github.com/logzio/azure-monitor-metrics-receiver v1.1.0/go.mod h1:6J/ZJtFGAuv3XvLWOWTefbi1BBHvnawNjUTGcx2qUG4= +github.com/loov/hrtime v1.0.1/go.mod h1:yDY3Pwv2izeY4sq7YcPX/dtLwzg5NU1AxWuWxKwd0p0= +github.com/loov/hrtime v1.0.3/go.mod h1:yDY3Pwv2izeY4sq7YcPX/dtLwzg5NU1AxWuWxKwd0p0= +github.com/loov/hrtime/hrplot v1.0.2/go.mod h1:9t65xYn4d42ntjv40Wt5lbU72/VC5S0zGDgjC8kD5BU= +github.com/loov/plot v0.0.0-20200413101321-e09a6f01d2f5/go.mod h1:gSrhfSMoiPGG0CZ9E66kXjaHxFw0fzJhooyicOnz5z4= +github.com/lpar/date v1.0.0 h1:bq/zVqFTUmsxvd/CylidY4Udqpr9BOFrParoP6p0x/I= +github.com/lpar/date v1.0.0/go.mod h1:KjYe0dDyMQTgpqcUz4LEIeM5VZwhggjVx/V2dtc8NSo= +github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a h1:3Bm7EwfUQUvhNeKIkUct/gl9eod1TcXuj8stxvi/GoI= +github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= +github.com/lxc/incus/v6 v6.12.0 h1:XMjlk5nvRSIqzqj3bsMrM+lu8X84aKBwKEx1e1JC4g8= +github.com/lxc/incus/v6 v6.12.0/go.mod h1:8y7uDdiLvApGJVXh2UIB7SL6SSGPBWT96Sti/2LiToM= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= +github.com/mattn/go-ieproxy v0.0.11 h1:MQ/5BuGSgDAHZOJe6YY80IF2UVCfGkwfo6AeD7HtHYo= +github.com/mattn/go-ieproxy v0.0.11/go.mod h1:/NsJd+kxZBmjMc5hrJCKMbP57B84rvq9BiDRbtO9AS0= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mdlayher/apcupsd v0.0.0-20220319200143-473c7b5f3c6a h1:JOlLsLUQnokTyWWwEvOVoKH3XUl6oDMP8jisO54l6J8= +github.com/mdlayher/apcupsd v0.0.0-20220319200143-473c7b5f3c6a/go.mod h1:960H6oqSawdujauTeLX9BOx+ZdYX0TdG9xE9br5bino= +github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= +github.com/mdlayher/ethtool v0.0.0-20211028163843-288d040e9d60/go.mod h1:aYbhishWc4Ai3I2U4Gaa2n3kHWSwzme6EsG/46HRQbE= +github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= +github.com/mdlayher/genetlink v1.1.0/go.mod h1:1cAHdejIIk9zbWfP3gW30vY1QUlwyuhaqfkyANVVf10= +github.com/mdlayher/genetlink v1.2.0 h1:4yrIkRV5Wfk1WfpWTcoOlGmsWgQj3OtQN9ZsbrE+XtU= +github.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ= +github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= +github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= +github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= +github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= +github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8= +github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= +github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= +github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= +github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= +github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= +github.com/mdlayher/netlink v1.4.2/go.mod h1:13VaingaArGUTUxFLf/iEovKxXji32JAtF858jZYEug= +github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA= +github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= +github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= +github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= +github.com/mdlayher/socket v0.0.0-20211007213009-516dcbdf0267/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g= +github.com/mdlayher/socket v0.0.0-20211102153432-57e3fa563ecb/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g= +github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= +github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= +github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= +github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ= +github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= +github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXdQbCmeMxwc= +github.com/microsoft/ApplicationInsights-Go v0.4.4 h1:G4+H9WNs6ygSCe6sUyxRc2U81TI5Es90b2t/MwX5KqY= +github.com/microsoft/ApplicationInsights-Go v0.4.4/go.mod h1:fKRUseBqkw6bDiXTs3ESTiU/4YTIHsQS4W3fP2ieF4U= +github.com/microsoft/go-mssqldb v1.8.1 h1:/LPVjSb992vTa8CMVvliTMT//UAKj/jpe1xb/jJBjIk= +github.com/microsoft/go-mssqldb v1.8.1/go.mod h1:vp38dT33FGfVotRiTmDo3bFyaHq+p3LektQrjTULowo= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= +github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE= +github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= +github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= +github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 h1:BpfhmLKZf+SjVanKKhCgf3bg+511DmU9eDQTen7LLbY= +github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= +github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= +github.com/moby/ipvs v1.1.0 h1:ONN4pGaZQgAx+1Scz5RvWV4Q7Gb+mvfRh3NsPS+1XQQ= +github.com/moby/ipvs v1.1.0/go.mod h1:4VJMWuf098bsUMmZEiD4Tjk/O7mOn3l1PTD3s4OoYAs= +github.com/moby/moby v24.0.6+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= +github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= +github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= +github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= +github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= +github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= +github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= +github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM= +github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM= +github.com/muhlemmer/httpforwarded v0.1.0 h1:x4DLrzXdliq8mprgUMR0olDvHGkou5BJsK/vWUetyzY= +github.com/muhlemmer/httpforwarded v0.1.0/go.mod h1:yo9czKedo2pdZhoXe+yDkGVbU0TJ0q9oQ90BVoDEtw0= +github.com/multiplay/go-ts3 v1.2.0 h1:LaN6iz9TZjHXxhLwfU0gjUgDxX0Hq7BCbuyuRhYMl3U= +github.com/multiplay/go-ts3 v1.2.0/go.mod h1:OdNmiO3uV++4SldaJDQTIGg8gNAu5MOiccZiAqVqUZA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/nats-io/jwt/v2 v2.7.4 h1:jXFuDDxs/GQjGDZGhNgH4tXzSUK6WQi2rsj4xmsNOtI= +github.com/nats-io/jwt/v2 v2.7.4/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA= +github.com/nats-io/nats-server/v2 v2.11.3 h1:AbGtXxuwjo0gBroLGGr/dE0vf24kTKdRnBq/3z/Fdoc= +github.com/nats-io/nats-server/v2 v2.11.3/go.mod h1:6Z6Fd+JgckqzKig7DYwhgrE7bJ6fypPHnGPND+DqgMY= +github.com/nats-io/nats.go v1.42.0 h1:ynIMupIOvf/ZWH/b2qda6WGKGNSjwOUutTpWRvAmhaM= +github.com/nats-io/nats.go v1.42.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g= +github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0= +github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/ncw/swift/v2 v2.0.3 h1:8R9dmgFIWs+RiVlisCEfiQiik1hjuR0JnOkLxaP9ihg= +github.com/ncw/swift/v2 v2.0.3/go.mod h1:cbAO76/ZwcFrFlHdXPjaqWZ9R7Hdar7HpjRXBfbjigk= +github.com/netsampler/goflow2/v2 v2.2.2 h1:td6BxWc13xC7thXzcHyRJCQTLEY5MRzm7KuBb1E55VM= +github.com/netsampler/goflow2/v2 v2.2.2/go.mod h1:+FYeHV5uv5u0BEza9smuw6hSkwFWqHcimXpfJEJH9Aw= +github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1 h1:6OX5VXMuj2salqNBc41eXKz6K+nV6OB/hhlGnAKCbwU= +github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1/go.mod h1:2kY6OeOxrJ+RIQlVjWDc/pZlT3MIf30prs6drzMfJ6E= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nsqio/go-nsq v1.1.0 h1:PQg+xxiUjA7V+TLdXw7nVrJ5Jbl3sN86EhGCQj4+FYE= +github.com/nsqio/go-nsq v1.1.0/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY= +github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= +github.com/nwaples/tacplus v0.0.3 h1:i3v/BUWWrbKq00BzFDrgcPksUF4HwAWvS8Zk63ezYXg= +github.com/nwaples/tacplus v0.0.3/go.mod h1:y5ZA9N5V2JbmwO766S+ET9zuu5FtL1OtdfBCYrbTIgw= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro= +github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852/go.mod h1:eqOVx5Vwu4gd2mmMZvVZsgIqNSaW3xxRThUJ0k/TPk4= +github.com/olivere/elastic v6.2.37+incompatible h1:UfSGJem5czY+x/LqxgeCBgjDn6St+z8OnsCuxwD3L0U= +github.com/olivere/elastic v6.2.37+incompatible/go.mod h1:J+q1zQJTgAz9woqsbVRqGeB5G1iqDKVBWLNSYW8yfJ8= +github.com/olivere/elastic/v7 v7.0.12/go.mod h1:14rWX28Pnh3qCKYRVnSGXWLf9MbLonYS/4FDCY3LAPo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= +github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= +github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.101.0 h1:TCQYvGS2MKTotOTQDnHUSd4ljEzXRzHXopdv71giKWU= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.101.0/go.mod h1:Nl2d4DSK/IbaWnnBxYyhMNUW6C9sb5/4idVZrSW/5Ps= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.101.0 h1:dVINhi/nne11lG+Xnwuy9t/N4xyaH2Om2EU+5lphCA4= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.101.0/go.mod h1:kjyfpKOuBfkx3UsJQsbQ5eTJM3yQWiRYaYxs47PpxvI= +github.com/openconfig/gnmi v0.0.0-20200414194230-1597cc0f2600/go.mod h1:M/EcuapNQgvzxo1DDXHK4tx3QpYM/uG4l591v33jG2A= +github.com/openconfig/gnmi v0.0.0-20200508230933-d19cebf5e7be/go.mod h1:M/EcuapNQgvzxo1DDXHK4tx3QpYM/uG4l591v33jG2A= +github.com/openconfig/gnmi v0.0.0-20220503232738-6eb133c65a13/go.mod h1:h365Ifq35G6kLZDQlRvrccTt2LKK90VpjZLMNGxJRYc= +github.com/openconfig/gnmi v0.14.1 h1:qKMuFvhIRR2/xxCOsStPQ25aKpbMDdWr3kI+nP9bhMs= +github.com/openconfig/gnmi v0.14.1/go.mod h1:whr6zVq9PCU8mV1D0K9v7Ajd3+swoN6Yam9n8OH3eT0= +github.com/openconfig/goyang v0.0.0-20200115183954-d0a48929f0ea/go.mod h1:dhXaV0JgHJzdrHi2l+w0fZrwArtXL7jEFoiqLEdmkvU= +github.com/openconfig/goyang v0.2.2/go.mod h1:vX61x01Q46AzbZUzG617vWqh/cB+aisc+RrNkXRd3W8= +github.com/openconfig/goyang v1.0.0/go.mod h1:vX61x01Q46AzbZUzG617vWqh/cB+aisc+RrNkXRd3W8= +github.com/openconfig/goyang v1.6.2 h1:LVwwlVIIt4nmwacW67yBsxzP5DhDM94SOEMWod1hEA0= +github.com/openconfig/goyang v1.6.2/go.mod h1:jzlGg+yjRpOcq1Kg6q6cSiLGQK5hrNNMsUx0fFxm4U0= +github.com/openconfig/gribi v0.1.1-0.20210423184541-ce37eb4ba92f/go.mod h1:OoH46A2kV42cIXGyviYmAlGmn6cHjGduyC2+I9d/iVs= +github.com/openconfig/grpctunnel v0.0.0-20210610163803-fde4a9dc048d/go.mod h1:x9tAZ4EwqCQ0jI8D6S8Yhw9Z0ee7/BxWQX0k0Uib5Q8= +github.com/openconfig/ygot v0.6.0/go.mod h1:o30svNf7O0xK+R35tlx95odkDmZWS9JyWWQSmIhqwAs= +github.com/openconfig/ygot v0.10.4/go.mod h1:oCQNdXnv7dWc8scTDgoFkauv1wwplJn5HspHcjlxSAQ= +github.com/openconfig/ygot v0.20.0/go.mod h1:7ZiBFNc4n/1Hkv2v2dAEpxisqDznp0JVpLR13Toe4AY= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/opensearch-project/opensearch-go/v2 v2.3.0 h1:nQIEMr+A92CkhHrZgUhcfsrZjibvB3APXf2a1VwCmMQ= +github.com/opensearch-project/opensearch-go/v2 v2.3.0/go.mod h1:8LDr9FCgUTVoT+5ESjc2+iaZuldqE+23Iq0r1XeNue8= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A= +github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0 h1:uhcF5Jd7rP9DVEL10Siffyepr6SvlKbUsjH5JpNCRi8= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0/go.mod h1:+oCZ5GXXr7KPI/DNOQORPTq5AWHfALJj9c72b0+YsEY= +github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= +github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= +github.com/oracle/oci-go-sdk/v65 v65.80.0 h1:Rr7QLMozd2DfDBKo6AB3DzLYQxAwuOG118+K5AAD5E8= +github.com/oracle/oci-go-sdk/v65 v65.80.0/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0= +github.com/p4lang/p4runtime v1.4.1 h1:YdtDyDReeGEmSvuxqR8iefSTnttRSW5jWJWtpgCSFv4= +github.com/p4lang/p4runtime v1.4.1/go.mod h1:OWAP4Wh9uKGnQjleslObpFE0REP78b5gR1pHyYmvNPQ= +github.com/panjf2000/ants/v2 v2.9.1 h1:Q5vh5xohbsZXGcD6hhszzGqB7jSSc2/CRr3QKIga8Kw= +github.com/panjf2000/ants/v2 v2.9.1/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU= +github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU= +github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY= +github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0 h1:2nosf3P75OZv2/ZO/9Px5ZgZ5gbKrzA3joN1QMfOGMQ= +github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0/go.mod h1:lAVhWwbNaveeJmxrxuSTxMgKpF6DjnuVpn6T8WiBwYQ= +github.com/pborman/ansi v1.0.0 h1:OqjHMhvlSuCCV5JT07yqPuJPQzQl+WXsiZ14gZsqOrQ= +github.com/pborman/ansi v1.0.0/go.mod h1:SgWzwMAx1X/Ez7i90VqF8LRiQtx52pWDiQP+x3iGnzw= +github.com/pborman/getopt v0.0.0-20190409184431-ee0cd42419d3/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= +github.com/pcolladosoto/goslurm v0.1.0 h1:d2KigvDfsIIeVeHHj/pTtajz2T0cHHqhGk9iJWUdGaM= +github.com/pcolladosoto/goslurm v0.1.0/go.mod h1:eLuBFfN/tj4O/HDMrAJXb+3s3rGhdHQVZFcOUV1Sbbo= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14 h1:XeOYlK9W1uCmhjJSsY78Mcuh7MVkNjTzmHx1yBzizSU= +github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14/go.mod h1:jVblp62SafmidSkvWrXyxAme3gaTfEtWwRPGz5cpvHg= +github.com/peterbourgon/ff/v3 v3.3.1/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= +github.com/peterbourgon/unixtransport v0.0.4 h1:UTF0FxXCAglvoZz9jaGPYjEg52DjBLDYGMJvJni6Tfw= +github.com/peterbourgon/unixtransport v0.0.4/go.mod h1:o8aUkOCa8W/BIXpi15uKvbSabjtBh0JhSOJGSfoOhAU= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/pierrec/lz4/v4 v4.0.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= +github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= +github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/transport/v2 v2.2.4 h1:41JJK6DZQYSeVLxILA2+F4ZkKb4Xd/tFJZRFZQ9QAlo= +github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw= +github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA= +github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA= +github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus-community/pro-bing v0.7.0 h1:KFYFbxC2f2Fp6c+TyxbCOEarf7rbnzr9Gw8eIb0RfZA= +github.com/prometheus-community/pro-bing v0.7.0/go.mod h1:Moob9dvlY50Bfq6i88xIwfyw7xLFHH69LUgx9n5zqCE= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= +github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/prometheus v0.54.1 h1:vKuwQNjnYN2/mDoWfHXDhAsz/68q/dQDb+YbcEqU7MQ= +github.com/prometheus/prometheus v0.54.1/go.mod h1:xlLByHhk2g3ycakQGrMaU8K7OySZx98BzeCR99991NY= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8 h1:Y258uzXU/potCYnQd1r6wlAnoMB68BiCkCcCnKx1SH8= +github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8/go.mod h1:bSJjRokAHHOhA+XFxplld8w2R/dXLH7Z3BZ532vhFwU= +github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw= +github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o= +github.com/rclone/rclone v1.69.2 h1:6uhFI7tiOrR5fy7Q88s49EqXc222mmwvZd7G9ne4lOE= +github.com/rclone/rclone v1.69.2/go.mod h1:fJPDOXUUPwN3KsbC3CGoVUuA5XU16IQvvMtrRqXYpvs= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI= +github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= +github.com/relvacode/iso8601 v1.3.0 h1:HguUjsGpIMh/zsTczGN3DVJFxTU/GX+MMmzcKoMO7ko= +github.com/relvacode/iso8601 v1.3.0/go.mod h1:FlNp+jz+TXpyRqgmM7tnzHHzBnz776kmAH2h3sZCn0I= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rfjakob/eme v1.1.2 h1:SxziR8msSOElPayZNFfQw4Tjx/Sbaeeh3eRvrHVMUs4= +github.com/rfjakob/eme v1.1.2/go.mod h1:cVvpasglm/G3ngEfcfT/Wt0GwhkuO32pf/poW6Nyk1k= +github.com/riemann/riemann-go-client v0.5.1-0.20211206220514-f58f10cdce16 h1:bGXoxRwUpPTCaQ86DRE+3wqE9vh3aH8W0HH5L/ygOFM= +github.com/riemann/riemann-go-client v0.5.1-0.20211206220514-f58f10cdce16/go.mod h1:4rS0vfmzOMwfFPhi6Zve4k/59TsBepqd6WESNULE0ho= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/robbiet480/go.nut v0.0.0-20220219091450-bd8f121e1fa1 h1:YmFqprZILGlF/X3tvMA4Rwn3ySxyE3hGUajBHkkaZbM= +github.com/robbiet480/go.nut v0.0.0-20220219091450-bd8f121e1fa1/go.mod h1:pL1huxuIlWub46MsMVJg4p7OXkzbPp/APxh9IH0eJjQ= +github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff h1:+6NUiITWwE5q1KO6SAfUX918c+Tab0+tGAM/mtdlUyA= +github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/robinson/gos7 v0.0.0-20240315073918-1f14519e4846 h1:CnAbtX0j07ZVR/TnD5V6ypFTrASJlfr+fc4OY2da9eg= +github.com/robinson/gos7 v0.0.0-20240315073918-1f14519e4846/go.mod h1:AMHIeh1KJ7Xa2RVOMHdv9jXKrpw0D4EWGGQMHLb2doc= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI= +github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs= +github.com/safchain/ethtool v0.5.10 h1:Im294gZtuf4pSGJRAOGKaASNi3wMeFaGaWuSaomedpc= +github.com/safchain/ethtool v0.5.10/go.mod h1:w9jh2Lx7YBR4UwzLkzCmWl85UY0W2uZdd7/DckVE5+c= +github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= +github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seancfoley/bintree v1.3.1 h1:cqmmQK7Jm4aw8gna0bP+huu5leVOgHGSJBEpUx3EXGI= +github.com/seancfoley/bintree v1.3.1/go.mod h1:hIUabL8OFYyFVTQ6azeajbopogQc2l5C/hiXMcemWNU= +github.com/seancfoley/ipaddress-go v1.7.1 h1:fDWryS+L8iaaH5RxIKbY0xB5Z+Zxk8xoXLN4S4eAPdQ= +github.com/seancfoley/ipaddress-go v1.7.1/go.mod h1:TQRZgv+9jdvzHmKoPGBMxyiaVmoI0rYpfEk8Q/sL/Iw= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/sensu/sensu-go/api/core/v2 v2.16.0 h1:HOq4rFkQ1S5ZjxmMTLc5J5mAbECrnKWvtXXbMqr3j9s= +github.com/sensu/sensu-go/api/core/v2 v2.16.0/go.mod h1:MjM7+MCGEyTAgaZ589SiGHwYiaYF7N/58dU0J070u/0= +github.com/shirou/gopsutil/v4 v4.25.4 h1:cdtFO363VEOOFrUCjZRh4XVJkb548lyF0q0uTeMqYPw= +github.com/shirou/gopsutil/v4 v4.25.4/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/showwin/speedtest-go v1.7.10 h1:9o5zb7KsuzZKn+IE2//z5btLKJ870JwO6ETayUkqRFw= +github.com/showwin/speedtest-go v1.7.10/go.mod h1:Ei7OCTmNPdWofMadzcfgq1rUO7mvJy9Jycj//G7vyfA= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/signalfx/com_signalfx_metrics_protobuf v0.0.3 h1:32k2QLgsKhcEs55q4REPKyIadvid5FPy2+VMgvbmKJ0= +github.com/signalfx/com_signalfx_metrics_protobuf v0.0.3/go.mod h1:gJrXWi7wSGXfiC7+VheQaz+ypdCt5SmZNL+BRxUe7y4= +github.com/signalfx/gohistogram v0.0.0-20160107210732-1ccfd2ff5083 h1:WsShHmu12ZztYPfh9b+I+VjYD1o8iOHhB67WZCMEEE8= +github.com/signalfx/gohistogram v0.0.0-20160107210732-1ccfd2ff5083/go.mod h1:adPDS6s7WaajdFBV9mQ7i0dKfQ8xiDnF9ZNETVPpp7c= +github.com/signalfx/golib/v3 v3.3.54 h1:jUwTnaIXLHT0I1+hXoX0cPLdICIwBjB3e5/NGnnjgJY= +github.com/signalfx/golib/v3 v3.3.54/go.mod h1:KDQZIYpJ3yXPz/KysPQQEYooWdpq4eQZPsjwKR5secc= +github.com/signalfx/sapm-proto v0.12.0 h1:OtOe+Jm8L61Ml8K6X8a89zc8/RlaaMRElCImeGKR/Ew= +github.com/signalfx/sapm-proto v0.12.0/go.mod h1:wQEki8RNCYjkv19jw5aWDcmDMTQru0ckfUbgHI69U2E= +github.com/sijms/go-ora/v2 v2.8.24 h1:TODRWjWGwJ1VlBOhbTLat+diTYe8HXq2soJeB+HMjnw= +github.com/sijms/go-ora/v2 v2.8.24/go.mod h1:QgFInVi3ZWyqAiJwzBQA+nbKYKH77tdp1PYoCqhR2dU= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +github.com/sleepinggenius2/gosmi v0.4.4 h1:xgu+Mt7CptuB10IPt3SVXBAA9tARToT4B9xGzjjxQX8= +github.com/sleepinggenius2/gosmi v0.4.4/go.mod h1:l8OniPmd3bJzw0MXP2/qh7AhP/e+bTY2CNivIhsnDT0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/gunit v1.1.3/go.mod h1:EH5qMBab2UclzXUcpR8b93eHsIlp9u+pDQIRp5DZNzQ= +github.com/snowflakedb/gosnowflake v1.14.0 h1:lP91Y47ho3dzpTxWr7wjpvDXteh+ZttsLaw1WXzHS34= +github.com/snowflakedb/gosnowflake v1.14.0/go.mod h1:NUxNYUdyPn9sRoYB/udq/fXBXuhLS3SBTPI2/OT79uc= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= +github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/spacemonkeygo/monkit/v3 v3.0.22 h1:4/g8IVItBDKLdVnqrdHZrCVPpIrwDBzl1jrV0IHQHDU= +github.com/spacemonkeygo/monkit/v3 v3.0.22/go.mod h1:XkZYGzknZwkD0AKUnZaSXhRiVTLCkq7CWVa3IsE72gA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= +github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= +github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= +github.com/srebhan/cborquery v1.0.4 h1:R+PZ/ZKpgf2z0d9jkr2aCP53GI0PCC9Ibz8iqX/Pluk= +github.com/srebhan/cborquery v1.0.4/go.mod h1:667M4EgeI9mJPFV5Mhyxg8rAuRO0SIIrgGtgZcFLqpE= +github.com/srebhan/protobufquery v1.0.4 h1:MLMo7nS02HSwux538Id3SCkf/FShA4MK3pppc9U/acY= +github.com/srebhan/protobufquery v1.0.4/go.mod h1:qMuAoKJAsVFYmyLE4H0dQ8F9+gBBHw+LBMqAZ326uA4= +github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/t3rm1n4l/go-mega v0.0.0-20241213150454-ec0027fb0002 h1:jevGbwKzMmHLgHAaDaMJLQX3jpXUWjUvnsrPeMgkM7o= +github.com/t3rm1n4l/go-mega v0.0.0-20241213150454-ec0027fb0002/go.mod h1:0Mv/XWQoRWF7d7jkc4DufsAJQg8xyZ5NtCkY59wECQY= +github.com/tbrandon/mbserver v0.0.0-20170611213546-993e1772cc62 h1:Oj2e7Sae4XrOsk3ij21QjjEgAcVSeo9nkp0dI//cD2o= +github.com/tbrandon/mbserver v0.0.0-20170611213546-993e1772cc62/go.mod h1:qUzPVlSj2UgxJkVbH0ZwuuiR46U8RBMDT5KLY78Ifpw= +github.com/tdrn-org/go-hue v0.3.0 h1:ywIlfTx9lcDp+n9XyGNY/9mUihW82lsWUanTzvdfeMc= +github.com/tdrn-org/go-hue v0.3.0/go.mod h1:KUnPy2lGoP43ygNoCg6jVEhf8h5fpRn0Esjxq9syCnU= +github.com/tdrn-org/go-nsdp v0.5.0 h1:bOs8qABaP/BSQlWeziZx9gjGkC2ld9UQek9p5w6PvdY= +github.com/tdrn-org/go-nsdp v0.5.0/go.mod h1:zp7CxiCPcyXHo+s6tn+wrNBr1qQe1G/hOh/FybM5xiM= +github.com/tedsuo/ifrit v0.0.0-20180802180643-bea94bb476cc/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0= +github.com/testcontainers/testcontainers-go v0.37.0 h1:L2Qc0vkTw2EHWQ08djon0D2uw7Z/PtHS/QzZZ5Ra/hg= +github.com/testcontainers/testcontainers-go v0.37.0/go.mod h1:QPzbxZhQ6Bclip9igjLFj6z0hs01bU8lrl2dHQmgFGM= +github.com/testcontainers/testcontainers-go/modules/azure v0.37.0 h1:pOqYnDvd2rkBb+ON0ikJgI3PzIslWlbR+y+czw5tWF0= +github.com/testcontainers/testcontainers-go/modules/azure v0.37.0/go.mod h1:h4/DPyIHUxdnnpTGhKkHUT/lYOYhjtQExiFCGdHOl+A= +github.com/testcontainers/testcontainers-go/modules/kafka v0.37.0 h1:ZkYNKqhqvKm+aZk9C1fxw/fpNNOK+Nm/wHPjmJdN3Ko= +github.com/testcontainers/testcontainers-go/modules/kafka v0.37.0/go.mod h1:+LvaFfSFW5PMiJTxTQlV6TBpXH1Ktk1h0FTVRZfqSxY= +github.com/thomasklein94/packer-plugin-libvirt v0.5.0 h1:aj2HLHZZM/ClGLIwVp9rrgh+2TOU/w4EiaZHAwCpOgs= +github.com/thomasklein94/packer-plugin-libvirt v0.5.0/go.mod h1:GwN82FQ6KxCNKtS8LNUgLbwTZs90GGhBzCmTNkrTCrY= +github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/tinylru v1.1.0/go.mod h1:3+bX+TJ2baOLMWTnlyNWHh4QMnFyARg2TLTQ6OFbzw8= +github.com/tidwall/tinylru v1.2.1 h1:VgBr72c2IEr+V+pCdkPZUwiQ0KJknnWIYbhxAVkYfQk= +github.com/tidwall/tinylru v1.2.1/go.mod h1:9bQnEduwB6inr2Y7AkBP7JPgCkyrhTV/ZpX0oOOpBI4= +github.com/tidwall/wal v1.1.8 h1:2qDSGdAdjaY3PEvHRva+9UFqgk+ef7cOiW1Qn5JH1y0= +github.com/tidwall/wal v1.1.8/go.mod h1:r6lR1j27W9EPalgHiB7zLJDYu3mzW5BQP5KrzBpYY/E= +github.com/tinylib/msgp v1.2.5 h1:WeQg1whrXRFiZusidTQqzETkRpGjFjcIhW6uqWH09po= +github.com/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= +github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= +github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= +github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= +github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= +github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= +github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/twmb/murmur3 v1.1.7 h1:ULWBiM04n/XoN3YMSJ6Z2pHDFLf+MeIVQU71ZPrvbWg= +github.com/twmb/murmur3 v1.1.7/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= +github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= +github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= +github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= +github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/unknwon/goconfig v1.0.0 h1:rS7O+CmUdli1T+oDm7fYj1MwqNWtEJfNj+FqcUHML8U= +github.com/unknwon/goconfig v1.0.0/go.mod h1:qu2ZQ/wcC/if2u32263HTVC39PeOQRSmidQk3DuDFQ8= +github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g= +github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/vapourismo/knx-go v0.0.0-20240915133544-a6ab43471c11 h1:YzrpNqpAuAgUQ0vseiI3mAVz7zr0rM5LWdaGCCr6Ipc= +github.com/vapourismo/knx-go v0.0.0-20240915133544-a6ab43471c11/go.mod h1:+iC7aAxEwuJ4mvdKaY0zCGT0dpIC/AtHt4yv2jr5FOo= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0= +github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= +github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/vjeantet/grok v1.0.1 h1:2rhIR7J4gThTgcZ1m2JY4TrJZNgjn985U28kT2wQrJ4= +github.com/vjeantet/grok v1.0.1/go.mod h1:ax1aAchzC6/QMXMcyzHQGZWaW1l195+uMYIkCWPCNIo= +github.com/vmware/govmomi v0.50.0 h1:vFOnUCBCX3m3MgTKfBp68Pz5gsHvKkO07Y2wCGYYQOM= +github.com/vmware/govmomi v0.50.0/go.mod h1:Z5uo7z0kRhVV00E4gfbUGwUaXIKTgqngsT+t/mIDpcI= +github.com/wavefronthq/wavefront-sdk-go v0.15.0 h1:po9E3vh/0y7kOx8D9EtFp7kbSLLLKbmu/w/s1xGJAQU= +github.com/wavefronthq/wavefront-sdk-go v0.15.0/go.mod h1:V72c8e+bXuLK8HpA6ioW0ll5mK9IPD+4IHNNDY75ksA= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/xdg/scram v1.0.5 h1:TuS0RFmt5Is5qm9Tm2SoD89OPqe4IRiFtyFY4iwWXsw= +github.com/xdg/scram v1.0.5/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.3 h1:cmL5Enob4W83ti/ZHuZLuKD/xqJfus4fVPwE+/BDm+4= +github.com/xdg/stringprep v1.0.3/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/goldmark v1.7.11 h1:ZCxLyDMtz0nT2HFfsYG8WZ47Trip2+JyLysKcMYE5bo= +github.com/yuin/goldmark v1.7.11/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= +github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg= +github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA= +github.com/yunify/qingstor-sdk-go/v3 v3.2.0 h1:9sB2WZMgjwSUNZhrgvaNGazVltoFUUfuS9f0uCWtTr8= +github.com/yunify/qingstor-sdk-go/v3 v3.2.0/go.mod h1:KciFNuMu6F4WLk9nGwwK69sCGKLCdd9f97ac/wfumS4= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/assert v1.3.1 h1:vukIABvugfNMZMQO1ABsyQDJDTVQbn+LWSMy1ol1h6A= +github.com/zeebo/assert v1.3.1/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= +github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= +github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= +github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= +github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +github.com/zitadel/logging v0.6.2 h1:MW2kDDR0ieQynPZ0KIZPrh9ote2WkxfBif5QoARDQcU= +github.com/zitadel/logging v0.6.2/go.mod h1:z6VWLWUkJpnNVDSLzrPSQSQyttysKZ6bCRongw0ROK4= +github.com/zitadel/oidc/v3 v3.37.0 h1:nYATWlnP7f18XiAbw6upUruBaqfB1kUrXrSTf1EYGO8= +github.com/zitadel/oidc/v3 v3.37.0/go.mod h1:/xDan4OUQhguJ4Ur73OOJrtugvR164OMnidXP9xfVNw= +github.com/zitadel/schema v1.3.1 h1:QT3kwiRIRXXLVAs6gCK/u044WmUVh6IlbLXUsn6yRQU= +github.com/zitadel/schema v1.3.1/go.mod h1:071u7D2LQacy1HAN+YnMd/mx1qVE2isb0Mjeqg46xnU= +go.einride.tech/aip v0.68.1 h1:16/AfSxcQISGN5z9C5lM+0mLYXihrHbQ1onvYTr93aQ= +go.einride.tech/aip v0.68.1/go.mod h1:XaFtaj4HuA3Zwk9xoBtTWgNubZ0ZZXv9BZJCkuKuWbg= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= +go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= +go.etcd.io/etcd/api/v3 v3.5.4 h1:OHVyt3TopwtUQ2GKdd5wu3PmmipR4FTwCqoEjSyRdIc= +go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= +go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= +go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ= +go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/collector v0.81.0 h1:pF+sB8xNXlg/W0a0QTLz4mUWyool1a9toVj8LmLoFqg= +go.opentelemetry.io/collector/consumer v0.101.0 h1:9tDxaeHe1+Uovf3fhdx7T4pV5mo/Dc0hniH7O5H3RBA= +go.opentelemetry.io/collector/consumer v0.101.0/go.mod h1:ud5k64on9m7hHTrhjEeLhWbLkd8+Gp06rDt3p86TKNs= +go.opentelemetry.io/collector/pdata v1.31.0 h1:P5WuLr1l2JcIvr6Dw2hl01ltp2ZafPnC4Isv+BLTBqU= +go.opentelemetry.io/collector/pdata v1.31.0/go.mod h1:m41io9nWpy7aCm/uD1L9QcKiZwOP0ldj83JEA34dmlk= +go.opentelemetry.io/collector/pdata/testdata v0.101.0 h1:JzeUtg5RN1iIFgY8DakGlqBkGxOTJlkaYlLausnEGKY= +go.opentelemetry.io/collector/pdata/testdata v0.101.0/go.mod h1:ZGobfCus4fWo5RduZ7ENI0+HD9BewgKuO6qU2rBVnUg= +go.opentelemetry.io/collector/semconv v0.105.0 h1:8p6dZ3JfxFTjbY38d8xlQGB1TQ3nPUvs+D0RERniZ1g= +go.opentelemetry.io/collector/semconv v0.105.0/go.mod h1:yMVUCNoQPZVq/IPfrHrnntZTWsLf5YGZ7qwKulIl5hw= +go.opentelemetry.io/contrib/detectors/gcp v1.35.0 h1:bGvFt68+KTiAKFlacHW6AhA56GF2rS0bdD3aJYEnmzA= +go.opentelemetry.io/contrib/detectors/gcp v1.35.0/go.mod h1:qGWP8/+ILwMRIUf9uIVLloR1uo5ZYAslM4O6OqUi1DA= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 h1:jd0+5t/YynESZqsSyPz+7PAFdEop0dlN0+PkyHYo8oI= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0/go.mod h1:U707O40ee1FpQGyhvqnzmCJm1Wh6OX6GGBVn0E6Uyyk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 h1:j9+03ymgYhPKmeXGk5Zu+cIZOlVzd9Zv7QIiyItjFBU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0/go.mod h1:Y5+XiUG4Emn1hTfciPzGPJaSI+RpDts6BnCIir0SLqk= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0 h1:PB3Zrjs1sG1GBX51SXyTSoOTqcDglmsk7nT6tkKPb/k= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0/go.mod h1:U2R3XyVPzn0WX7wOIypPuptulsMcPDPs/oiSVOMVnHY= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= +go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= +go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= +go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.starlark.net v0.0.0-20250417143717-f57e51f710eb h1:zOg9DxxrorEmgGUr5UPdCEwKqiqG0MlZciuCuA3XiDE= +go.starlark.net v0.0.0-20250417143717-f57e51f710eb/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8= +go.step.sm/crypto v0.63.0 h1:U1QGELQqJ85oDfeNFE2V52cow1rvy0m3MekG3wFmyXY= +go.step.sm/crypto v0.63.0/go.mod h1:aj3LETmCZeSil1DMq3BlbhDBcN86+mmKrHZtXWyc0L4= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211111083644-e5c967477495/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211214234402-4825e8c3871d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= +golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +golang.zx2c4.com/go118/netip v0.0.0-20211111135330-a4a02eeacf9d/go.mod h1:5yyfuiqVIJ7t+3MqrpTQ+QqRkMWiESiyDvPNvKYCecg= +golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= +golang.zx2c4.com/wireguard v0.0.0-20211129173154-2dd424e2d808/go.mod h1:TjUWrnD5ATh7bFvmm/ALEJZQ4ivKbETb6pmyj1vUoNI= +golang.zx2c4.com/wireguard v0.0.0-20211209221555-9c9e7e272434 h1:3zl8RkJNQ8wfPRomwv/6DBbH2Ut6dgMaWTxM0ZunWnE= +golang.zx2c4.com/wireguard v0.0.0-20211209221555-9c9e7e272434/go.mod h1:TjUWrnD5ATh7bFvmm/ALEJZQ4ivKbETb6pmyj1vUoNI= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20211230205640-daad0b7ba671 h1:tJAYx7pB6b5bNqi7XatStqFT2zFAxhXcGDq1R6FqqjU= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20211230205640-daad0b7ba671/go.mod h1:Q2XNgour4QSkFj0BWCkVlW0HWJwQgNMsMahpSlI0Eno= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= +google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +google.golang.org/api v0.232.0 h1:qGnmaIMf7KcuwHOlF3mERVzChloDYwRfOJOrHt8YC3I= +google.golang.org/api v0.232.0/go.mod h1:p9QCfBWZk1IJETUdbTKloR5ToFdKbYh2fkjsUL6vNoY= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200519141106-08726f379972/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= +google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE= +google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE= +google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 h1:0PeQib/pH3nB/5pEmFeVQJotzGohV0dq4Vcp09H5yhE= +google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34/go.mod h1:0awUlEkap+Pb1UMeJwJQQAdJQrt3moU7J2moTy69irI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 h1:h6p3mQqrmT1XkHVTfzLdNz1u7IhINeZkz67/xTbOuWs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= +google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/fatih/pool.v2 v2.0.0 h1:xIFeWtxifuQJGk/IEPKsTduEKcKvPmhoiVDGpC40nKg= +gopkg.in/fatih/pool.v2 v2.0.0/go.mod h1:8xVGeu1/2jr2wm5V9SPuMht2H5AEmf5aFMGSQixtjTY= +gopkg.in/fsnotify.v1 v1.2.1/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gorethink/gorethink.v3 v3.0.5 h1:e2Uc/Xe+hpcVQFsj6MuHlYog3r0JYpnTzwDj/y2O4MU= +gopkg.in/gorethink/gorethink.v3 v3.0.5/go.mod h1:+3yIIHJUGMBK+wyPH+iN5TP+88ikFDfZdqTlK3Y9q8I= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/olivere/elastic.v5 v5.0.86 h1:xFy6qRCGAmo5Wjx96srho9BitLhZl2fcnpuidPwduXM= +gopkg.in/olivere/elastic.v5 v5.0.86/go.mod h1:M3WNlsF+WhYn7api4D87NIflwTV/c0iVs8cqfWhK+68= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= +gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= +gopkg.in/tomb.v1 v1.0.0-20140529071818-c131134a1947/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs= +gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= +gopkg.in/validator.v2 v2.0.1 h1:xF0KWyGWXm/LM2G1TrEjqOu4pa6coO9AlWSf3msVfDY= +gopkg.in/validator.v2 v2.0.1/go.mod h1:lIUZBlB3Im4s/eYp39Ry/wkR02yOPhZ9IwIRBjuPuG8= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= +honnef.co/go/tools v0.2.2 h1:MNh1AVMyVX23VUHE2O27jm6lNj3vjO5DexS4A1xvnzk= +honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= +k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU= +k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM= +k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ= +k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98= +k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= +k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro= +k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +layeh.com/radius v0.0.0-20221205141417-e7fbddd11d68 h1:2NDro2Jzkrqfngy/sA5GVnChs7fx8EzcQKFi/lI2cfg= +layeh.com/radius v0.0.0-20221205141417-e7fbddd11d68/go.mod h1:pFWM9De99EY9TPVyHIyA56QmoRViVck/x41WFkUlc9A= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v4 v4.25.2 h1:T2oH7sZdGvTaie0BRNFbIYsabzCxUQg8nLqCdQ2i0ic= +modernc.org/cc/v4 v4.25.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= +modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccgo/v4 v4.25.1 h1:TFSzPrAGmDsdnhT9X2UrcPMI3N/mJ9/X9ykKXwLhDsU= +modernc.org/ccgo/v4 v4.25.1/go.mod h1:njjuAYiPflywOOrm3B7kCB444ONP5pAVr8PIEoE0uDw= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= +modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= +modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= +modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= +modernc.org/libc v1.62.1 h1:s0+fv5E3FymN8eJVmnk0llBe6rOxCu/DEU+XygRbS8s= +modernc.org/libc v1.62.1/go.mod h1:iXhATfJQLjG3NWy56a6WVU73lWOcdYVxsvwCgoPljuo= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.9.1 h1:V/Z1solwAVmMW1yttq3nDdZPJqV1rM05Ccq6KMSZ34g= +modernc.org/memory v1.9.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= +modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= +modernc.org/sqlite v1.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI= +modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= +moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs= +moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE= +pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= +pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= +sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +software.sslmate.com/src/go-pkcs12 v0.5.0 h1:EC6R394xgENTpZ4RltKydeDUjtlM5drOYIG9c6TVj2M= +software.sslmate.com/src/go-pkcs12 v0.5.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= +storj.io/common v0.0.0-20240812101423-26b53789c348 h1:Urs3fX+1Fyb+CFKGw0mCJV3MPR499WM+Vs6osw4Rqtk= +storj.io/common v0.0.0-20240812101423-26b53789c348/go.mod h1:XMpwKxc04HCBl4H5IFCGv1ca5Dm0tvH4NL7Jx+JhxuA= +storj.io/drpc v0.0.35-0.20240709171858-0075ac871661 h1:hLvEV2RMTscX3JHPd+LSQCeTt8i1Q0Yt7U2EdfyMnaQ= +storj.io/drpc v0.0.35-0.20240709171858-0075ac871661/go.mod h1:Y9LZaa8esL1PW2IDMqJE7CFSNq7d5bQ3RI7mGPtmKMg= +storj.io/eventkit v0.0.0-20240415002644-1d9596fee086 h1:TkytkGUI6zGtH5Qx/O0VxQCcYJqOOiwRq0oMi4uM5Tg= +storj.io/eventkit v0.0.0-20240415002644-1d9596fee086/go.mod h1:S6p41RzIBKoeGAdrziksWkiijnZXql9YcNsc23t0u+8= +storj.io/infectious v0.0.2 h1:rGIdDC/6gNYAStsxsZU79D/MqFjNyJc1tsyyj9sTl7Q= +storj.io/infectious v0.0.2/go.mod h1:QEjKKww28Sjl1x8iDsjBpOM4r1Yp8RsowNcItsZJ1Vs= +storj.io/picobuf v0.0.3 h1:xAUPB5ZUGfxkqd3bnw3zp01kkWb9wlhg4vtZWUs2S9A= +storj.io/picobuf v0.0.3/go.mod h1:4V4xelV1RSCck5GgmkL/Txw9l6IfX3XcBzegmL5Kudo= +storj.io/uplink v1.13.1 h1:C8RdW/upALoCyuF16Lod9XGCXEdbJAS+ABQy9JO/0pA= +storj.io/uplink v1.13.1/go.mod h1:x0MQr4UfFsQBwgVWZAtEsLpuwAn6dg7G0Mpne1r516E= diff --git a/info.plist b/info.plist new file mode 100644 index 0000000..e1267df --- /dev/null +++ b/info.plist @@ -0,0 +1,16 @@ + + + + + CFBundleExecutable + telegraf_entry_mac + CFBundleIconFile + icon.icns + CFBundleIdentifier + com.influxdata.telegraf + NSHighResolutionCapable + + LSUIElement + + + \ No newline at end of file diff --git a/input.go b/input.go new file mode 100644 index 0000000..0f2dac2 --- /dev/null +++ b/input.go @@ -0,0 +1,23 @@ +package telegraf + +type Input interface { + PluginDescriber + + // Gather takes in an accumulator and adds the metrics that the Input + // gathers. This is called every agent.interval + Gather(Accumulator) error +} + +type ServiceInput interface { + Input + + // Start the ServiceInput. The Accumulator may be retained and used until + // Stop returns. + Start(Accumulator) error + + // Stop stops the services and closes any necessary channels and connections. + // Metrics should not be written out to the accumulator once stop returns, so + // Stop() should stop reading and wait for any in-flight metrics to write out + // to the accumulator before returning. + Stop() +} diff --git a/internal/choice/choice.go b/internal/choice/choice.go new file mode 100644 index 0000000..5c178fa --- /dev/null +++ b/internal/choice/choice.go @@ -0,0 +1,36 @@ +// Package choice provides basic functions for working with +// plugin options that must be one of several values. +package choice + +import "fmt" + +// Contains return true if the choice in the list of choices. +func Contains(choice string, choices []string) bool { + for _, item := range choices { + if item == choice { + return true + } + } + return false +} + +// Check returns an error if a choice is not one of +// the available choices. +func Check(choice string, available []string) error { + if !Contains(choice, available) { + return fmt.Errorf("unknown choice %s", choice) + } + return nil +} + +// CheckSlice returns an error if the choices is not a subset of +// available. +func CheckSlice(choices, available []string) error { + for _, choice := range choices { + err := Check(choice, available) + if err != nil { + return err + } + } + return nil +} diff --git a/internal/content_coding.go b/internal/content_coding.go new file mode 100644 index 0000000..624e3c2 --- /dev/null +++ b/internal/content_coding.go @@ -0,0 +1,495 @@ +package internal + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + + "github.com/klauspost/compress/gzip" + "github.com/klauspost/compress/zlib" + "github.com/klauspost/compress/zstd" + "github.com/klauspost/pgzip" +) + +const defaultMaxDecompressionSize int64 = 500 * 1024 * 1024 // 500MB + +// DecodingOption provide methods to change the decoding from the standard +// configuration. +type DecodingOption func(*decoderConfig) + +type decoderConfig struct { + maxDecompressionSize int64 +} + +func WithMaxDecompressionSize(maxDecompressionSize int64) DecodingOption { + return func(cfg *decoderConfig) { + cfg.maxDecompressionSize = maxDecompressionSize + } +} + +type encoderConfig struct { + level int +} + +// EncodingOption provide methods to change the encoding from the standard +// configuration. +type EncodingOption func(*encoderConfig) + +func WithCompressionLevel(level int) EncodingOption { + return func(cfg *encoderConfig) { + cfg.level = level + } +} + +// NewStreamContentDecoder returns a reader that will decode the stream +// according to the encoding type. +func NewStreamContentDecoder(encoding string, r io.Reader) (io.Reader, error) { + switch encoding { + case "gzip": + return NewGzipReader(r) + case "identity", "": + return r, nil + default: + return nil, errors.New("invalid value for content_encoding") + } +} + +// GzipReader is similar to gzip.Reader but reads only a single gzip stream per read. +type GzipReader struct { + r io.Reader + z *pgzip.Reader + endOfStream bool +} + +func NewGzipReader(r io.Reader) (io.Reader, error) { + // We need a read that implements ByteReader in order to line up the next + // stream. + br := bufio.NewReader(r) + + // Reads the first gzip stream header. + z, err := pgzip.NewReader(br) + if err != nil { + return nil, err + } + + // Prevent future calls to Read from reading the following gzip header. + z.Multistream(false) + + return &GzipReader{r: br, z: z}, nil +} + +func (r *GzipReader) Read(b []byte) (int, error) { + if r.endOfStream { + // Reads the next gzip header and prepares for the next stream. + err := r.z.Reset(r.r) + if err != nil { + return 0, err + } + r.z.Multistream(false) + r.endOfStream = false + } + + n, err := r.z.Read(b) + + // Since multistream is disabled, io.EOF indicates the end of the gzip + // sequence. On the next read we must read the next gzip header. + if errors.Is(err, io.EOF) { + r.endOfStream = true + return n, nil + } + return n, err +} + +// NewContentEncoder returns a ContentEncoder for the encoding type. +func NewContentEncoder(encoding string, options ...EncodingOption) (ContentEncoder, error) { + switch encoding { + case "gzip": + return NewGzipEncoder(options...) + case "identity", "": + return NewIdentityEncoder(options...) + case "zlib": + return NewZlibEncoder(options...) + case "zstd": + return NewZstdEncoder(options...) + default: + return nil, errors.New("invalid value for content_encoding") + } +} + +type AutoDecoder struct { + encoding string + gzip *GzipDecoder + identity *IdentityDecoder +} + +func (a *AutoDecoder) SetEncoding(encoding string) { + a.encoding = encoding +} + +func (a *AutoDecoder) Decode(data []byte) ([]byte, error) { + if a.encoding == "gzip" { + return a.gzip.Decode(data) + } + return a.identity.Decode(data) +} + +func NewAutoContentDecoder(options ...DecodingOption) *AutoDecoder { + var a AutoDecoder + + a.identity = NewIdentityDecoder(options...) + a.gzip = NewGzipDecoder(options...) + return &a +} + +// NewContentDecoder returns a ContentDecoder for the encoding type. +func NewContentDecoder(encoding string, options ...DecodingOption) (ContentDecoder, error) { + switch encoding { + case "auto": + return NewAutoContentDecoder(options...), nil + case "gzip": + return NewGzipDecoder(options...), nil + case "identity", "": + return NewIdentityDecoder(options...), nil + case "zlib": + return NewZlibDecoder(options...), nil + case "zstd": + return NewZstdDecoder(options...) + default: + return nil, errors.New("invalid value for content_encoding") + } +} + +// ContentEncoder applies a wrapper encoding to byte buffers. +type ContentEncoder interface { + Encode([]byte) ([]byte, error) +} + +// GzipEncoder compresses the buffer using gzip at the default level. +type GzipEncoder struct { + pwriter *pgzip.Writer + writer *gzip.Writer + buf *bytes.Buffer +} + +func NewGzipEncoder(options ...EncodingOption) (*GzipEncoder, error) { + cfg := encoderConfig{level: gzip.DefaultCompression} + for _, o := range options { + o(&cfg) + } + + // Check if the compression level is supported + switch cfg.level { + case gzip.NoCompression, gzip.DefaultCompression, gzip.BestSpeed, gzip.BestCompression: + // Do nothing as those are valid levels + default: + return nil, errors.New("invalid compression level, only 0, 1 and 9 are supported") + } + + var buf bytes.Buffer + pw, err := pgzip.NewWriterLevel(&buf, cfg.level) + if err != nil { + return nil, err + } + + w, err := gzip.NewWriterLevel(&buf, cfg.level) + return &GzipEncoder{ + pwriter: pw, + writer: w, + buf: &buf, + }, err +} + +func (e *GzipEncoder) Encode(data []byte) ([]byte, error) { + // Parallel Gzip is only faster for larger data chunks. According to the + // project's documentation the trade-off size is at about 1MB, so we switch + // to parallel Gzip if the data is larger and run the built-in version + // otherwise. + if len(data) > 1024*1024 { + return e.encodeBig(data) + } + return e.encodeSmall(data) +} + +func (e *GzipEncoder) encodeSmall(data []byte) ([]byte, error) { + e.buf.Reset() + e.writer.Reset(e.buf) + + _, err := e.writer.Write(data) + if err != nil { + return nil, err + } + err = e.writer.Close() + if err != nil { + return nil, err + } + return e.buf.Bytes(), nil +} + +func (e *GzipEncoder) encodeBig(data []byte) ([]byte, error) { + e.buf.Reset() + e.pwriter.Reset(e.buf) + + _, err := e.pwriter.Write(data) + if err != nil { + return nil, err + } + err = e.pwriter.Close() + if err != nil { + return nil, err + } + return e.buf.Bytes(), nil +} + +type ZlibEncoder struct { + writer *zlib.Writer + buf *bytes.Buffer +} + +func NewZlibEncoder(options ...EncodingOption) (*ZlibEncoder, error) { + cfg := encoderConfig{level: zlib.DefaultCompression} + for _, o := range options { + o(&cfg) + } + + switch cfg.level { + case zlib.NoCompression, zlib.DefaultCompression, zlib.BestSpeed, zlib.BestCompression: + // Do nothing as those are valid levels + default: + return nil, errors.New("invalid compression level, only 0, 1 and 9 are supported") + } + + var buf bytes.Buffer + w, err := zlib.NewWriterLevel(&buf, cfg.level) + return &ZlibEncoder{ + writer: w, + buf: &buf, + }, err +} + +func (e *ZlibEncoder) Encode(data []byte) ([]byte, error) { + e.buf.Reset() + e.writer.Reset(e.buf) + + _, err := e.writer.Write(data) + if err != nil { + return nil, err + } + err = e.writer.Close() + if err != nil { + return nil, err + } + return e.buf.Bytes(), nil +} + +type ZstdEncoder struct { + encoder *zstd.Encoder +} + +func NewZstdEncoder(options ...EncodingOption) (*ZstdEncoder, error) { + cfg := encoderConfig{level: 3} + for _, o := range options { + o(&cfg) + } + + // Map the levels + var level zstd.EncoderLevel + switch cfg.level { + case 1: + level = zstd.SpeedFastest + case 3: + level = zstd.SpeedDefault + case 7: + level = zstd.SpeedBetterCompression + case 11: + level = zstd.SpeedBestCompression + default: + return nil, errors.New("invalid compression level, only 1, 3, 7 and 11 are supported") + } + + e, err := zstd.NewWriter(nil, zstd.WithEncoderLevel(level)) + return &ZstdEncoder{ + encoder: e, + }, err +} + +func (e *ZstdEncoder) Encode(data []byte) ([]byte, error) { + return e.encoder.EncodeAll(data, make([]byte, 0, len(data))), nil +} + +// IdentityEncoder is a null encoder that applies no transformation. +type IdentityEncoder struct{} + +func NewIdentityEncoder(options ...EncodingOption) (*IdentityEncoder, error) { + if len(options) > 0 { + return nil, errors.New("identity encoder does not support options") + } + + return &IdentityEncoder{}, nil +} + +func (*IdentityEncoder) Encode(data []byte) ([]byte, error) { + return data, nil +} + +// ContentDecoder removes a wrapper encoding from byte buffers. +type ContentDecoder interface { + SetEncoding(string) + Decode([]byte) ([]byte, error) +} + +// GzipDecoder decompresses buffers with gzip compression. +type GzipDecoder struct { + preader *pgzip.Reader + reader *gzip.Reader + buf *bytes.Buffer + maxDecompressionSize int64 +} + +func NewGzipDecoder(options ...DecodingOption) *GzipDecoder { + cfg := decoderConfig{maxDecompressionSize: defaultMaxDecompressionSize} + for _, o := range options { + o(&cfg) + } + + return &GzipDecoder{ + preader: new(pgzip.Reader), + reader: new(gzip.Reader), + buf: new(bytes.Buffer), + maxDecompressionSize: cfg.maxDecompressionSize, + } +} + +func (*GzipDecoder) SetEncoding(string) {} + +func (d *GzipDecoder) Decode(data []byte) ([]byte, error) { + // Parallel Gzip is only faster for larger data chunks. According to the + // project's documentation the trade-off size is at about 1MB, so we switch + // to parallel Gzip if the data is larger and run the built-in version + // otherwise. + if len(data) > 1024*1024 { + return d.decodeBig(data) + } + return d.decodeSmall(data) +} + +func (d *GzipDecoder) decodeSmall(data []byte) ([]byte, error) { + err := d.reader.Reset(bytes.NewBuffer(data)) + if err != nil { + return nil, err + } + d.buf.Reset() + + n, err := io.CopyN(d.buf, d.reader, d.maxDecompressionSize) + if err != nil && !errors.Is(err, io.EOF) { + return nil, err + } else if n == d.maxDecompressionSize { + return nil, fmt.Errorf("size of decoded data exceeds allowed size %d", d.maxDecompressionSize) + } + + err = d.reader.Close() + if err != nil { + return nil, err + } + return d.buf.Bytes(), nil +} + +func (d *GzipDecoder) decodeBig(data []byte) ([]byte, error) { + err := d.preader.Reset(bytes.NewBuffer(data)) + if err != nil { + return nil, err + } + d.buf.Reset() + + n, err := io.CopyN(d.buf, d.preader, d.maxDecompressionSize) + if err != nil && !errors.Is(err, io.EOF) { + return nil, err + } else if n == d.maxDecompressionSize { + return nil, fmt.Errorf("size of decoded data exceeds allowed size %d", d.maxDecompressionSize) + } + + err = d.preader.Close() + if err != nil { + return nil, err + } + return d.buf.Bytes(), nil +} + +type ZlibDecoder struct { + buf *bytes.Buffer + maxDecompressionSize int64 +} + +func NewZlibDecoder(options ...DecodingOption) *ZlibDecoder { + cfg := decoderConfig{maxDecompressionSize: defaultMaxDecompressionSize} + for _, o := range options { + o(&cfg) + } + + return &ZlibDecoder{ + buf: new(bytes.Buffer), + maxDecompressionSize: cfg.maxDecompressionSize, + } +} + +func (*ZlibDecoder) SetEncoding(string) {} + +func (d *ZlibDecoder) Decode(data []byte) ([]byte, error) { + d.buf.Reset() + + b := bytes.NewBuffer(data) + r, err := zlib.NewReader(b) + if err != nil { + return nil, err + } + + n, err := io.CopyN(d.buf, r, d.maxDecompressionSize) + if err != nil && !errors.Is(err, io.EOF) { + return nil, err + } else if n == d.maxDecompressionSize { + return nil, fmt.Errorf("size of decoded data exceeds allowed size %d", d.maxDecompressionSize) + } + + err = r.Close() + if err != nil { + return nil, err + } + return d.buf.Bytes(), nil +} + +type ZstdDecoder struct { + decoder *zstd.Decoder +} + +func NewZstdDecoder(options ...DecodingOption) (*ZstdDecoder, error) { + cfg := decoderConfig{maxDecompressionSize: defaultMaxDecompressionSize} + for _, o := range options { + o(&cfg) + } + + d, err := zstd.NewReader(nil, zstd.WithDecoderConcurrency(0), zstd.WithDecoderMaxWindow(uint64(cfg.maxDecompressionSize))) + return &ZstdDecoder{ + decoder: d, + }, err +} + +func (*ZstdDecoder) SetEncoding(string) {} + +func (d *ZstdDecoder) Decode(data []byte) ([]byte, error) { + return d.decoder.DecodeAll(data, nil) +} + +// IdentityDecoder is a null decoder that returns the input. +type IdentityDecoder struct { +} + +func NewIdentityDecoder(_ ...DecodingOption) *IdentityDecoder { + return &IdentityDecoder{} +} + +func (*IdentityDecoder) SetEncoding(string) {} + +func (*IdentityDecoder) Decode(data []byte) ([]byte, error) { + return data, nil +} diff --git a/internal/content_coding_test.go b/internal/content_coding_test.go new file mode 100644 index 0000000..46401b1 --- /dev/null +++ b/internal/content_coding_test.go @@ -0,0 +1,555 @@ +package internal + +import ( + "bytes" + "fmt" + "io" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +const maxDecompressionSize = 1024 + +func TestGzipEncodeDecode(t *testing.T) { + enc, err := NewGzipEncoder() + require.NoError(t, err) + dec := NewGzipDecoder(WithMaxDecompressionSize(maxDecompressionSize)) + + payload, err := enc.Encode([]byte("howdy")) + require.NoError(t, err) + + actual, err := dec.Decode(payload) + require.NoError(t, err) + + require.Equal(t, "howdy", string(actual)) +} + +func TestGzipReuse(t *testing.T) { + enc, err := NewGzipEncoder() + require.NoError(t, err) + dec := NewGzipDecoder(WithMaxDecompressionSize(maxDecompressionSize)) + + payload, err := enc.Encode([]byte("howdy")) + require.NoError(t, err) + + actual, err := dec.Decode(payload) + require.NoError(t, err) + + require.Equal(t, "howdy", string(actual)) + + payload, err = enc.Encode([]byte("doody")) + require.NoError(t, err) + + actual, err = dec.Decode(payload) + require.NoError(t, err) + + require.Equal(t, "doody", string(actual)) +} + +func TestZlibEncodeDecode(t *testing.T) { + enc, err := NewZlibEncoder() + require.NoError(t, err) + dec := NewZlibDecoder(WithMaxDecompressionSize(maxDecompressionSize)) + + payload, err := enc.Encode([]byte("howdy")) + require.NoError(t, err) + + actual, err := dec.Decode(payload) + require.NoError(t, err) + + require.Equal(t, "howdy", string(actual)) +} + +func TestZlibEncodeDecodeWithTooLargeMessage(t *testing.T) { + enc, err := NewZlibEncoder() + require.NoError(t, err) + dec := NewZlibDecoder(WithMaxDecompressionSize(3)) + + payload, err := enc.Encode([]byte("howdy")) + require.NoError(t, err) + + _, err = dec.Decode(payload) + require.ErrorContains(t, err, "size of decoded data exceeds allowed size 3") +} + +func TestZstdEncodeDecode(t *testing.T) { + enc, err := NewZstdEncoder() + require.NoError(t, err) + dec, err := NewZstdDecoder(WithMaxDecompressionSize(maxDecompressionSize)) + require.NoError(t, err) + + payload, err := enc.Encode([]byte("howdy")) + require.NoError(t, err) + + actual, err := dec.Decode(payload) + require.NoError(t, err) + + require.Equal(t, "howdy", string(actual)) +} + +func TestZstdReuse(t *testing.T) { + enc, err := NewZstdEncoder() + require.NoError(t, err) + dec, err := NewZstdDecoder(WithMaxDecompressionSize(maxDecompressionSize)) + require.NoError(t, err) + + payload, err := enc.Encode([]byte("howdy")) + require.NoError(t, err) + + actual, err := dec.Decode(payload) + require.NoError(t, err) + + require.Equal(t, "howdy", string(actual)) + + payload, err = enc.Encode([]byte("doody")) + require.NoError(t, err) + + actual, err = dec.Decode(payload) + require.NoError(t, err) + + require.Equal(t, "doody", string(actual)) +} + +func TestIdentityEncodeDecode(t *testing.T) { + dec := NewIdentityDecoder(WithMaxDecompressionSize(maxDecompressionSize)) + enc, err := NewIdentityEncoder() + require.NoError(t, err) + + payload, err := enc.Encode([]byte("howdy")) + require.NoError(t, err) + + actual, err := dec.Decode(payload) + require.NoError(t, err) + + require.Equal(t, "howdy", string(actual)) +} + +func TestStreamIdentityDecode(t *testing.T) { + var r bytes.Buffer + n, err := r.WriteString("howdy") + require.NoError(t, err) + require.Equal(t, 5, n) + + dec, err := NewStreamContentDecoder("identity", &r) + require.NoError(t, err) + + data, err := io.ReadAll(dec) + require.NoError(t, err) + + require.Equal(t, []byte("howdy"), data) +} + +func TestStreamGzipDecode(t *testing.T) { + enc, err := NewGzipEncoder() + require.NoError(t, err) + written, err := enc.Encode([]byte("howdy")) + require.NoError(t, err) + + w := bytes.NewBuffer(written) + + dec, err := NewStreamContentDecoder("gzip", w) + require.NoError(t, err) + + b := make([]byte, 10) + n, err := dec.Read(b) + require.NoError(t, err) + require.Equal(t, 5, n) + + require.Equal(t, []byte("howdy"), b[:n]) +} + +func TestCompressionLevel(t *testing.T) { + tests := []struct { + algorithm string + validLevels []int + errormsg string + }{ + { + algorithm: "gzip", + validLevels: []int{0, 1, 9}, + errormsg: "invalid compression level", + }, + { + algorithm: "zlib", + validLevels: []int{0, 1, 9}, + errormsg: "invalid compression level", + }, + { + algorithm: "zstd", + validLevels: []int{1, 3, 7, 11}, + errormsg: "invalid compression level", + }, + { + algorithm: "identity", + errormsg: "does not support options", + }, + } + + for _, tt := range tests { + // Check default i.e. without specifying level + t.Run(tt.algorithm+" default", func(t *testing.T) { + enc, err := NewContentEncoder(tt.algorithm) + require.NoError(t, err) + require.NotNil(t, enc) + }) + + // Check invalid level + t.Run(tt.algorithm+" invalid", func(t *testing.T) { + _, err := NewContentEncoder(tt.algorithm, WithCompressionLevel(12)) + require.ErrorContains(t, err, tt.errormsg) + }) + + // Check known levels 0..9 + for level := 0; level < 10; level++ { + name := fmt.Sprintf("%s level %d", tt.algorithm, level) + t.Run(name, func(t *testing.T) { + var valid bool + for _, l := range tt.validLevels { + if l == level { + valid = true + break + } + } + + enc, err := NewContentEncoder(tt.algorithm, WithCompressionLevel(level)) + if valid { + require.NoError(t, err) + require.NotNil(t, enc) + } else { + require.ErrorContains(t, err, tt.errormsg) + } + }) + } + } +} + +func BenchmarkGzipEncode(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 64)) + dataLen := int64(len(data)) + 1 + + enc, err := NewGzipEncoder() + require.NoError(b, err) + dec := NewGzipDecoder(WithMaxDecompressionSize(dataLen)) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + _, err := enc.Encode(data) + require.NoError(b, err) + } +} + +func BenchmarkGzipDecode(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 64)) + dataLen := int64(len(data)) + 1 + + enc, err := NewGzipEncoder() + require.NoError(b, err) + dec := NewGzipDecoder(WithMaxDecompressionSize(dataLen)) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + _, err = dec.Decode(payload) + require.NoError(b, err) + } +} + +func BenchmarkGzipEncodeDecode(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 64)) + dataLen := int64(len(data)) + 1 + + enc, err := NewGzipEncoder() + require.NoError(b, err) + dec := NewGzipDecoder(WithMaxDecompressionSize(dataLen)) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + payload, err := enc.Encode(data) + require.NoError(b, err) + + _, err = dec.Decode(payload) + require.NoError(b, err) + } +} + +func BenchmarkGzipEncodeBig(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 1024*1024)) + dataLen := int64(len(data)) + 1 + + enc, err := NewGzipEncoder() + require.NoError(b, err) + dec := NewGzipDecoder(WithMaxDecompressionSize(dataLen)) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + _, err := enc.Encode(data) + require.NoError(b, err) + } +} + +func BenchmarkGzipDecodeBig(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 1024*1024)) + dataLen := int64(len(data)) + 1 + + enc, err := NewGzipEncoder() + require.NoError(b, err) + dec := NewGzipDecoder(WithMaxDecompressionSize(dataLen)) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + _, err = dec.Decode(payload) + require.NoError(b, err) + } +} + +func BenchmarkGzipEncodeDecodeBig(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 1024*1024)) + dataLen := int64(len(data)) + 1 + + enc, err := NewGzipEncoder() + require.NoError(b, err) + dec := NewGzipDecoder(WithMaxDecompressionSize(dataLen)) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + payload, err := enc.Encode(data) + require.NoError(b, err) + + _, err = dec.Decode(payload) + require.NoError(b, err) + } +} + +func BenchmarkZstdEncode(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 64)) + dataLen := int64(len(data)) + 1 + + enc, err := NewZstdEncoder() + require.NoError(b, err) + dec, err := NewZstdDecoder(WithMaxDecompressionSize(dataLen)) + require.NoError(b, err) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + _, err := enc.Encode(data) + require.NoError(b, err) + } +} + +func BenchmarkZstdDecode(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 64)) + dataLen := int64(len(data)) + 1 + + enc, err := NewZstdEncoder() + require.NoError(b, err) + dec, err := NewZstdDecoder(WithMaxDecompressionSize(dataLen)) + require.NoError(b, err) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + _, err = dec.Decode(payload) + require.NoError(b, err) + } +} + +func BenchmarkZstdEncodeDecode(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 64)) + dataLen := int64(len(data)) + 1 + + enc, err := NewZstdEncoder() + require.NoError(b, err) + dec, err := NewZstdDecoder(WithMaxDecompressionSize(dataLen)) + require.NoError(b, err) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + payload, err := enc.Encode(data) + require.NoError(b, err) + + _, err = dec.Decode(payload) + require.NoError(b, err) + } +} + +func BenchmarkZstdEncodeBig(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 1024*1024)) + dataLen := int64(len(data)) + 1 + + enc, err := NewZstdEncoder() + require.NoError(b, err) + dec, err := NewZstdDecoder(WithMaxDecompressionSize(dataLen)) + require.NoError(b, err) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + _, err := enc.Encode(data) + require.NoError(b, err) + } +} + +func BenchmarkZstdDecodeBig(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 1024*1024)) + dataLen := int64(len(data)) + 1 + + enc, err := NewZstdEncoder() + require.NoError(b, err) + dec, err := NewZstdDecoder(WithMaxDecompressionSize(dataLen)) + require.NoError(b, err) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + _, err = dec.Decode(payload) + require.NoError(b, err) + } +} + +func BenchmarkZstdEncodeDecodeBig(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 1024*1024)) + dataLen := int64(len(data)) + 1 + + enc, err := NewZstdEncoder() + require.NoError(b, err) + dec, err := NewZstdDecoder(WithMaxDecompressionSize(dataLen)) + require.NoError(b, err) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + payload, err := enc.Encode(data) + require.NoError(b, err) + + _, err = dec.Decode(payload) + require.NoError(b, err) + } +} + +func BenchmarkZlibEncode(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 64)) + dataLen := int64(len(data)) + 1 + + enc, err := NewZlibEncoder() + require.NoError(b, err) + dec := NewZlibDecoder(WithMaxDecompressionSize(dataLen)) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + _, err := enc.Encode(data) + require.NoError(b, err) + } +} + +func BenchmarkZlibDecode(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 64)) + dataLen := int64(len(data)) + 1 + + enc, err := NewZlibEncoder() + require.NoError(b, err) + dec := NewZlibDecoder(WithMaxDecompressionSize(dataLen)) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + _, err = dec.Decode(payload) + require.NoError(b, err) + } +} + +func BenchmarkZlibEncodeDecode(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 64)) + dataLen := int64(len(data)) + 1 + + enc, err := NewZlibEncoder() + require.NoError(b, err) + dec := NewZlibDecoder(WithMaxDecompressionSize(dataLen)) + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + payload, err := enc.Encode(data) + require.NoError(b, err) + + _, err = dec.Decode(payload) + require.NoError(b, err) + } +} + +func BenchmarkIdentityEncodeDecode(b *testing.B) { + data := []byte(strings.Repeat("-howdy stranger-", 64)) + dataLen := int64(len(data)) + 1 + + dec := NewIdentityDecoder(WithMaxDecompressionSize(dataLen)) + enc, err := NewIdentityEncoder() + require.NoError(b, err) + + payload, err := enc.Encode(data) + require.NoError(b, err) + actual, err := dec.Decode(payload) + require.NoError(b, err) + require.Equal(b, data, actual) + + for n := 0; n < b.N; n++ { + payload, err := enc.Encode(data) + require.NoError(b, err) + + _, err = dec.Decode(payload) + require.NoError(b, err) + } +} diff --git a/internal/customized_no.go b/internal/customized_no.go new file mode 100644 index 0000000..ec361b0 --- /dev/null +++ b/internal/customized_no.go @@ -0,0 +1,5 @@ +//go:build !custom + +package internal + +const Customized = "" diff --git a/internal/customized_yes.go b/internal/customized_yes.go new file mode 100644 index 0000000..dbf2203 --- /dev/null +++ b/internal/customized_yes.go @@ -0,0 +1,5 @@ +//go:build custom + +package internal + +const Customized = " (customized)" diff --git a/internal/docker/docker.go b/internal/docker/docker.go new file mode 100644 index 0000000..c24f6a1 --- /dev/null +++ b/internal/docker/docker.go @@ -0,0 +1,33 @@ +package docker + +import "strings" + +// ParseImage Adapts some of the logic from the actual Docker library's image parsing routines: +// https://github.com/docker/distribution/blob/release/2.7/reference/normalize.go +func ParseImage(image string) (imageName, imageVersion string) { + domain := "" + remainder := "" + + i := strings.IndexRune(image, '/') + + if i == -1 || (!strings.ContainsAny(image[:i], ".:") && image[:i] != "localhost") { + remainder = image + } else { + domain, remainder = image[:i], image[i+1:] + } + + imageVersion = "unknown" + i = strings.LastIndex(remainder, ":") + if i > -1 { + imageVersion = remainder[i+1:] + imageName = remainder[:i] + } else { + imageName = remainder + } + + if domain != "" { + imageName = domain + "/" + imageName + } + + return imageName, imageVersion +} diff --git a/internal/docker/docker_test.go b/internal/docker/docker_test.go new file mode 100644 index 0000000..f8a22ac --- /dev/null +++ b/internal/docker/docker_test.go @@ -0,0 +1,60 @@ +package docker_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/influxdata/telegraf/internal/docker" +) + +func TestParseImage(t *testing.T) { + tests := []struct { + image string + parsedName string + parsedVersion string + }{ + { + image: "postgres", + parsedName: "postgres", + parsedVersion: "unknown", + }, + { + image: "postgres:latest", + parsedName: "postgres", + parsedVersion: "latest", + }, + { + image: "coreos/etcd", + parsedName: "coreos/etcd", + parsedVersion: "unknown", + }, + { + image: "coreos/etcd:latest", + parsedName: "coreos/etcd", + parsedVersion: "latest", + }, + { + image: "quay.io/postgres", + parsedName: "quay.io/postgres", + parsedVersion: "unknown", + }, + { + image: "quay.io:4443/coreos/etcd", + parsedName: "quay.io:4443/coreos/etcd", + parsedVersion: "unknown", + }, + { + image: "quay.io:4443/coreos/etcd:latest", + parsedName: "quay.io:4443/coreos/etcd", + parsedVersion: "latest", + }, + } + for _, tt := range tests { + t.Run("parse name "+tt.image, func(t *testing.T) { + imageName, imageVersion := docker.ParseImage(tt.image) + require.Equal(t, tt.parsedName, imageName) + require.Equal(t, tt.parsedVersion, imageVersion) + }) + } +} diff --git a/internal/env.go b/internal/env.go new file mode 100644 index 0000000..e91c4f0 --- /dev/null +++ b/internal/env.go @@ -0,0 +1,19 @@ +package internal + +import "os" + +// GetProcPath returns the path stored in HOST_PROC env variable, or /proc if HOST_PROC has not been set. +func GetProcPath() string { + if hostProc := os.Getenv("HOST_PROC"); hostProc != "" { + return hostProc + } + return "/proc" +} + +// GetSysPath returns the path stored in HOST_SYS env variable, or /sys if HOST_SYS has not been set. +func GetSysPath() string { + if hostSys := os.Getenv("HOST_SYS"); hostSys != "" { + return hostSys + } + return "/sys" +} diff --git a/internal/errors.go b/internal/errors.go new file mode 100644 index 0000000..a36bda7 --- /dev/null +++ b/internal/errors.go @@ -0,0 +1,63 @@ +package internal + +import "errors" + +var ( + ErrNotConnected = errors.New("not connected") + ErrSerialization = errors.New("serialization of metric(s) failed") + ErrSizeLimitReached = errors.New("size limit reached") +) + +// StartupError indicates an error that occurred during startup of a plugin +// e.g. due to connectivity issues or resources being not yet available. +// In case the 'Retry' flag is set, the startup of the plugin might be retried +// depending on the configured startup-error-behavior. The 'RemovePlugin' +// flag denotes if the agent should remove the plugin from further processing. +type StartupError struct { + Err error + Retry bool + Partial bool +} + +func (e *StartupError) Error() string { + return e.Err.Error() +} + +func (e *StartupError) Unwrap() error { + return e.Err +} + +// FatalError indicates a not-recoverable error in the plugin. The corresponding +// plugin should be remove by the agent stopping any further processing for that +// plugin instance. +type FatalError struct { + Err error +} + +func (e *FatalError) Error() string { + return e.Err.Error() +} + +func (e *FatalError) Unwrap() error { + return e.Err +} + +// PartialWriteError indicate that only a subset of the metrics were written +// successfully (i.e. accepted). The rejected metrics should be removed from +// the buffer without being successfully written. Please note: the metrics +// are specified as indices into the batch to be able to reference tracking +// metrics correctly. +type PartialWriteError struct { + Err error + MetricsAccept []int + MetricsReject []int + MetricsRejectErrors []error +} + +func (e *PartialWriteError) Error() string { + return e.Err.Error() +} + +func (e *PartialWriteError) Unwrap() error { + return e.Err +} diff --git a/internal/exec.go b/internal/exec.go new file mode 100644 index 0000000..7fe95c0 --- /dev/null +++ b/internal/exec.go @@ -0,0 +1,44 @@ +package internal + +import ( + "bytes" + "os/exec" + "time" +) + +// CombinedOutputTimeout runs the given command with the given timeout and +// returns the combined output of stdout and stderr. +// If the command times out, it attempts to kill the process. +func CombinedOutputTimeout(c *exec.Cmd, timeout time.Duration) ([]byte, error) { + var b bytes.Buffer + c.Stdout = &b + c.Stderr = &b + if err := c.Start(); err != nil { + return nil, err + } + err := WaitTimeout(c, timeout) + return b.Bytes(), err +} + +// StdOutputTimeout runs the given command with the given timeout and +// returns the output of stdout. +// If the command times out, it attempts to kill the process. +func StdOutputTimeout(c *exec.Cmd, timeout time.Duration) ([]byte, error) { + var b bytes.Buffer + c.Stdout = &b + c.Stderr = nil + if err := c.Start(); err != nil { + return nil, err + } + err := WaitTimeout(c, timeout) + return b.Bytes(), err +} + +// RunTimeout runs the given command with the given timeout. +// If the command times out, it attempts to kill the process. +func RunTimeout(c *exec.Cmd, timeout time.Duration) error { + if err := c.Start(); err != nil { + return err + } + return WaitTimeout(c, timeout) +} diff --git a/internal/exec_unix.go b/internal/exec_unix.go new file mode 100644 index 0000000..9a012f7 --- /dev/null +++ b/internal/exec_unix.go @@ -0,0 +1,66 @@ +//go:build !windows + +package internal + +import ( + "log" + "os/exec" + "syscall" + "time" +) + +// KillGrace is the amount of time we allow a process to shutdown before +// sending a SIGKILL. +const KillGrace = 5 * time.Second + +// WaitTimeout waits for the given command to finish with a timeout. +// It assumes the command has already been started. +// If the command times out, it attempts to kill the process. +func WaitTimeout(c *exec.Cmd, timeout time.Duration) error { + var kill *time.Timer + term := time.AfterFunc(timeout, func() { + err := syscall.Kill(-c.Process.Pid, syscall.SIGTERM) + if err != nil { + log.Printf("E! [agent] Error terminating process children: %s", err) + } + err = c.Process.Signal(syscall.SIGTERM) + if err != nil { + log.Printf("E! [agent] Error terminating process: %s", err) + return + } + + kill = time.AfterFunc(KillGrace, func() { + err := syscall.Kill(-c.Process.Pid, syscall.SIGKILL) + if err != nil { + log.Printf("E! [agent] Error terminating process children: %s", err) + } + err = c.Process.Kill() + if err != nil { + log.Printf("E! [agent] Error killing process: %s", err) + return + } + }) + }) + + err := c.Wait() + + // Shutdown all timers + if kill != nil { + kill.Stop() + } + termSent := !term.Stop() + + // If the process exited without error treat it as success. This allows a + // process to do a clean shutdown on signal. + if err == nil { + return nil + } + + // If SIGTERM was sent then treat any process error as a timeout. + if termSent { + return ErrTimeout + } + + // Otherwise there was an error unrelated to termination. + return err +} diff --git a/internal/exec_windows.go b/internal/exec_windows.go new file mode 100644 index 0000000..a577b86 --- /dev/null +++ b/internal/exec_windows.go @@ -0,0 +1,41 @@ +//go:build windows + +package internal + +import ( + "log" + "os/exec" + "time" +) + +// WaitTimeout waits for the given command to finish with a timeout. +// It assumes the command has already been started. +// If the command times out, it attempts to kill the process. +func WaitTimeout(c *exec.Cmd, timeout time.Duration) error { + timer := time.AfterFunc(timeout, func() { + err := c.Process.Kill() + if err != nil { + log.Printf("E! [agent] Error killing process: %s", err) + return + } + }) + + err := c.Wait() + + // Shutdown all timers + termSent := !timer.Stop() + + // If the process exited without error treat it as success. This allows a + // process to do a clean shutdown on signal. + if err == nil { + return nil + } + + // If SIGTERM was sent then treat any process error as a timeout. + if termSent { + return ErrTimeout + } + + // Otherwise there was an error unrelated to termination. + return err +} diff --git a/internal/fuzz/json.go b/internal/fuzz/json.go new file mode 100644 index 0000000..54faef6 --- /dev/null +++ b/internal/fuzz/json.go @@ -0,0 +1,42 @@ +package fuzz + +// https://github.com/google/AFL/blob/master/dictionaries/json.dict +var JSONDictionary = []string{ + "0", + ",0", + ":0", + "0:", + "-1.2e+3", + "true", + "false", + "null", + "\"\"", + ",\"\"", + ":\"\"", + "\"\":", + "{}", + ",{}", + ":{}", + "{\"\":0}", + "{{}}", + "[]", + ",[]", + ":[]", + "[0]", + "[[]]", + "''", + "\\", + "\\b", + "\\f", + "\\n", + "\\r", + "\\t", + "\\u0000", + "\\x00", + "\\0", + "\\uD800\\uDC00", + "\\uDBFF\\uDFFF", + "\"\":0", + "//", + "/**/", +} diff --git a/internal/globpath/globpath.go b/internal/globpath/globpath.go new file mode 100644 index 0000000..d18b90b --- /dev/null +++ b/internal/globpath/globpath.go @@ -0,0 +1,97 @@ +package globpath + +import ( + "os" + "path/filepath" + "strings" + + "github.com/bmatcuk/doublestar/v3" + "github.com/gobwas/glob" +) + +type GlobPath struct { + path string + hasMeta bool + HasSuperMeta bool + rootGlob string + g glob.Glob +} + +func Compile(path string) (*GlobPath, error) { + out := GlobPath{ + hasMeta: hasMeta(path), + HasSuperMeta: hasSuperMeta(path), + path: filepath.FromSlash(path), + } + + // if there are no glob meta characters in the path, don't bother compiling + // a glob object + if !out.hasMeta || !out.HasSuperMeta { + return &out, nil + } + + // find the root elements of the object path, the entry point for recursion + // when you have a super-meta in your path (which are : + // glob(/your/expression/until/first/star/of/super-meta)) + out.rootGlob = path[:strings.Index(path, "**")+1] + var err error + if out.g, err = glob.Compile(path, os.PathSeparator); err != nil { + return nil, err + } + return &out, nil +} + +// Match returns all files matching the expression. +// If it's a static path, returns path. +// All returned path will have the host platform separator. +func (g *GlobPath) Match() []string { + // This string replacement is for backwards compatibility support + // The original implementation allowed **.txt but the double star package requires **/**.txt + g.path = strings.ReplaceAll(g.path, "**/**", "**") + g.path = strings.ReplaceAll(g.path, "**", "**/**") + + //nolint:errcheck // pattern is known + files, _ := doublestar.Glob(g.path) + return files +} + +// MatchString tests the path string against the glob. The path should contain +// the host platform separator. +func (g *GlobPath) MatchString(path string) bool { + if !g.HasSuperMeta { + //nolint:errcheck // pattern is known + res, _ := filepath.Match(g.path, path) + return res + } + return g.g.Match(path) +} + +// GetRoots returns a list of files and directories which should be optimal +// prefixes of matching files when you have a super-meta in your expression : +// - any directory under these roots may contain a matching file +// - no file outside of these roots can match the pattern +// Note that it returns both files and directories. +// All returned path will have the host platform separator. +func (g *GlobPath) GetRoots() []string { + if !g.hasMeta { + return []string{g.path} + } + if !g.HasSuperMeta { + //nolint:errcheck // pattern is known + matches, _ := filepath.Glob(g.path) + return matches + } + //nolint:errcheck // pattern is known + roots, _ := filepath.Glob(g.rootGlob) + return roots +} + +// hasMeta reports whether path contains any magic glob characters. +func hasMeta(path string) bool { + return strings.ContainsAny(path, "*?[") +} + +// hasSuperMeta reports whether path contains any super magic glob characters (**). +func hasSuperMeta(path string) bool { + return strings.Contains(path, "**") +} diff --git a/internal/globpath/globpath_test.go b/internal/globpath/globpath_test.go new file mode 100644 index 0000000..09047ea --- /dev/null +++ b/internal/globpath/globpath_test.go @@ -0,0 +1,124 @@ +//go:build !windows + +// TODO: Windows - should be enabled for Windows when super asterisk is fixed on Windows +// https://github.com/influxdata/telegraf/issues/6248 + +package globpath + +import ( + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/stretchr/testify/require" +) + +var ( + testdataDir = getTestdataDir() +) + +func TestCompileAndMatch(t *testing.T) { + type test struct { + path string + matches int + } + + tests := []test{ + // test super asterisk + {path: filepath.Join(testdataDir, "**"), matches: 7}, + // test single asterisk + {path: filepath.Join(testdataDir, "*.log"), matches: 3}, + // test no meta characters (file exists) + {path: filepath.Join(testdataDir, "log1.log"), matches: 1}, + // test file that doesn't exist + {path: filepath.Join(testdataDir, "i_dont_exist.log"), matches: 0}, + // test super asterisk that doesn't exist + {path: filepath.Join(testdataDir, "dir_doesnt_exist", "**"), matches: 0}, + // test exclamation mark creates non-matching list with a range + {path: filepath.Join(testdataDir, "log[!1-2]*"), matches: 1}, + // test caret creates non-matching list + {path: filepath.Join(testdataDir, "log[^1-2]*"), matches: 1}, + // test exclamation mark creates non-matching list without a range + {path: filepath.Join(testdataDir, "log[!2]*"), matches: 2}, + // test exclamation mark creates non-matching list without a range + //nolint:gocritic // filepathJoin - '\\' used to escape in glob, not path separator + {path: filepath.Join(testdataDir, "log\\[!*"), matches: 1}, + // test exclamation mark creates non-matching list without a range + //nolint:gocritic // filepathJoin - '\\' used to escape in glob, not path separator + {path: filepath.Join(testdataDir, "log\\[^*"), matches: 0}, + } + + for _, tc := range tests { + g, err := Compile(tc.path) + require.NoError(t, err) + matches := g.Match() + require.Len(t, matches, tc.matches) + } +} + +func TestRootGlob(t *testing.T) { + tests := []struct { + input string + output string + }{ + {filepath.Join(testdataDir, "**"), filepath.Join(testdataDir, "*")}, + {filepath.Join(testdataDir, "nested?", "**"), filepath.Join(testdataDir, "nested?", "*")}, + {filepath.Join(testdataDir, "ne**", "nest*"), filepath.Join(testdataDir, "ne*")}, + {filepath.Join(testdataDir, "nested?", "*"), ""}, + } + + for _, test := range tests { + actual, err := Compile(test.input) + require.NoError(t, err) + require.Equal(t, actual.rootGlob, test.output) + } +} + +func TestFindNestedTextFile(t *testing.T) { + // test super asterisk + g1, err := Compile(filepath.Join(testdataDir, "**.txt")) + require.NoError(t, err) + + matches := g1.Match() + require.Len(t, matches, 1) +} + +func TestMatch_ErrPermission(t *testing.T) { + tests := []struct { + input string + expected []string + }{ + {"/root/foo", []string(nil)}, + {"/root/f*", []string(nil)}, + } + + for _, test := range tests { + glob, err := Compile(test.input) + require.NoError(t, err) + actual := glob.Match() + require.Equal(t, test.expected, actual) + } +} + +func TestWindowsSeparator(t *testing.T) { + //nolint:staticcheck // Silence linter for now as we plan to reenable tests for Windows later + if runtime.GOOS != "windows" { + t.Skip("Skipping Windows only test") + } + + glob, err := Compile("testdata/nested1") + require.NoError(t, err) + ok := glob.MatchString("testdata\\nested1") + require.True(t, ok) +} + +func getTestdataDir() string { + dir, err := os.Getwd() + if err != nil { + // if we cannot even establish the test directory, further progress is meaningless + panic(err) + } + + return filepath.Join(dir, "testdata") +} diff --git a/internal/globpath/testdata/log1.log b/internal/globpath/testdata/log1.log new file mode 100644 index 0000000..e69de29 diff --git a/internal/globpath/testdata/log2.log b/internal/globpath/testdata/log2.log new file mode 100644 index 0000000..e69de29 diff --git a/internal/globpath/testdata/log[!.log b/internal/globpath/testdata/log[!.log new file mode 100644 index 0000000..e69de29 diff --git a/internal/globpath/testdata/nested1/nested2/nested.txt b/internal/globpath/testdata/nested1/nested2/nested.txt new file mode 100644 index 0000000..e69de29 diff --git a/internal/globpath/testdata/test.conf b/internal/globpath/testdata/test.conf new file mode 100644 index 0000000..a061119 --- /dev/null +++ b/internal/globpath/testdata/test.conf @@ -0,0 +1,5 @@ +# this is a fake testing config file +# for testing the filestat plugin + +option1 = "foo" +option2 = "bar" diff --git a/internal/goplugin/noplugin.go b/internal/goplugin/noplugin.go new file mode 100644 index 0000000..b14e78f --- /dev/null +++ b/internal/goplugin/noplugin.go @@ -0,0 +1,9 @@ +//go:build !goplugin + +package goplugin + +import "errors" + +func LoadExternalPlugins(_ string) error { + return errors.New("go plugin support is not enabled") +} diff --git a/internal/goplugin/plugin.go b/internal/goplugin/plugin.go new file mode 100644 index 0000000..c2d18d0 --- /dev/null +++ b/internal/goplugin/plugin.go @@ -0,0 +1,42 @@ +//go:build goplugin + +package goplugin + +import ( + "fmt" + "os" + "path" + "path/filepath" + "plugin" + "strings" +) + +// loadExternalPlugins loads external plugins from shared libraries (.so, .dll, etc.) +// in the specified directory. +func LoadExternalPlugins(rootDir string) error { + return filepath.Walk(rootDir, func(pth string, info os.FileInfo, err error) error { + // Stop if there was an error. + if err != nil { + return err + } + + // Ignore directories. + if info.IsDir() { + return nil + } + + // Ignore files that aren't shared libraries. + ext := strings.ToLower(path.Ext(pth)) + if ext != ".so" && ext != ".dll" { + return nil + } + + // Load plugin. + _, err = plugin.Open(pth) + if err != nil { + return fmt.Errorf("error loading %s: %s", pth, err) + } + + return nil + }) +} diff --git a/internal/host_endianness_be.go b/internal/host_endianness_be.go new file mode 100644 index 0000000..dbc7a3a --- /dev/null +++ b/internal/host_endianness_be.go @@ -0,0 +1,7 @@ +//go:build armbe || arm64be || mips || mips64 || mips64p32 || ppc || ppc64 || s390 || s390x || sparc || sparc64 + +package internal + +import "encoding/binary" + +var HostEndianness = binary.BigEndian diff --git a/internal/host_endianness_le.go b/internal/host_endianness_le.go new file mode 100644 index 0000000..2d5fba0 --- /dev/null +++ b/internal/host_endianness_le.go @@ -0,0 +1,7 @@ +//go:build 386 || amd64 || amd64p32 || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || ppc64le || riscv || riscv64 || wasm + +package internal + +import "encoding/binary" + +var HostEndianness = binary.LittleEndian diff --git a/internal/http.go b/internal/http.go new file mode 100644 index 0000000..832f82e --- /dev/null +++ b/internal/http.go @@ -0,0 +1,227 @@ +package internal + +import ( + "crypto/subtle" + "errors" + "fmt" + "net" + "net/http" + "net/url" + "strings" + + "github.com/golang-jwt/jwt/v5" +) + +type BasicAuthErrorFunc func(rw http.ResponseWriter) + +// JWTAuthHandler returns a http handler that requires the HTTP bearer auth +// token to be valid and match the given user. +func JWTAuthHandler(secret, username string, onError BasicAuthErrorFunc) func(h http.Handler) http.Handler { + return func(h http.Handler) http.Handler { + return &jwtAuthHandler{ + secret: []byte(secret), + username: []byte(username), + onError: onError, + next: h, + } + } +} + +type jwtAuthHandler struct { + secret []byte + username []byte + onError BasicAuthErrorFunc + next http.Handler +} + +func (h *jwtAuthHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + authHeader := req.Header.Get("Authentication") + if !strings.HasPrefix(authHeader, "Bearer ") { + h.onError(rw) + http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + return + } + bearer := strings.TrimPrefix(authHeader, "Bearer ") + token, err := jwt.Parse(bearer, func(t *jwt.Token) (interface{}, error) { + if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", t.Method) + } + return h.secret, nil + }) + if err != nil || !token.Valid { + h.onError(rw) + if err != nil && errors.Is(err, jwt.ErrTokenExpired) { + http.Error(rw, "token expired", http.StatusUnauthorized) + } else if err != nil { + http.Error(rw, "invalid token: "+err.Error(), http.StatusUnauthorized) + } else { + http.Error(rw, "invalid token", http.StatusUnauthorized) + } + return + } + + claims, ok := token.Claims.(jwt.MapClaims) + if !ok { + h.onError(rw) + http.Error(rw, "problem authenticating token", http.StatusInternalServerError) + return + } + + username, ok := claims["username"].(string) + if !ok || username == "" { + h.onError(rw) + http.Error(rw, "token must contain a string username", http.StatusUnauthorized) + return + } + if subtle.ConstantTimeCompare([]byte(username), h.username) != 1 { + h.onError(rw) + http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + return + } + + h.next.ServeHTTP(rw, req) +} + +// BasicAuthHandler returns a http handler that requires HTTP basic auth +// credentials to match the given username and password. +func BasicAuthHandler(username, password, realm string, onError BasicAuthErrorFunc) func(h http.Handler) http.Handler { + return func(h http.Handler) http.Handler { + return &basicAuthHandler{ + username: username, + password: password, + realm: realm, + onError: onError, + next: h, + } + } +} + +type basicAuthHandler struct { + username string + password string + realm string + onError BasicAuthErrorFunc + next http.Handler +} + +func (h *basicAuthHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + if h.username == "" && h.password == "" { + h.next.ServeHTTP(rw, req) + return + } + + var reqUsername, reqPassword string + var ok bool + authHeader := req.Header.Get("Authorization") + if strings.HasPrefix(authHeader, "Token ") { + token := strings.TrimPrefix(authHeader, "Token ") + reqUsername, reqPassword, ok = strings.Cut(token, ":") + } else { + reqUsername, reqPassword, ok = req.BasicAuth() + } + + if !ok || + subtle.ConstantTimeCompare([]byte(reqUsername), []byte(h.username)) != 1 || + subtle.ConstantTimeCompare([]byte(reqPassword), []byte(h.password)) != 1 { + rw.Header().Set("WWW-Authenticate", "Basic realm=\""+h.realm+"\"") + h.onError(rw) + http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + return + } + + h.next.ServeHTTP(rw, req) +} + +type GenericAuthErrorFunc func(rw http.ResponseWriter) + +// GenericAuthHandler returns a http handler that requires `Authorization: ` +func GenericAuthHandler(credentials string, onError GenericAuthErrorFunc) func(h http.Handler) http.Handler { + return func(h http.Handler) http.Handler { + return &genericAuthHandler{ + credentials: credentials, + onError: onError, + next: h, + } + } +} + +// Generic auth scheme handler - exact match on `Authorization: ` +type genericAuthHandler struct { + credentials string + onError GenericAuthErrorFunc + next http.Handler +} + +func (h *genericAuthHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + if h.credentials != "" { + // Scheme checking + authorization := req.Header.Get("Authorization") + if subtle.ConstantTimeCompare([]byte(authorization), []byte(h.credentials)) != 1 { + h.onError(rw) + http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + return + } + } + + h.next.ServeHTTP(rw, req) +} + +// ErrorFunc is a callback for writing an error response. +type ErrorFunc func(rw http.ResponseWriter, code int) + +// IPRangeHandler returns a http handler that requires the remote address to be +// in the specified network. +func IPRangeHandler(networks []*net.IPNet, onError ErrorFunc) func(h http.Handler) http.Handler { + return func(h http.Handler) http.Handler { + return &ipRangeHandler{ + networks: networks, + onError: onError, + next: h, + } + } +} + +type ipRangeHandler struct { + networks []*net.IPNet + onError ErrorFunc + next http.Handler +} + +func (h *ipRangeHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + if len(h.networks) == 0 { + h.next.ServeHTTP(rw, req) + return + } + + remoteIPString, _, err := net.SplitHostPort(req.RemoteAddr) + if err != nil { + h.onError(rw, http.StatusForbidden) + return + } + + remoteIP := net.ParseIP(remoteIPString) + if remoteIP == nil { + h.onError(rw, http.StatusForbidden) + return + } + + for _, network := range h.networks { + if network.Contains(remoteIP) { + h.next.ServeHTTP(rw, req) + return + } + } + + h.onError(rw, http.StatusForbidden) +} + +func OnClientError(client *http.Client, err error) { + // Close connection after a timeout error. If this is a HTTP2 + // connection this ensures that next interval a new connection will be + // used and name lookup will be performed. + // https://github.com/golang/go/issues/36026 + var urlErr *url.Error + if errors.As(err, &urlErr) && urlErr.Timeout() { + client.CloseIdleConnections() + } +} diff --git a/internal/internal.go b/internal/internal.go new file mode 100644 index 0000000..aa50dda --- /dev/null +++ b/internal/internal.go @@ -0,0 +1,441 @@ +package internal + +import ( + "bufio" + "compress/gzip" + "context" + crypto_rand "crypto/rand" + "errors" + "fmt" + "io" + "log" + "math/big" + "math/rand" + "os" + "os/exec" + "runtime" + "strings" + "sync" + "syscall" + "time" + "unicode" + + "github.com/influxdata/telegraf/internal/choice" +) + +const alphanum string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +const NoMetricsCreatedMsg = "No metrics were created from a message. Verify your parser settings. This message is only printed once." + +var once sync.Once + +var ( + ErrTimeout = errors.New("command timed out") + ErrNotImplemented = errors.New("not implemented yet") +) + +// Set via LDFLAGS -X +var ( + Version = "unknown" + Branch = "" + Commit = "" +) + +type ReadWaitCloser struct { + pipeReader *io.PipeReader + wg sync.WaitGroup +} + +func FormatFullVersion() string { + var parts = []string{"Telegraf"} + + if Version != "" { + parts = append(parts, Version) + } else { + parts = append(parts, "unknown") + } + + if Branch != "" || Commit != "" { + if Branch == "" { + Branch = "unknown" + } + if Commit == "" { + Commit = "unknown" + } + git := fmt.Sprintf("(git: %s@%s)", Branch, Commit) + parts = append(parts, git) + } + + return strings.Join(parts, " ") +} + +// ProductToken returns a tag for Telegraf that can be used in user agents. +func ProductToken() string { + return fmt.Sprintf("Telegraf/%s Go/%s", + Version, strings.TrimPrefix(runtime.Version(), "go")) +} + +// ReadLines reads contents from a file and splits them by new lines. +func ReadLines(filename string) ([]string, error) { + f, err := os.Open(filename) + if err != nil { + return []string{""}, err + } + defer f.Close() + + var ret []string + scanner := bufio.NewScanner(f) + for scanner.Scan() { + ret = append(ret, scanner.Text()) + } + + return ret, nil +} + +// RandomString returns a random string of alphanumeric characters +func RandomString(n int) (string, error) { + var bytes = make([]byte, n) + _, err := crypto_rand.Read(bytes) + if err != nil { + return "", err + } + for i, b := range bytes { + bytes[i] = alphanum[b%byte(len(alphanum))] + } + return string(bytes), nil +} + +// SnakeCase converts the given string to snake case following the Golang format: +// acronyms are converted to lower-case and preceded by an underscore. +func SnakeCase(in string) string { + runes := []rune(in) + length := len(runes) + + var out []rune + for i := 0; i < length; i++ { + if i > 0 && unicode.IsUpper(runes[i]) { + prevLower := unicode.IsLower(runes[i-1]) + nextLower := i+1 < length && unicode.IsLower(runes[i+1]) + // Special case for plural acronyms + nextPlural := i+1 < length && runes[i+1] == 's' + + if prevLower || (nextLower && !nextPlural) { + out = append(out, '_') + } + } + out = append(out, unicode.ToLower(runes[i])) + } + + return string(out) +} + +// RandomSleep will sleep for a random amount of time up to max. +// If the shutdown channel is closed, it will return before it has finished sleeping. +func RandomSleep(limit time.Duration, shutdown chan struct{}) { + sleepDuration := RandomDuration(limit) + if sleepDuration == 0 { + return + } + + t := time.NewTimer(time.Nanosecond * sleepDuration) + select { + case <-t.C: + return + case <-shutdown: + t.Stop() + return + } +} + +// RandomDuration returns a random duration between 0 and max. +func RandomDuration(limit time.Duration) time.Duration { + if limit == 0 { + return 0 + } + + return time.Duration(rand.Int63n(limit.Nanoseconds())) //nolint:gosec // G404: not security critical +} + +// SleepContext sleeps until the context is closed or the duration is reached. +func SleepContext(ctx context.Context, duration time.Duration) error { + if duration == 0 { + return nil + } + + t := time.NewTimer(duration) + select { + case <-t.C: + return nil + case <-ctx.Done(): + t.Stop() + return ctx.Err() + } +} + +// AlignDuration returns the duration until next aligned interval. +// If the current time is aligned a 0 duration is returned. +func AlignDuration(tm time.Time, interval time.Duration) time.Duration { + return AlignTime(tm, interval).Sub(tm) +} + +// AlignTime returns the time of the next aligned interval. +// If the current time is aligned the current time is returned. +func AlignTime(tm time.Time, interval time.Duration) time.Time { + truncated := tm.Truncate(interval) + if truncated.Equal(tm) { + return tm + } + return truncated.Add(interval) +} + +// ExitStatus takes the error from exec.Command +// and returns the exit status and true +// if error is not exit status, will return 0 and false +func ExitStatus(err error) (int, bool) { + var exitErr *exec.ExitError + if errors.As(err, &exitErr) { + if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { + return status.ExitStatus(), true + } + } + return 0, false +} + +func (r *ReadWaitCloser) Close() error { + err := r.pipeReader.Close() + r.wg.Wait() // wait for the gzip goroutine finish + return err +} + +// CompressWithGzip takes an io.Reader as input and pipes it through a +// gzip.Writer returning an io.Reader containing the gzipped data. +// Errors occurring during compression are returned to the instance reading +// from the returned reader via through the corresponding read call +// (e.g. io.Copy or io.ReadAll). +func CompressWithGzip(data io.Reader) io.ReadCloser { + pipeReader, pipeWriter := io.Pipe() + gzipWriter := gzip.NewWriter(pipeWriter) + + // Start copying from the uncompressed reader to the output reader + // in the background until the input reader is closed (or errors out). + go func() { + // This copy will block until "data" reached EOF or an error occurs + _, err := io.Copy(gzipWriter, data) + + // Close the compression writer and make sure we do not overwrite + // the copy error if any. + gzipErr := gzipWriter.Close() + if err == nil { + err = gzipErr + } + + // Subsequent reads from the output reader (connected to "pipeWriter" + // via pipe) will return the copy (or closing) error if any to the + // instance reading from the reader returned by the CompressWithGzip + // function. If "err" is nil, the below function will correctly report + // io.EOF. + pipeWriter.CloseWithError(err) + }() + + // Return a reader which then can be read by the caller to collect the + // compressed stream. + return pipeReader +} + +// ParseTimestamp parses a Time according to the standard Telegraf options. +// These are generally displayed in the toml similar to: +// +// json_time_key= "timestamp" +// json_time_format = "2006-01-02T15:04:05Z07:00" +// json_timezone = "America/Los_Angeles" +// +// The format can be one of "unix", "unix_ms", "unix_us", "unix_ns", or a Go +// time layout suitable for time.Parse. +// +// When using the "unix" format, an optional fractional component is allowed. +// Specific unix time precisions cannot have a fractional component. +// +// Unix times may be an int64, float64, or string. When using a Go format +// string the timestamp must be a string. +// +// The location is a location string suitable for time.LoadLocation. Unix +// times do not use the location string, a unix time is always return in the +// UTC location. +func ParseTimestamp(format string, timestamp interface{}, location *time.Location, separator ...string) (time.Time, error) { + switch format { + case "unix", "unix_ms", "unix_us", "unix_ns": + sep := []string{",", "."} + if len(separator) > 0 { + sep = separator + } + return parseUnix(format, timestamp, sep) + default: + v, ok := timestamp.(string) + if !ok { + return time.Unix(0, 0), errors.New("unsupported type") + } + return parseTime(format, v, location) + } +} + +// parseTime parses a timestamp in unix format with different resolutions +func parseUnix(format string, timestamp interface{}, separator []string) (time.Time, error) { + // Extract the scaling factor to nanoseconds from "format" + var factor int64 + switch format { + case "unix": + factor = int64(time.Second) + case "unix_ms": + factor = int64(time.Millisecond) + case "unix_us": + factor = int64(time.Microsecond) + case "unix_ns": + factor = int64(time.Nanosecond) + } + + zero := time.Unix(0, 0) + + // Convert the representation to time + switch v := timestamp.(type) { + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: + t, err := ToInt64(v) + if err != nil { + return zero, err + } + return time.Unix(0, t*factor).UTC(), nil + case float32, float64: + ts, err := ToFloat64(v) + if err != nil { + return zero, err + } + + // Parse the float as a precise fraction to avoid precision loss + f := big.Rat{} + if f.SetFloat64(ts) == nil { + return zero, errors.New("invalid number") + } + return timeFromFraction(&f, factor), nil + case string: + // Sanitize the string to have no thousand separators and dot + // as decimal separator to ease later parsing + v = sanitizeTimestamp(v, separator) + + // Parse the string as a precise fraction to avoid precision loss + f := big.Rat{} + if _, ok := f.SetString(v); !ok { + return zero, errors.New("invalid number") + } + return timeFromFraction(&f, factor), nil + } + + return zero, errors.New("unsupported type") +} + +func timeFromFraction(f *big.Rat, factor int64) time.Time { + // Extract the numerator and denominator and scale to nanoseconds + num := f.Num() + denom := f.Denom() + num.Mul(num, big.NewInt(factor)) + + // Get the integer (non-fractional part) of the timestamp and convert + // it into time + t := big.Int{} + t.Div(num, denom) + + return time.Unix(0, t.Int64()).UTC() +} + +// sanitizeTimestamp removes thousand separators and uses dot as +// decimal separator. Returns also a boolean indicating success. +func sanitizeTimestamp(timestamp string, decimalSeparator []string) string { + // Remove thousand-separators that are not used for decimal separation + sanitized := timestamp + for _, s := range []string{" ", ",", "."} { + if !choice.Contains(s, decimalSeparator) { + sanitized = strings.ReplaceAll(sanitized, s, "") + } + } + + // Replace decimal separators by dot to have a standard, parsable format + for _, s := range decimalSeparator { + // Make sure we replace only the first occurrence of any separator. + if strings.Contains(sanitized, s) { + return strings.Replace(sanitized, s, ".", 1) + } + } + return sanitized +} + +// parseTime parses a string timestamp according to the format string. +func parseTime(format, timestamp string, location *time.Location) (time.Time, error) { + loc := location + if loc == nil { + loc = time.UTC + } + + switch strings.ToLower(format) { + case "ansic": + format = time.ANSIC + case "unixdate": + format = time.UnixDate + case "rubydate": + format = time.RubyDate + case "rfc822": + format = time.RFC822 + case "rfc822z": + format = time.RFC822Z + case "rfc850": + format = time.RFC850 + case "rfc1123": + format = time.RFC1123 + case "rfc1123z": + format = time.RFC1123Z + case "rfc3339": + format = time.RFC3339 + case "rfc3339nano": + format = time.RFC3339Nano + case "stamp": + format = time.Stamp + case "stampmilli": + format = time.StampMilli + case "stampmicro": + format = time.StampMicro + case "stampnano": + format = time.StampNano + } + + if !strings.Contains(format, "MST") { + return time.ParseInLocation(format, timestamp, loc) + } + + // Golang does not parse times with ambiguous timezone abbreviations, + // but only parses the time-fields and the timezone NAME with a zero + // offset (see https://groups.google.com/g/golang-nuts/c/hDMdnm_jUFQ/m/yeL9IHOsAQAJ). + // To handle those timezones correctly we can use the timezone-name and + // force parsing the time in that timezone. This way we get the correct + // time for the "most probably" of the ambiguous timezone-abbreviations. + ts, err := time.Parse(format, timestamp) + if err != nil { + return time.Time{}, err + } + zone, offset := ts.Zone() + if zone == "UTC" || offset != 0 { + return ts.In(loc), nil + } + once.Do(func() { + const msg = `Your config is using abbreviated timezones and parsing was changed in v1.27.0! + Please see the change log, remove any workarounds in place, and carefully + check your data timestamps! If case you experience any problems, please + file an issue on https://github.com/influxdata/telegraf/issues!` + log.Print("W! " + msg) + }) + + abbrevLoc, err := time.LoadLocation(zone) + if err != nil { + return time.Time{}, fmt.Errorf("cannot resolve timezone abbreviation %q: %w", zone, err) + } + ts, err = time.ParseInLocation(format, timestamp, abbrevLoc) + if err != nil { + return time.Time{}, err + } + return ts.In(loc), nil +} diff --git a/internal/internal_test.go b/internal/internal_test.go new file mode 100644 index 0000000..f0cfdcf --- /dev/null +++ b/internal/internal_test.go @@ -0,0 +1,784 @@ +package internal + +import ( + "bytes" + "compress/gzip" + "crypto/rand" + "io" + "log" + "os/exec" + "regexp" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +type SnakeTest struct { + input string + output string +} + +var tests = []SnakeTest{ + {"a", "a"}, + {"snake", "snake"}, + {"A", "a"}, + {"ID", "id"}, + {"MOTD", "motd"}, + {"Snake", "snake"}, + {"SnakeTest", "snake_test"}, + {"APIResponse", "api_response"}, + {"SnakeID", "snake_id"}, + {"SnakeIDGoogle", "snake_id_google"}, + {"LinuxMOTD", "linux_motd"}, + {"OMGWTFBBQ", "omgwtfbbq"}, + {"omg_wtf_bbq", "omg_wtf_bbq"}, + {"ConsumedLCUs", "consumed_lcus"}, +} + +func TestSnakeCase(t *testing.T) { + for _, test := range tests { + t.Run(test.input, func(t *testing.T) { + require.Equal(t, test.output, SnakeCase(test.input)) + }) + } +} + +func TestRunTimeout(t *testing.T) { + t.Skip("Skipping test due to random failures & a data race when running test-all.") + + sleepbin, err := exec.LookPath("sleep") + if err != nil || sleepbin == "" { + t.Skip("'sleep' binary not available on OS, skipping.") + } + + cmd := exec.Command(sleepbin, "10") + start := time.Now() + err = RunTimeout(cmd, time.Millisecond*20) + elapsed := time.Since(start) + + require.Equal(t, ErrTimeout, err) + // Verify that command gets killed in 20ms, with some breathing room + require.Less(t, elapsed, time.Millisecond*75) +} + +// Verifies behavior of a command that doesn't get killed. +func TestRunTimeoutFastExit(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test due to random failures.") + } + echobin, err := exec.LookPath("echo") + if err != nil || echobin == "" { + t.Skip("'echo' binary not available on OS, skipping.") + } + cmd := exec.Command(echobin) + start := time.Now() + err = RunTimeout(cmd, time.Millisecond*20) + buf := &bytes.Buffer{} + log.SetOutput(buf) + elapsed := time.Since(start) + + require.NoError(t, err) + // Verify that command gets killed in 20ms, with some breathing room + require.Less(t, elapsed, time.Millisecond*75) + + // Verify "process already finished" log doesn't occur. + time.Sleep(time.Millisecond * 75) + require.Empty(t, buf.String()) +} + +func TestCombinedOutputTimeout(t *testing.T) { + // TODO: Fix this test + t.Skip("Test failing too often, skip for now and revisit later.") + sleepbin, err := exec.LookPath("sleep") + if err != nil || sleepbin == "" { + t.Skip("'sleep' binary not available on OS, skipping.") + } + cmd := exec.Command(sleepbin, "10") + start := time.Now() + _, err = CombinedOutputTimeout(cmd, time.Millisecond*20) + elapsed := time.Since(start) + + require.Equal(t, ErrTimeout, err) + // Verify that command gets killed in 20ms, with some breathing room + require.Less(t, elapsed, time.Millisecond*75) +} + +func TestCombinedOutput(t *testing.T) { + echobin, err := exec.LookPath("echo") + if err != nil || echobin == "" { + t.Skip("'echo' binary not available on OS, skipping.") + } + cmd := exec.Command(echobin, "foo") + out, err := CombinedOutputTimeout(cmd, time.Second) + + require.NoError(t, err) + require.Equal(t, "foo\n", string(out)) +} + +// test that CombinedOutputTimeout and exec.Cmd.CombinedOutput return +// the same output from a failed command. +func TestCombinedOutputError(t *testing.T) { + shell, err := exec.LookPath("sh") + if err != nil || shell == "" { + t.Skip("'sh' binary not available on OS, skipping.") + } + cmd := exec.Command(shell, "-c", "false") + expected, err := cmd.CombinedOutput() + require.Error(t, err) + + cmd2 := exec.Command(shell, "-c", "false") + actual, err := CombinedOutputTimeout(cmd2, time.Second) + + require.Error(t, err) + require.Equal(t, expected, actual) +} + +func TestRunError(t *testing.T) { + shell, err := exec.LookPath("sh") + if err != nil || shell == "" { + t.Skip("'sh' binary not available on OS, skipping.") + } + cmd := exec.Command(shell, "-c", "false") + err = RunTimeout(cmd, time.Second) + + require.Error(t, err) +} + +func TestRandomSleep(t *testing.T) { + // TODO: Fix this test + t.Skip("Test failing too often, skip for now and revisit later.") + // test that zero max returns immediately + s := time.Now() + RandomSleep(time.Duration(0), make(chan struct{})) + elapsed := time.Since(s) + require.Less(t, elapsed, time.Millisecond) + + // test that max sleep is respected + s = time.Now() + RandomSleep(time.Millisecond*50, make(chan struct{})) + elapsed = time.Since(s) + require.Less(t, elapsed, time.Millisecond*100) + + // test that shutdown is respected + s = time.Now() + shutdown := make(chan struct{}) + go func() { + time.Sleep(time.Millisecond * 100) + close(shutdown) + }() + RandomSleep(time.Second, shutdown) + elapsed = time.Since(s) + require.Less(t, elapsed, time.Millisecond*150) +} + +func TestCompressWithGzip(t *testing.T) { + testData := "the quick brown fox jumps over the lazy dog" + inputBuffer := bytes.NewBufferString(testData) + + outputBuffer := CompressWithGzip(inputBuffer) + gzipReader, err := gzip.NewReader(outputBuffer) + require.NoError(t, err) + defer gzipReader.Close() + + output, err := io.ReadAll(gzipReader) + require.NoError(t, err) + + require.Equal(t, testData, string(output)) +} + +type mockReader struct { + err error + ncalls uint64 // record the number of calls to Read + msg []byte +} + +func (r *mockReader) Read(p []byte) (n int, err error) { + r.ncalls++ + + if len(r.msg) > 0 { + n, err = copy(p, r.msg), io.EOF + } else { + n, err = rand.Read(p) + } + if r.err == nil { + return n, err + } + return n, r.err +} + +func TestCompressWithGzipEarlyClose(t *testing.T) { + mr := &mockReader{} + + rc := CompressWithGzip(mr) + n, err := io.CopyN(io.Discard, rc, 10000) + require.NoError(t, err) + require.Equal(t, int64(10000), n) + + r1 := mr.ncalls + require.NoError(t, rc.Close()) + + n, err = io.CopyN(io.Discard, rc, 10000) + require.ErrorIs(t, err, io.ErrClosedPipe) + require.Equal(t, int64(0), n) + + r2 := mr.ncalls + // no more read to the source after closing + require.Equal(t, r1, r2) +} + +func TestCompressWithGzipErrorPropagationCopy(t *testing.T) { + errs := []error{io.ErrClosedPipe, io.ErrNoProgress, io.ErrUnexpectedEOF} + for _, expected := range errs { + r := &mockReader{msg: []byte("this is a test"), err: expected} + + rc := CompressWithGzip(r) + n, err := io.Copy(io.Discard, rc) + require.Positive(t, n) + require.ErrorIs(t, err, expected) + require.NoError(t, rc.Close()) + } +} + +func TestCompressWithGzipErrorPropagationReadAll(t *testing.T) { + errs := []error{io.ErrClosedPipe, io.ErrNoProgress, io.ErrUnexpectedEOF} + for _, expected := range errs { + r := &mockReader{msg: []byte("this is a test"), err: expected} + + rc := CompressWithGzip(r) + buf, err := io.ReadAll(rc) + require.NotEmpty(t, buf) + require.ErrorIs(t, err, expected) + require.NoError(t, rc.Close()) + } +} + +func TestAlignDuration(t *testing.T) { + tests := []struct { + name string + now time.Time + interval time.Duration + expected time.Duration + }{ + { + name: "aligned", + now: time.Date(2018, 1, 1, 1, 1, 0, 0, time.UTC), + interval: 10 * time.Second, + expected: 0 * time.Second, + }, + { + name: "standard interval", + now: time.Date(2018, 1, 1, 1, 1, 1, 0, time.UTC), + interval: 10 * time.Second, + expected: 9 * time.Second, + }, + { + name: "odd interval", + now: time.Date(2018, 1, 1, 1, 1, 1, 0, time.UTC), + interval: 3 * time.Second, + expected: 2 * time.Second, + }, + { + name: "sub second interval", + now: time.Date(2018, 1, 1, 1, 1, 0, 5e8, time.UTC), + interval: 1 * time.Second, + expected: 500 * time.Millisecond, + }, + { + name: "non divisible not aligned on minutes", + now: time.Date(2018, 1, 1, 1, 0, 0, 0, time.UTC), + interval: 1*time.Second + 100*time.Millisecond, + expected: 400 * time.Millisecond, + }, + { + name: "long interval", + now: time.Date(2018, 1, 1, 1, 1, 0, 0, time.UTC), + interval: 1 * time.Hour, + expected: 59 * time.Minute, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := AlignDuration(tt.now, tt.interval) + require.Equal(t, tt.expected, actual) + }) + } +} + +func TestAlignTime(t *testing.T) { + rfc3339 := func(value string) time.Time { + tt, err := time.Parse(time.RFC3339, value) + require.NoError(t, err) + return tt + } + + tests := []struct { + name string + now time.Time + interval time.Duration + expected time.Time + }{ + { + name: "aligned", + now: rfc3339("2018-01-01T01:01:00Z"), + interval: 10 * time.Second, + expected: rfc3339("2018-01-01T01:01:00Z"), + }, + { + name: "aligned", + now: rfc3339("2018-01-01T01:01:01Z"), + interval: 10 * time.Second, + expected: rfc3339("2018-01-01T01:01:10Z"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := AlignTime(tt.now, tt.interval) + require.Equal(t, tt.expected, actual) + }) + } +} + +func TestParseTimestamp(t *testing.T) { + rfc3339 := func(value string) time.Time { + tm, err := time.Parse(time.RFC3339Nano, value) + require.NoError(t, err) + return tm + } + ansic := func(value string) time.Time { + tm, err := time.Parse(time.ANSIC, value) + require.NoError(t, err) + return tm + } + + rubydate := func(value string) time.Time { + tm, err := time.Parse(time.RubyDate, value) + require.NoError(t, err) + return tm + } + + rfc822z := func(value string) time.Time { + tm, err := time.Parse(time.RFC822Z, value) + require.NoError(t, err) + return tm + } + + rfc1123z := func(value string) time.Time { + tm, err := time.Parse(time.RFC1123Z, value) + require.NoError(t, err) + return tm + } + + rfc3339nano := func(value string) time.Time { + tm, err := time.Parse(time.RFC3339Nano, value) + require.NoError(t, err) + return tm + } + + stamp := func(value string) time.Time { + tm, err := time.Parse(time.Stamp, value) + require.NoError(t, err) + return tm + } + + stampmilli := func(value string) time.Time { + tm, err := time.Parse(time.StampMilli, value) + require.NoError(t, err) + return tm + } + + stampmicro := func(value string) time.Time { + tm, err := time.Parse(time.StampMicro, value) + require.NoError(t, err) + return tm + } + + stampnano := func(value string) time.Time { + tm, err := time.Parse(time.StampNano, value) + require.NoError(t, err) + return tm + } + + tests := []struct { + name string + format string + timestamp interface{} + location string + separator []string + expected time.Time + }{ + { + name: "parse layout string in utc", + format: "2006-01-02 15:04:05", + timestamp: "2019-02-20 21:50:34", + location: "UTC", + expected: rfc3339("2019-02-20T21:50:34Z"), + }, + { + name: "layout regression 6386", + format: "02.01.2006 15:04:05", + timestamp: "09.07.2019 00:11:00", + expected: rfc3339("2019-07-09T00:11:00Z"), + }, + { + name: "default location is utc", + format: "2006-01-02 15:04:05", + timestamp: "2019-02-20 21:50:34", + expected: rfc3339("2019-02-20T21:50:34Z"), + }, + { + name: "unix seconds without fractional", + format: "unix", + timestamp: "1568338208", + expected: rfc3339("2019-09-13T01:30:08Z"), + }, + { + name: "unix seconds with fractional", + format: "unix", + timestamp: "1568338208.500", + expected: rfc3339("2019-09-13T01:30:08.500Z"), + }, + { + name: "unix seconds with fractional and comma decimal point", + format: "unix", + timestamp: "1568338208,500", + expected: rfc3339("2019-09-13T01:30:08.500Z"), + }, + { + name: "unix seconds extra precision", + format: "unix", + timestamp: "1568338208.00000050042", + expected: rfc3339("2019-09-13T01:30:08.000000500Z"), + }, + { + name: "unix seconds with thousand separator only (dot)", + format: "unix", + timestamp: "1.568.338.208", + separator: []string{","}, + expected: rfc3339("2019-09-13T01:30:08Z"), + }, + { + name: "unix seconds with thousand separator only (comma)", + format: "unix", + timestamp: "1,568,338,208", + separator: []string{"."}, + expected: rfc3339("2019-09-13T01:30:08Z"), + }, + { + name: "unix seconds with thousand separator only (space)", + format: "unix", + timestamp: "1 568 338 208", + separator: []string{"."}, + expected: rfc3339("2019-09-13T01:30:08Z"), + }, + { + name: "unix seconds with thousand separator only (underscore)", + format: "unix", + timestamp: "1_568_338_208", + separator: []string{"."}, + expected: rfc3339("2019-09-13T01:30:08Z"), + }, + { + name: "unix seconds with thousand and decimal separator (US)", + format: "unix", + timestamp: "1,568,338,208.500", + separator: []string{"."}, + expected: rfc3339("2019-09-13T01:30:08.500Z"), + }, + { + name: "unix seconds with thousand and decimal separator (EU)", + format: "unix", + timestamp: "1.568.338.208,500", + separator: []string{","}, + expected: rfc3339("2019-09-13T01:30:08.500Z"), + }, + { + name: "unix seconds integer", + format: "unix", + timestamp: int64(1568338208), + expected: rfc3339("2019-09-13T01:30:08Z"), + }, + { + name: "unix seconds float", + format: "unix", + timestamp: float64(1568338208.500), + expected: rfc3339("2019-09-13T01:30:08.500Z"), + }, + { + name: "unix seconds float exponential", + format: "unix", + timestamp: float64(1.5683382085e+9), + expected: rfc3339("2019-09-13T01:30:08.500Z"), + }, + { + name: "unix milliseconds", + format: "unix_ms", + timestamp: "1568338208500", + expected: rfc3339("2019-09-13T01:30:08.500Z"), + }, + { + name: "unix milliseconds with fractional", + format: "unix_ms", + timestamp: "1568338208500.42", + expected: rfc3339("2019-09-13T01:30:08.50042Z"), + }, + { + name: "unix microseconds", + format: "unix_us", + timestamp: "1568338208000500", + expected: rfc3339("2019-09-13T01:30:08.000500Z"), + }, + { + name: "unix nanoseconds", + format: "unix_ns", + timestamp: "1568338208000000500", + expected: rfc3339("2019-09-13T01:30:08.000000500Z"), + }, + { + name: "unix nanoseconds exponential", + format: "unix_ns", + timestamp: "1.5683382080000005e+18", + expected: rfc3339("2019-09-13T01:30:08.000000500Z"), + }, + { + name: "rfc339 test", + format: "RFC3339", + timestamp: "2018-10-26T13:30:33Z", + expected: rfc3339("2018-10-26T13:30:33Z"), + }, + + { + name: "ANSIC", + format: "ANSIC", + timestamp: "Mon Jan 2 15:04:05 2006", + expected: ansic("Mon Jan 2 15:04:05 2006"), + }, + + { + name: "UnixDate", + format: "UnixDate", + timestamp: "Mon Jan 2 15:04:05 MST 2006", + expected: time.Unix(1136239445, 0), + location: "Local", + }, + + { + name: "RubyDate", + format: "RubyDate", + timestamp: "Mon Jan 02 15:04:05 -0700 2006", + expected: rubydate("Mon Jan 02 15:04:05 -0700 2006"), + location: "Local", + }, + + { + name: "RFC822", + format: "RFC822", + timestamp: "02 Jan 06 15:04 MST", + expected: time.Unix(1136239440, 0), + location: "Local", + }, + + { + name: "RFC822Z", + format: "RFC822Z", + timestamp: "02 Jan 06 15:04 -0700", + expected: rfc822z("02 Jan 06 15:04 -0700"), + location: "Local", + }, + + { + name: "RFC850", + format: "RFC850", + timestamp: "Monday, 02-Jan-06 15:04:05 MST", + expected: time.Unix(1136239445, 0), + location: "Local", + }, + + { + name: "RFC1123", + format: "RFC1123", + timestamp: "Mon, 02 Jan 2006 15:04:05 MST", + expected: time.Unix(1136239445, 0), + location: "Local", + }, + + { + name: "RFC1123Z", + format: "RFC1123Z", + timestamp: "Mon, 02 Jan 2006 15:04:05 -0700", + expected: rfc1123z("Mon, 02 Jan 2006 15:04:05 -0700"), + location: "Local", + }, + + { + name: "RFC3339Nano", + format: "RFC3339Nano", + timestamp: "2006-01-02T15:04:05.999999999-07:00", + expected: rfc3339nano("2006-01-02T15:04:05.999999999-07:00"), + location: "Local", + }, + + { + name: "Stamp", + format: "Stamp", + timestamp: "Jan 2 15:04:05", + expected: stamp("Jan 2 15:04:05"), + }, + + { + name: "StampMilli", + format: "StampMilli", + timestamp: "Jan 2 15:04:05.000", + expected: stampmilli("Jan 2 15:04:05.000"), + }, + + { + name: "StampMicro", + format: "StampMicro", + timestamp: "Jan 2 15:04:05.000000", + expected: stampmicro("Jan 2 15:04:05.000000"), + }, + + { + name: "StampNano", + format: "StampNano", + timestamp: "Jan 2 15:04:05.000000000", + expected: stampnano("Jan 2 15:04:05.000000000"), + }, + + { + name: "RFC850", + format: "RFC850", + timestamp: "Monday, 02-Jan-06 15:04:05 MST", + expected: time.Unix(1136239445, 0), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Ensure any one-time warnings are printed for each test + once = sync.Once{} + + // Ensure the warnings are captured and not to stdout + var buf bytes.Buffer + backup := log.Writer() + log.SetOutput(&buf) + defer log.SetOutput(backup) + + var loc *time.Location + if tt.location != "" { + var err error + loc, err = time.LoadLocation(tt.location) + require.NoError(t, err) + } + tm, err := ParseTimestamp(tt.format, tt.timestamp, loc, tt.separator...) + require.NoError(t, err) + require.Equal(t, tt.expected.Unix(), tm.Unix()) + }) + } +} + +func TestParseTimestampInvalid(t *testing.T) { + tests := []struct { + name string + format string + timestamp interface{} + expected string + }{ + { + name: "too few digits", + format: "2006-01-02 15:04:05", + timestamp: "2019-02-20 21:50", + expected: "cannot parse \"\" as \":\"", + }, + { + name: "invalid layout", + format: "rfc3399", + timestamp: "09.07.2019 00:11:00", + expected: "cannot parse \"09.07.2019 00:11:00\" as \"rfc\"", + }, + { + name: "layout not matching time", + format: "rfc3339", + timestamp: "09.07.2019 00:11:00", + expected: "parsing time \"09.07.2019 00:11:00\" as \"2006-01-02T15:04:05Z07:00\": cannot parse", + }, + { + name: "unix wrong type", + format: "unix", + timestamp: true, + expected: "unsupported type", + }, + { + name: "unix multiple separators (dot)", + format: "unix", + timestamp: "1568338.208.500", + expected: "invalid number", + }, + { + name: "unix multiple separators (comma)", + format: "unix", + timestamp: "1568338,208,500", + expected: "invalid number", + }, + { + name: "unix multiple separators (mixed)", + format: "unix", + timestamp: "1,568,338,208.500", + expected: "invalid number", + }, + { + name: "invalid timezone abbreviation", + format: "RFC850", + timestamp: "Monday, 02-Jan-06 15:04:05 CDT", + expected: "cannot resolve timezone abbreviation", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Ensure any one-time warnings are printed for each test + once = sync.Once{} + + // Ensure the warnings are captured and not to stdout + var buf bytes.Buffer + backup := log.Writer() + log.SetOutput(&buf) + defer log.SetOutput(backup) + + _, err := ParseTimestamp(tt.format, tt.timestamp, nil) + require.ErrorContains(t, err, tt.expected) + }) + } +} + +func TestTimestampAbbrevWarning(t *testing.T) { + // Ensure any one-time warnings are printed for each test + once = sync.Once{} + + // Ensure the warnings are captured and not to stdout + var buf bytes.Buffer + backup := log.Writer() + log.SetOutput(&buf) + defer log.SetOutput(backup) + + // Try multiple timestamps with abbreviated timezones in case a user + // is actually in one of the timezones. + ts, err := ParseTimestamp("RFC1123", "Mon, 02 Jan 2006 15:04:05 MST", nil) + require.NoError(t, err) + require.EqualValues(t, 1136239445, ts.Unix()) + + ts2, err := ParseTimestamp("RFC1123", "Mon, 02 Jan 2006 15:04:05 EST", nil) + require.NoError(t, err) + require.EqualValues(t, 1136232245, ts2.Unix()) + + require.Contains(t, buf.String(), "Your config is using abbreviated timezones and parsing was changed in v1.27.0") +} + +func TestProductToken(t *testing.T) { + token := ProductToken() + // Telegraf version depends on the call to SetVersion, it cannot be set + // multiple times and is not thread-safe. + re := regexp.MustCompile(`^Telegraf/[^\s]+ Go/\d+.\d+(.\d+)?$`) + require.True(t, re.MatchString(token), token) +} diff --git a/internal/limiter/limiter.go b/internal/limiter/limiter.go new file mode 100644 index 0000000..98fcd92 --- /dev/null +++ b/internal/limiter/limiter.go @@ -0,0 +1,59 @@ +package limiter + +import ( + "sync" + "time" +) + +// NewRateLimiter returns a rate limiter that will emit from the C +// channel only 'n' times every 'rate' seconds. +func NewRateLimiter(n int, rate time.Duration) *rateLimiter { + r := &rateLimiter{ + C: make(chan bool), + rate: rate, + n: n, + shutdown: make(chan bool), + } + r.wg.Add(1) + go r.limiter() + return r +} + +type rateLimiter struct { + C chan bool + rate time.Duration + n int + + shutdown chan bool + wg sync.WaitGroup +} + +func (r *rateLimiter) Stop() { + close(r.shutdown) + r.wg.Wait() + close(r.C) +} + +func (r *rateLimiter) limiter() { + defer r.wg.Done() + ticker := time.NewTicker(r.rate) + defer ticker.Stop() + counter := 0 + for { + select { + case <-r.shutdown: + return + case <-ticker.C: + counter = 0 + default: + if counter < r.n { + select { + case r.C <- true: + counter++ + case <-r.shutdown: + return + } + } + } + } +} diff --git a/internal/process/process.go b/internal/process/process.go new file mode 100644 index 0000000..c471060 --- /dev/null +++ b/internal/process/process.go @@ -0,0 +1,215 @@ +package process + +import ( + "context" + "errors" + "fmt" + "io" + "os" + "os/exec" + "sync" + "sync/atomic" + "time" + + "github.com/influxdata/telegraf" +) + +// Process is a long-running process manager that will restart processes if they stop. +type Process struct { + Cmd *exec.Cmd + Stdin io.WriteCloser + Stdout io.ReadCloser + Stderr io.ReadCloser + ReadStdoutFn func(io.Reader) + ReadStderrFn func(io.Reader) + RestartDelay time.Duration + StopOnError bool + Log telegraf.Logger + + name string + args []string + envs []string + pid int32 + cancel context.CancelFunc + mainLoopWg sync.WaitGroup + + sync.Mutex +} + +// New creates a new process wrapper +func New(command, envs []string) (*Process, error) { + if len(command) == 0 { + return nil, errors.New("no command") + } + + p := &Process{ + RestartDelay: 5 * time.Second, + name: command[0], + args: make([]string, 0), + envs: envs, + } + + if len(command) > 1 { + p.args = command[1:] + } + + return p, nil +} + +// Start the process. A &Process can only be started once. It will restart itself +// as necessary. +func (p *Process) Start() error { + ctx, cancel := context.WithCancel(context.Background()) + p.cancel = cancel + + if err := p.cmdStart(); err != nil { + return err + } + + p.mainLoopWg.Add(1) + go func() { + defer p.mainLoopWg.Done() + if err := p.cmdLoop(ctx); err != nil { + p.Log.Errorf("Process quit with message: %v", err) + } + }() + + return nil +} + +// Stop is called when the process isn't needed anymore +func (p *Process) Stop() { + if p.cancel != nil { + // signal our intent to shut down and not restart the process + p.cancel() + } + // close stdin so the app can shut down gracefully. + if err := p.Stdin.Close(); err != nil && !errors.Is(err, os.ErrClosed) { + p.Log.Errorf("Stdin closed with message: %v", err) + } + p.mainLoopWg.Wait() +} + +func (p *Process) Pid() int { + pid := atomic.LoadInt32(&p.pid) + return int(pid) +} + +func (p *Process) State() (state *os.ProcessState, running bool) { + p.Lock() + defer p.Unlock() + + return p.Cmd.ProcessState, p.Cmd.ProcessState.ExitCode() == -1 +} + +func (p *Process) cmdStart() error { + p.Cmd = exec.Command(p.name, p.args...) + + if len(p.envs) > 0 { + p.Cmd.Env = append(os.Environ(), p.envs...) + } + + var err error + p.Stdin, err = p.Cmd.StdinPipe() + if err != nil { + return fmt.Errorf("error opening stdin pipe: %w", err) + } + + p.Stdout, err = p.Cmd.StdoutPipe() + if err != nil { + return fmt.Errorf("error opening stdout pipe: %w", err) + } + + p.Stderr, err = p.Cmd.StderrPipe() + if err != nil { + return fmt.Errorf("error opening stderr pipe: %w", err) + } + + p.Log.Infof("Starting process: %s %s", p.name, p.args) + + if err := p.Cmd.Start(); err != nil { + return fmt.Errorf("error starting process: %w", err) + } + atomic.StoreInt32(&p.pid, int32(p.Cmd.Process.Pid)) + return nil +} + +// cmdLoop watches an already running process, restarting it when appropriate. +func (p *Process) cmdLoop(ctx context.Context) error { + for { + err := p.cmdWait(ctx) + if err != nil && p.StopOnError { + return err + } + if isQuitting(ctx) { + p.Log.Infof("Process %s shut down", p.Cmd.Path) + return nil + } + + p.Log.Errorf("Process %s exited: %v", p.Cmd.Path, err) + p.Log.Infof("Restarting in %s...", p.RestartDelay) + + select { + case <-ctx.Done(): + return nil + case <-time.After(p.RestartDelay): + // Continue the loop and restart the process + if err := p.cmdStart(); err != nil { + return err + } + } + } +} + +// cmdWait waits for the process to finish. +func (p *Process) cmdWait(ctx context.Context) error { + var wg sync.WaitGroup + + if p.ReadStdoutFn == nil { + p.ReadStdoutFn = defaultReadPipe + } + if p.ReadStderrFn == nil { + p.ReadStderrFn = defaultReadPipe + } + + processCtx, processCancel := context.WithCancel(context.Background()) + defer processCancel() + + wg.Add(1) + go func() { + p.ReadStdoutFn(p.Stdout) + wg.Done() + }() + + wg.Add(1) + go func() { + p.ReadStderrFn(p.Stderr) + wg.Done() + }() + + wg.Add(1) + go func() { + select { + case <-ctx.Done(): + p.gracefulStop(processCtx, p.Cmd, 5*time.Second) + case <-processCtx.Done(): + } + wg.Done() + }() + + p.Lock() + err := p.Cmd.Wait() + p.Unlock() + processCancel() + wg.Wait() + return err +} + +func isQuitting(ctx context.Context) bool { + return ctx.Err() != nil +} + +func defaultReadPipe(r io.Reader) { + //nolint:errcheck // Discarding the data, no need to handle an error + io.Copy(io.Discard, r) +} diff --git a/internal/process/process_posix.go b/internal/process/process_posix.go new file mode 100644 index 0000000..a059e78 --- /dev/null +++ b/internal/process/process_posix.go @@ -0,0 +1,27 @@ +//go:build !windows + +package process + +import ( + "context" + "os/exec" + "syscall" + "time" +) + +func (p *Process) gracefulStop(ctx context.Context, cmd *exec.Cmd, timeout time.Duration) { + select { + case <-time.After(timeout): + if err := cmd.Process.Signal(syscall.SIGTERM); err != nil { + p.Log.Errorf("Error after sending SIGTERM signal to process: %v", err) + } + case <-ctx.Done(): + } + select { + case <-time.After(timeout): + if err := cmd.Process.Kill(); err != nil { + p.Log.Errorf("Error after killing process: %v", err) + } + case <-ctx.Done(): + } +} diff --git a/internal/process/process_test.go b/internal/process/process_test.go new file mode 100644 index 0000000..7ab275c --- /dev/null +++ b/internal/process/process_test.go @@ -0,0 +1,81 @@ +//go:build !windows + +package process + +import ( + "bufio" + "flag" + "fmt" + "io" + "os" + "sync/atomic" + "syscall" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/influxdata/telegraf/testutil" +) + +// test that a restarting process resets pipes properly +func TestRestartingRebindsPipes(t *testing.T) { + if testing.Short() { + t.Skip("Skipping long running test in short mode") + } + + exe, err := os.Executable() + require.NoError(t, err) + + p, err := New([]string{exe, "-external"}, []string{"INTERNAL_PROCESS_MODE=application"}) + p.RestartDelay = 100 * time.Nanosecond + p.Log = testutil.Logger{} + require.NoError(t, err) + + linesRead := int64(0) + p.ReadStdoutFn = func(r io.Reader) { + scanner := bufio.NewScanner(r) + + for scanner.Scan() { + atomic.AddInt64(&linesRead, 1) + } + } + + require.NoError(t, p.Start()) + + for atomic.LoadInt64(&linesRead) < 1 { + time.Sleep(1 * time.Millisecond) + } + + require.NoError(t, syscall.Kill(p.Pid(), syscall.SIGKILL)) + + for atomic.LoadInt64(&linesRead) < 2 { + time.Sleep(1 * time.Millisecond) + } + + // the mainLoopWg.Wait() call p.Stop() makes takes multiple seconds to complete + p.Stop() +} + +var external = flag.Bool("external", false, + "if true, run externalProcess instead of tests") + +func TestMain(m *testing.M) { + flag.Parse() + runMode := os.Getenv("INTERNAL_PROCESS_MODE") + if *external && runMode == "application" { + externalProcess() + os.Exit(0) + } + code := m.Run() + os.Exit(code) +} + +// externalProcess is an external "misbehaving" process that won't exit +// cleanly. +func externalProcess() { + wait := make(chan int) + fmt.Fprintln(os.Stdout, "started") + <-wait + os.Exit(2) //nolint:revive // os.Exit called intentionally +} diff --git a/internal/process/process_windows.go b/internal/process/process_windows.go new file mode 100644 index 0000000..c465249 --- /dev/null +++ b/internal/process/process_windows.go @@ -0,0 +1,19 @@ +//go:build windows + +package process + +import ( + "context" + "os/exec" + "time" +) + +func (p *Process) gracefulStop(ctx context.Context, cmd *exec.Cmd, timeout time.Duration) { + select { + case <-time.After(timeout): + if err := cmd.Process.Kill(); err != nil { + p.Log.Errorf("Error after killing process: %v", err) + } + case <-ctx.Done(): + } +} diff --git a/internal/rotate/file_writer.go b/internal/rotate/file_writer.go new file mode 100644 index 0000000..e4581d6 --- /dev/null +++ b/internal/rotate/file_writer.go @@ -0,0 +1,183 @@ +package rotate + +// Rotating things +import ( + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "sync" + "time" +) + +// FilePerm defines the permissions that Writer will use for all +// the files it creates. +const ( + FilePerm = os.FileMode(0644) + DateFormat = "2006-01-02" +) + +// FileWriter implements the io.Writer interface and writes to the +// filename specified. +// Will rotate at the specified interval and/or when the current file size exceeds maxSizeInBytes +// At rotation time, current file is renamed and a new file is created. +// If the number of archives exceeds maxArchives, older files are deleted. +type FileWriter struct { + filename string + filenameRotationTemplate string + current *os.File + interval time.Duration + maxSizeInBytes int64 + maxArchives int + expireTime time.Time + bytesWritten int64 + sync.Mutex +} + +// NewFileWriter creates a new file writer. +func NewFileWriter(filename string, interval time.Duration, maxSizeInBytes int64, maxArchives int) (io.WriteCloser, error) { + if interval == 0 && maxSizeInBytes <= 0 { + // No rotation needed so a basic io.Writer will do the trick + return openFile(filename) + } + + w := &FileWriter{ + filename: filename, + interval: interval, + maxSizeInBytes: maxSizeInBytes, + maxArchives: maxArchives, + filenameRotationTemplate: getFilenameRotationTemplate(filename), + } + + if err := w.openCurrent(); err != nil { + return nil, err + } + + return w, nil +} + +func openFile(filename string) (*os.File, error) { + return os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, FilePerm) +} + +func getFilenameRotationTemplate(filename string) string { + // Extract the file extension + fileExt := filepath.Ext(filename) + // Remove the file extension from the filename (if any) + stem := strings.TrimSuffix(filename, fileExt) + return stem + ".%s-%s" + fileExt +} + +// Write writes p to the current file, then checks to see if +// rotation is necessary. +func (w *FileWriter) Write(p []byte) (n int, err error) { + w.Lock() + defer w.Unlock() + if n, err = w.current.Write(p); err != nil { + return 0, err + } + w.bytesWritten += int64(n) + + if err := w.rotateIfNeeded(); err != nil { + return 0, err + } + + return n, nil +} + +// Close closes the current file. Writer is unusable after this +// is called. +func (w *FileWriter) Close() (err error) { + w.Lock() + defer w.Unlock() + + // Rotate before closing + if err := w.rotateIfNeeded(); err != nil { + return err + } + + // Close the file if we did not rotate + if err := w.current.Close(); err != nil { + return err + } + + w.current = nil + return nil +} + +func (w *FileWriter) openCurrent() (err error) { + // In case ModTime() fails, we use time.Now() + w.expireTime = time.Now().Add(w.interval) + w.bytesWritten = 0 + w.current, err = openFile(w.filename) + + if err != nil { + return err + } + + // Goal here is to rotate old pre-existing files. + // For that we use fileInfo.ModTime, instead of time.Now(). + // Example: telegraf is restarted every 23 hours and + // the rotation interval is set to 24 hours. + // With time.now() as a reference we'd never rotate the file. + if fileInfo, err := w.current.Stat(); err == nil { + w.expireTime = fileInfo.ModTime().Add(w.interval) + w.bytesWritten = fileInfo.Size() + } + + return w.rotateIfNeeded() +} + +func (w *FileWriter) rotateIfNeeded() error { + if (w.interval > 0 && time.Now().After(w.expireTime)) || + (w.maxSizeInBytes > 0 && w.bytesWritten >= w.maxSizeInBytes) { + if err := w.rotate(); err != nil { + // Ignore rotation errors and keep the log open + fmt.Printf("unable to rotate the file %q, %s", w.filename, err.Error()) + } + return w.openCurrent() + } + return nil +} + +func (w *FileWriter) rotate() (err error) { + if err := w.current.Close(); err != nil { + return err + } + + // Use year-month-date for readability, unix time to make the file name unique with second precision + now := time.Now() + rotatedFilename := fmt.Sprintf(w.filenameRotationTemplate, now.Format(DateFormat), strconv.FormatInt(now.Unix(), 10)) + if err := os.Rename(w.filename, rotatedFilename); err != nil { + return err + } + + return w.purgeArchivesIfNeeded() +} + +func (w *FileWriter) purgeArchivesIfNeeded() (err error) { + if w.maxArchives == -1 { + // Skip archiving + return nil + } + + var matches []string + if matches, err = filepath.Glob(fmt.Sprintf(w.filenameRotationTemplate, "*", "*")); err != nil { + return err + } + + // if there are more archives than the configured maximum, then purge older files + if len(matches) > w.maxArchives { + // sort files alphanumerically to delete older files first + sort.Strings(matches) + for _, filename := range matches[:len(matches)-w.maxArchives] { + if err := os.Remove(filename); err != nil { + return err + } + } + } + return nil +} diff --git a/internal/rotate/file_writer_test.go b/internal/rotate/file_writer_test.go new file mode 100644 index 0000000..4ebc74c --- /dev/null +++ b/internal/rotate/file_writer_test.go @@ -0,0 +1,150 @@ +package rotate + +import ( + "os" + "path/filepath" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestFileWriter_NoRotation(t *testing.T) { + tempDir := t.TempDir() + writer, err := NewFileWriter(filepath.Join(tempDir, "test"), 0, 0, 0) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, writer.Close()) }) + + _, err = writer.Write([]byte("Hello World")) + require.NoError(t, err) + _, err = writer.Write([]byte("Hello World 2")) + require.NoError(t, err) + files, err := os.ReadDir(tempDir) + require.NoError(t, err) + require.Len(t, files, 1) +} + +func TestFileWriter_TimeRotation(t *testing.T) { + tempDir := t.TempDir() + interval, err := time.ParseDuration("10ms") + require.NoError(t, err) + writer, err := NewFileWriter(filepath.Join(tempDir, "test"), interval, 0, -1) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, writer.Close()) }) + + _, err = writer.Write([]byte("Hello World")) + require.NoError(t, err) + time.Sleep(interval) + _, err = writer.Write([]byte("Hello World 2")) + require.NoError(t, err) + files, err := os.ReadDir(tempDir) + require.NoError(t, err) + require.Len(t, files, 2) +} + +func TestFileWriter_ReopenTimeRotation(t *testing.T) { + tempDir := t.TempDir() + interval, err := time.ParseDuration("10ms") + require.NoError(t, err) + filePath := filepath.Join(tempDir, "test.log") + err = os.WriteFile(filePath, []byte("Hello World"), 0640) + time.Sleep(interval) + require.NoError(t, err) + writer, err := NewFileWriter(filepath.Join(tempDir, "test.log"), interval, 0, -1) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, writer.Close()) }) + + files, err := os.ReadDir(tempDir) + require.NoError(t, err) + require.Len(t, files, 2) +} + +func TestFileWriter_SizeRotation(t *testing.T) { + tempDir := t.TempDir() + maxSize := int64(9) + writer, err := NewFileWriter(filepath.Join(tempDir, "test.log"), 0, maxSize, -1) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, writer.Close()) }) + + _, err = writer.Write([]byte("Hello World")) + require.NoError(t, err) + _, err = writer.Write([]byte("World 2")) + require.NoError(t, err) + files, err := os.ReadDir(tempDir) + require.NoError(t, err) + require.Len(t, files, 2) +} + +func TestFileWriter_ReopenSizeRotation(t *testing.T) { + tempDir := t.TempDir() + maxSize := int64(12) + filePath := filepath.Join(tempDir, "test.log") + err := os.WriteFile(filePath, []byte("Hello World"), 0640) + require.NoError(t, err) + writer, err := NewFileWriter(filepath.Join(tempDir, "test.log"), 0, maxSize, -1) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, writer.Close()) }) + + _, err = writer.Write([]byte("Hello World Again")) + require.NoError(t, err) + files, err := os.ReadDir(tempDir) + require.NoError(t, err) + require.Len(t, files, 2) +} + +func TestFileWriter_DeleteArchives(t *testing.T) { + if testing.Short() { + t.Skip("Skipping long test in short mode") + } + + tempDir := t.TempDir() + maxSize := int64(5) + writer, err := NewFileWriter(filepath.Join(tempDir, "test.log"), 0, maxSize, 2) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, writer.Close()) }) + + _, err = writer.Write([]byte("First file")) + require.NoError(t, err) + // File names include the date with second precision + // So, to force rotation with different file names + // we need to wait + time.Sleep(1 * time.Second) + _, err = writer.Write([]byte("Second file")) + require.NoError(t, err) + time.Sleep(1 * time.Second) + _, err = writer.Write([]byte("Third file")) + require.NoError(t, err) + + files, err := os.ReadDir(tempDir) + require.NoError(t, err) + require.Len(t, files, 3) + + for _, tempFile := range files { + var bytes []byte + var err error + path := filepath.Join(tempDir, tempFile.Name()) + if bytes, err = os.ReadFile(path); err != nil { + t.Error(err.Error()) + return + } + contents := string(bytes) + + if contents != "" && contents != "Second file" && contents != "Third file" { + t.Error("Should have deleted the eldest log file") + return + } + } +} + +func TestFileWriter_CloseDoesNotRotate(t *testing.T) { + tempDir := t.TempDir() + maxSize := int64(9) + writer, err := NewFileWriter(filepath.Join(tempDir, "test.log"), 0, maxSize, -1) + require.NoError(t, err) + require.NoError(t, writer.Close()) + + files, err := os.ReadDir(tempDir) + require.NoError(t, err) + require.Len(t, files, 1) + require.Regexp(t, "^test.log$", files[0].Name()) +} diff --git a/internal/snmp/config.go b/internal/snmp/config.go new file mode 100644 index 0000000..20cc20a --- /dev/null +++ b/internal/snmp/config.go @@ -0,0 +1,53 @@ +package snmp + +import ( + "time" + + "github.com/influxdata/telegraf/config" +) + +type ClientConfig struct { + // Timeout to wait for a response. + Timeout config.Duration `toml:"timeout"` + Retries int `toml:"retries"` + Version uint8 `toml:"version"` + UnconnectedUDPSocket bool `toml:"unconnected_udp_socket"` + + // Parameters for Version 1 & 2 + Community string `toml:"community"` + + // Parameters for Version 2 & 3 + MaxRepetitions uint32 `toml:"max_repetitions"` + + // Parameters for Version 3 + ContextName string `toml:"context_name"` + SecLevel string `toml:"sec_level"` + SecName string `toml:"sec_name"` + AuthProtocol string `toml:"auth_protocol"` + AuthPassword config.Secret `toml:"auth_password"` + PrivProtocol string `toml:"priv_protocol"` + PrivPassword config.Secret `toml:"priv_password"` + EngineID string `toml:"-"` + EngineBoots uint32 `toml:"-"` + EngineTime uint32 `toml:"-"` + + // Path to mib files + Path []string `toml:"path"` + Translator string `toml:"-"` +} + +func DefaultClientConfig() *ClientConfig { + return &ClientConfig{ + Timeout: config.Duration(5 * time.Second), + Retries: 3, + Version: 2, + Path: []string{"/usr/share/snmp/mibs"}, + Translator: "gosmi", + Community: "public", + MaxRepetitions: 10, + SecLevel: "authNoPriv", + SecName: "myuser", + AuthProtocol: "MD5", + AuthPassword: config.NewSecret([]byte("pass")), + } +} diff --git a/internal/snmp/field.go b/internal/snmp/field.go new file mode 100644 index 0000000..e41c3c1 --- /dev/null +++ b/internal/snmp/field.go @@ -0,0 +1,327 @@ +package snmp + +import ( + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "math" + "net" + "strconv" + "strings" + "unicode/utf8" + + "github.com/gosnmp/gosnmp" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/config" +) + +// Field holds the configuration for a Field to look up. +type Field struct { + // Name will be the name of the field. + Name string + // OID is prefix for this field. The plugin will perform a walk through all + // OIDs with this as their parent. For each value found, the plugin will strip + // off the OID prefix, and use the remainder as the index. For multiple fields + // to show up in the same row, they must share the same index. + Oid string + // OidIndexSuffix is the trailing sub-identifier on a table record OID that will be stripped off to get the record's index. + OidIndexSuffix string + // OidIndexLength specifies the length of the index in OID path segments. It can be used to remove sub-identifiers that vary in content or length. + OidIndexLength int + // IsTag controls whether this OID is output as a tag or a value. + IsTag bool + // Conversion controls any type conversion that is done on the value. + // "float"/"float(0)" will convert the value into a float. + // "float(X)" will convert the value into a float, and then move the decimal before Xth right-most digit. + // "int" will convert the value into an integer. + // "hwaddr" will convert a 6-byte string to a MAC address. + // "ipaddr" will convert the value to an IPv4 or IPv6 address. + // "enum"/"enum(1)" will convert the value according to its syntax. (Only supported with gosmi translator) + // "displayhint" will format the value according to the textual convention. (Only supported with gosmi translator) + Conversion string + // Translate tells if the value of the field should be snmptranslated + Translate bool + // Secondary index table allows to merge data from two tables with different index + // that this filed will be used to join them. There can be only one secondary index table. + SecondaryIndexTable bool + // This field is using secondary index, and will be later merged with primary index + // using SecondaryIndexTable. SecondaryIndexTable and SecondaryIndexUse are exclusive. + SecondaryIndexUse bool + // Controls if entries from secondary table should be added or not if joining + // index is present or not. I set to true, means that join is outer, and + // index is prepended with "Secondary." for missing values to avoid overlapping + // indexes from both tables. + // Can be set per field or globally with SecondaryIndexTable, global true overrides + // per field false. + SecondaryOuterJoin bool + + initialized bool + translator Translator +} + +// init() converts OID names to numbers, and sets the .Name attribute if unset. +func (f *Field) Init(tr Translator) error { + if f.initialized { + return nil + } + + f.translator = tr + + // check if oid needs translation or name is not set + if strings.ContainsAny(f.Oid, ":abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") || f.Name == "" { + _, oidNum, oidText, conversion, err := f.translator.SnmpTranslate(f.Oid) + if err != nil { + return fmt.Errorf("translating: %w", err) + } + f.Oid = oidNum + if f.Name == "" { + f.Name = oidText + } + if f.Conversion == "" { + f.Conversion = conversion + } + } + + if f.SecondaryIndexTable && f.SecondaryIndexUse { + return errors.New("fields SecondaryIndexTable and UseSecondaryIndex are exclusive") + } + + if !f.SecondaryIndexTable && !f.SecondaryIndexUse && f.SecondaryOuterJoin { + return errors.New("field SecondaryOuterJoin set to true, but field is not being used in join") + } + + switch f.Conversion { + case "hwaddr", "enum(1)": + config.PrintOptionValueDeprecationNotice("inputs.snmp", "field.conversion", f.Conversion, telegraf.DeprecationInfo{ + Since: "1.33.0", + Notice: "Use 'displayhint' instead", + }) + } + + f.initialized = true + return nil +} + +// fieldConvert converts from any type according to the conv specification +func (f *Field) Convert(ent gosnmp.SnmpPDU) (interface{}, error) { + v := ent.Value + + // snmptranslate table field value here + if f.Translate { + if entOid, ok := v.(string); ok { + _, _, oidText, _, err := f.translator.SnmpTranslate(entOid) + if err == nil { + // If no error translating, the original value should be replaced + v = oidText + } + } + } + + if f.Conversion == "" { + // OctetStrings may contain hex data that needs its own conversion + if ent.Type == gosnmp.OctetString && !utf8.Valid(v.([]byte)[:]) { + return hex.EncodeToString(v.([]byte)), nil + } + if bs, ok := v.([]byte); ok { + return string(bs), nil + } + return v, nil + } + + var d int + if _, err := fmt.Sscanf(f.Conversion, "float(%d)", &d); err == nil || f.Conversion == "float" { + switch vt := v.(type) { + case float32: + v = float64(vt) / math.Pow10(d) + case float64: + v = vt / math.Pow10(d) + case int: + v = float64(vt) / math.Pow10(d) + case int8: + v = float64(vt) / math.Pow10(d) + case int16: + v = float64(vt) / math.Pow10(d) + case int32: + v = float64(vt) / math.Pow10(d) + case int64: + v = float64(vt) / math.Pow10(d) + case uint: + v = float64(vt) / math.Pow10(d) + case uint8: + v = float64(vt) / math.Pow10(d) + case uint16: + v = float64(vt) / math.Pow10(d) + case uint32: + v = float64(vt) / math.Pow10(d) + case uint64: + v = float64(vt) / math.Pow10(d) + case []byte: + vf, err := strconv.ParseFloat(string(vt), 64) + if err != nil { + return nil, fmt.Errorf("failed to convert field to float with value %s: %w", vt, err) + } + v = vf / math.Pow10(d) + case string: + vf, err := strconv.ParseFloat(vt, 64) + if err != nil { + return nil, fmt.Errorf("failed to convert field to float with value %s: %w", vt, err) + } + v = vf / math.Pow10(d) + } + return v, nil + } + + if f.Conversion == "int" { + var err error + switch vt := v.(type) { + case float32: + v = int64(vt) + case float64: + v = int64(vt) + case int: + v = int64(vt) + case int8: + v = int64(vt) + case int16: + v = int64(vt) + case int32: + v = int64(vt) + case int64: + v = vt + case uint: + v = int64(vt) + case uint8: + v = int64(vt) + case uint16: + v = int64(vt) + case uint32: + v = int64(vt) + case uint64: + v = int64(vt) + case []byte: + v, err = strconv.ParseInt(string(vt), 10, 64) + case string: + v, err = strconv.ParseInt(vt, 10, 64) + } + return v, err + } + + // Deprecated: Use displayhint instead + if f.Conversion == "hwaddr" { + switch vt := v.(type) { + case string: + v = net.HardwareAddr(vt).String() + case []byte: + v = net.HardwareAddr(vt).String() + default: + return nil, fmt.Errorf("invalid type (%T) for hwaddr conversion", vt) + } + return v, nil + } + + if f.Conversion == "hex" { + switch vt := v.(type) { + case string: + switch ent.Type { + case gosnmp.IPAddress: + ip := net.ParseIP(vt) + if ip4 := ip.To4(); ip4 != nil { + v = hex.EncodeToString(ip4) + } else { + v = hex.EncodeToString(ip) + } + default: + return nil, fmt.Errorf("unsupported Asn1BER (%#v) for hex conversion", ent.Type) + } + case []byte: + v = hex.EncodeToString(vt) + default: + return nil, fmt.Errorf("unsupported type (%T) for hex conversion", vt) + } + return v, nil + } + + split := strings.Split(f.Conversion, ":") + if split[0] == "hextoint" && len(split) == 3 { + endian := split[1] + bit := split[2] + + bv, ok := v.([]byte) + if !ok { + return v, nil + } + + var b []byte + switch bit { + case "uint64": + b = make([]byte, 8) + case "uint32": + b = make([]byte, 4) + case "uint16": + b = make([]byte, 2) + default: + return nil, fmt.Errorf("invalid bit value (%s) for hex to int conversion", bit) + } + copy(b, bv) + + var byteOrder binary.ByteOrder + switch endian { + case "LittleEndian": + byteOrder = binary.LittleEndian + case "BigEndian": + byteOrder = binary.BigEndian + default: + return nil, fmt.Errorf("invalid Endian value (%s) for hex to int conversion", endian) + } + + switch bit { + case "uint64": + v = byteOrder.Uint64(b) + case "uint32": + v = byteOrder.Uint32(b) + case "uint16": + v = byteOrder.Uint16(b) + } + + return v, nil + } + + if f.Conversion == "ipaddr" { + var ipbs []byte + + switch vt := v.(type) { + case string: + ipbs = []byte(vt) + case []byte: + ipbs = vt + default: + return nil, fmt.Errorf("invalid type (%T) for ipaddr conversion", vt) + } + + switch len(ipbs) { + case 4, 16: + v = net.IP(ipbs).String() + default: + return nil, fmt.Errorf("invalid length (%d) for ipaddr conversion", len(ipbs)) + } + + return v, nil + } + + if f.Conversion == "enum" { + return f.translator.SnmpFormatEnum(ent.Name, ent.Value, false) + } + + // Deprecated: Use displayhint instead + if f.Conversion == "enum(1)" { + return f.translator.SnmpFormatEnum(ent.Name, ent.Value, true) + } + + if f.Conversion == "displayhint" { + return f.translator.SnmpFormatDisplayHint(ent.Name, ent.Value) + } + + return nil, fmt.Errorf("invalid conversion type %q", f.Conversion) +} diff --git a/internal/snmp/field_test.go b/internal/snmp/field_test.go new file mode 100644 index 0000000..d2b604d --- /dev/null +++ b/internal/snmp/field_test.go @@ -0,0 +1,252 @@ +package snmp + +import ( + "testing" + + "github.com/gosnmp/gosnmp" + "github.com/stretchr/testify/require" +) + +func TestConvertDefault(t *testing.T) { + tests := []struct { + name string + ent gosnmp.SnmpPDU + expected interface{} + errmsg string + }{ + { + name: "integer", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.Integer, + Value: int(2), + }, + expected: 2, + }, + { + name: "octet string with valid bytes", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.OctetString, + Value: []byte{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64}, + }, + expected: "Hello world", + }, + { + name: "octet string with invalid bytes", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.OctetString, + Value: []byte{0x84, 0xc8, 0x7, 0xff, 0xfd, 0x38, 0x54, 0xc1}, + }, + expected: "84c807fffd3854c1", + }, + } + + f := Field{} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual, err := f.Convert(tt.ent) + + if tt.errmsg != "" { + require.ErrorContains(t, err, tt.errmsg) + } else { + require.NoError(t, err) + } + + require.Equal(t, tt.expected, actual) + }) + } + + t.Run("invalid", func(t *testing.T) { + f.Conversion = "invalid" + actual, err := f.Convert(gosnmp.SnmpPDU{}) + + require.Nil(t, actual) + require.ErrorContains(t, err, "invalid conversion type") + }) +} + +func TestConvertHex(t *testing.T) { + tests := []struct { + name string + ent gosnmp.SnmpPDU + expected interface{} + errmsg string + }{ + { + name: "octet string with valid bytes", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.OctetString, + Value: []byte{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64}, + }, + expected: "48656c6c6f20776f726c64", + }, + { + name: "octet string with invalid bytes", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.OctetString, + Value: []byte{0x84, 0xc8, 0x7, 0xff, 0xfd, 0x38, 0x54, 0xc1}, + }, + expected: "84c807fffd3854c1", + }, + { + name: "IPv4", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.IPAddress, + Value: "192.0.2.1", + }, + expected: "c0000201", + }, + { + name: "IPv6", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.IPAddress, + Value: "2001:db8::1", + }, + expected: "20010db8000000000000000000000001", + }, + { + name: "oid", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.ObjectIdentifier, + Value: ".1.2.3", + }, + errmsg: "unsupported Asn1BER (0x6) for hex conversion", + }, + { + name: "integer", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.Integer, + Value: int(2), + }, + errmsg: "unsupported type (int) for hex conversion", + }, + } + + f := Field{Conversion: "hex"} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual, err := f.Convert(tt.ent) + + if tt.errmsg != "" { + require.ErrorContains(t, err, tt.errmsg) + } else { + require.NoError(t, err) + } + + require.Equal(t, tt.expected, actual) + }) + } +} + +func TestConvertHextoint(t *testing.T) { + tests := []struct { + name string + conversion string + ent gosnmp.SnmpPDU + expected interface{} + errmsg string + }{ + { + name: "empty", + conversion: "hextoint:BigEndian:uint64", + ent: gosnmp.SnmpPDU{}, + expected: nil, + }, + { + name: "big endian uint64", + conversion: "hextoint:BigEndian:uint64", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.OctetString, + Value: []byte{0x84, 0xc8, 0x7, 0xff, 0xfd, 0x38, 0x54, 0xc1}, + }, + expected: uint64(0x84c807fffd3854c1), + }, + { + name: "big endian uint32", + conversion: "hextoint:BigEndian:uint32", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.OctetString, + Value: []byte{0x84, 0xc8, 0x7, 0xff}, + }, + expected: uint32(0x84c807ff), + }, + { + name: "big endian uint16", + conversion: "hextoint:BigEndian:uint16", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.OctetString, + Value: []byte{0x84, 0xc8}, + }, + expected: uint16(0x84c8), + }, + { + name: "big endian invalid", + conversion: "hextoint:BigEndian:invalid", + ent: gosnmp.SnmpPDU{Type: gosnmp.OctetString, Value: make([]uint8, 0)}, + errmsg: "invalid bit value", + }, + { + name: "little endian uint64", + conversion: "hextoint:LittleEndian:uint64", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.OctetString, + Value: []byte{0x84, 0xc8, 0x7, 0xff, 0xfd, 0x38, 0x54, 0xc1}, + }, + expected: uint64(0xc15438fdff07c884), + }, + { + name: "little endian uint32", + conversion: "hextoint:LittleEndian:uint32", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.OctetString, + Value: []byte{0x84, 0xc8, 0x7, 0xff}, + }, + expected: uint32(0xff07c884), + }, + { + name: "little endian uint16", + conversion: "hextoint:LittleEndian:uint16", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.OctetString, + Value: []byte{0x84, 0xc8}, + }, + expected: uint16(0xc884), + }, + { + name: "little endian single byte", + conversion: "hextoint:LittleEndian:uint16", + ent: gosnmp.SnmpPDU{ + Type: gosnmp.OctetString, + Value: []byte{0x84}, + }, + expected: uint16(0x84), + }, + { + name: "little endian invalid", + conversion: "hextoint:LittleEndian:invalid", + ent: gosnmp.SnmpPDU{Type: gosnmp.OctetString, Value: make([]byte, 0)}, + errmsg: "invalid bit value", + }, + { + name: "invalid", + conversion: "hextoint:invalid:uint64", + ent: gosnmp.SnmpPDU{Type: gosnmp.OctetString, Value: make([]byte, 0)}, + errmsg: "invalid Endian value", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + f := Field{Conversion: tt.conversion} + + actual, err := f.Convert(tt.ent) + + if tt.errmsg != "" { + require.ErrorContains(t, err, tt.errmsg) + } else { + require.NoError(t, err) + } + + require.Equal(t, tt.expected, actual) + }) + } +} diff --git a/internal/snmp/mib_loader.go b/internal/snmp/mib_loader.go new file mode 100644 index 0000000..d664176 --- /dev/null +++ b/internal/snmp/mib_loader.go @@ -0,0 +1,140 @@ +package snmp + +import ( + "fmt" + "os" + "path/filepath" + "sync" + + "github.com/sleepinggenius2/gosmi" + + "github.com/influxdata/telegraf" +) + +// must init, append path for each directory, load module for every file +// or gosmi will fail without saying why +var m sync.Mutex +var once sync.Once +var cache = make(map[string]bool) + +type MibLoader interface { + // appendPath takes the path of a directory + appendPath(path string) + + // loadModule takes the name of a file in one of the + // directories. Basename only, no relative or absolute path + loadModule(path string) error +} + +type GosmiMibLoader struct{} + +func (*GosmiMibLoader) appendPath(path string) { + m.Lock() + defer m.Unlock() + + gosmi.AppendPath(path) +} + +func (*GosmiMibLoader) loadModule(path string) error { + m.Lock() + defer m.Unlock() + + _, err := gosmi.LoadModule(path) + return err +} + +// will give all found folders to gosmi and load in all modules found in the folders +func LoadMibsFromPath(paths []string, log telegraf.Logger, loader MibLoader) error { + folders, err := walkPaths(paths, log) + if err != nil { + return err + } + for _, path := range folders { + loader.appendPath(path) + modules, err := os.ReadDir(path) + if err != nil { + log.Warnf("Can't read directory %v", modules) + continue + } + + for _, entry := range modules { + info, err := entry.Info() + if err != nil { + log.Warnf("Couldn't get info for %v: %v", entry.Name(), err) + continue + } + if info.Mode()&os.ModeSymlink != 0 { + symlink := filepath.Join(path, info.Name()) + target, err := filepath.EvalSymlinks(symlink) + if err != nil { + log.Warnf("Couldn't evaluate symbolic links for %v: %v", symlink, err) + continue + } + // replace symlink's info with the target's info + info, err = os.Lstat(target) + if err != nil { + log.Warnf("Couldn't stat target %v: %v", target, err) + continue + } + } + if info.Mode().IsRegular() { + err := loader.loadModule(info.Name()) + if err != nil { + log.Warnf("Couldn't load module %v: %v", info.Name(), err) + continue + } + } + } + } + return nil +} + +// should walk the paths given and find all folders +func walkPaths(paths []string, log telegraf.Logger) ([]string, error) { + once.Do(gosmi.Init) + + folders := make([]string, 0) + for _, mibPath := range paths { + // Check if we loaded that path already and skip it if so + m.Lock() + cached := cache[mibPath] + cache[mibPath] = true + m.Unlock() + if cached { + continue + } + + err := filepath.Walk(mibPath, func(path string, info os.FileInfo, err error) error { + if info == nil { + log.Warnf("No mibs found") + if os.IsNotExist(err) { + log.Warnf("MIB path doesn't exist: %q", mibPath) + } else if err != nil { + return err + } + return nil + } + + if info.Mode()&os.ModeSymlink != 0 { + target, err := filepath.EvalSymlinks(path) + if err != nil { + log.Warnf("Couldn't evaluate symbolic links for %v: %v", path, err) + } + info, err = os.Lstat(target) + if err != nil { + log.Warnf("Couldn't stat target %v: %v", target, err) + } + path = target + } + if info.IsDir() { + folders = append(folders, path) + } + + return nil + }) + if err != nil { + return folders, fmt.Errorf("couldn't walk path %q: %w", mibPath, err) + } + } + return folders, nil +} diff --git a/internal/snmp/mib_loader_test.go b/internal/snmp/mib_loader_test.go new file mode 100644 index 0000000..88ff48e --- /dev/null +++ b/internal/snmp/mib_loader_test.go @@ -0,0 +1,87 @@ +package snmp + +import ( + "path/filepath" + "runtime" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/influxdata/telegraf/testutil" +) + +type TestingMibLoader struct { + folders []string + files []string +} + +func (t *TestingMibLoader) appendPath(path string) { + t.folders = append(t.folders, path) +} + +func (t *TestingMibLoader) loadModule(path string) error { + t.files = append(t.files, path) + return nil +} +func TestFolderLookup(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("Skipping on windows") + } + + tests := []struct { + name string + mibPath [][]string + paths [][]string + files []string + }{ + { + name: "loading folders", + mibPath: [][]string{{"testdata", "loadMibsFromPath", "root"}}, + paths: [][]string{ + {"testdata", "loadMibsFromPath", "root"}, + {"testdata", "loadMibsFromPath", "root", "dirOne"}, + {"testdata", "loadMibsFromPath", "root", "dirOne", "dirTwo"}, + {"testdata", "loadMibsFromPath", "linkTarget"}, + }, + files: []string{"empty", "emptyFile"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + loader := TestingMibLoader{} + + var givenPath []string + for _, paths := range tt.mibPath { + rootPath := filepath.Join(paths...) + givenPath = append(givenPath, rootPath) + } + + err := LoadMibsFromPath(givenPath, testutil.Logger{}, &loader) + require.NoError(t, err) + + var folders []string + for _, pathSlice := range tt.paths { + path := filepath.Join(pathSlice...) + folders = append(folders, path) + } + require.Equal(t, folders, loader.folders) + + require.Equal(t, tt.files, loader.files) + }) + } +} + +func TestMissingMibPath(t *testing.T) { + log := testutil.Logger{} + path := []string{"non-existing-directory"} + require.NoError(t, LoadMibsFromPath(path, log, &GosmiMibLoader{})) +} + +func BenchmarkMibLoading(b *testing.B) { + log := testutil.Logger{} + path := []string{"testdata/gosmi"} + for i := 0; i < b.N; i++ { + require.NoError(b, LoadMibsFromPath(path, log, &GosmiMibLoader{})) + } +} diff --git a/internal/snmp/table.go b/internal/snmp/table.go new file mode 100644 index 0000000..6f7eed5 --- /dev/null +++ b/internal/snmp/table.go @@ -0,0 +1,304 @@ +package snmp + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/gosnmp/gosnmp" +) + +// Table holds the configuration for a SNMP table. +type Table struct { + // Name will be the name of the measurement. + Name string + + // Which tags to inherit from the top-level config. + InheritTags []string + + // Adds each row's table index as a tag. + IndexAsTag bool + + // Fields is the tags and values to look up. + Fields []Field `toml:"field"` + + // OID for automatic field population. + // If provided, init() will populate Fields with all the table columns of the + // given OID. + Oid string + + initialized bool + translator Translator +} + +// RTable is the resulting table built from a Table. +type RTable struct { + // Name is the name of the field, copied from Table.Name. + Name string + // Time is the time the table was built. + Time time.Time + // Rows are the rows that were found, one row for each table OID index found. + Rows []RTableRow +} + +// RTableRow is the resulting row containing all the OID values which shared +// the same index. +type RTableRow struct { + // Tags are all the Field values which had IsTag=true. + Tags map[string]string + // Fields are all the Field values which had IsTag=false. + Fields map[string]interface{} +} + +// Init builds & initializes the nested fields. +func (t *Table) Init(tr Translator) error { + // makes sure oid or name is set in config file + // otherwise snmp will produce metrics with an empty name + if t.Oid == "" && t.Name == "" { + return errors.New("unnamed SNMP table in config file: one or both of the oid and name settings must be set") + } + + if t.initialized { + return nil + } + + t.translator = tr + if err := t.initBuild(); err != nil { + return err + } + + secondaryIndexTablePresent := false + // initialize all the nested fields + for i := range t.Fields { + if err := t.Fields[i].Init(t.translator); err != nil { + return fmt.Errorf("initializing field %s: %w", t.Fields[i].Name, err) + } + if t.Fields[i].SecondaryIndexTable { + if secondaryIndexTablePresent { + return errors.New("only one field can be SecondaryIndexTable") + } + secondaryIndexTablePresent = true + } + } + + t.initialized = true + return nil +} + +// initBuild initializes the table if it has an OID configured. If so, the +// net-snmp tools will be used to look up the OID and auto-populate the table's +// fields. +func (t *Table) initBuild() error { + if t.Oid == "" { + return nil + } + + _, _, oidText, fields, err := t.translator.SnmpTable(t.Oid) + if err != nil { + return err + } + + if t.Name == "" { + t.Name = oidText + } + + knownOIDs := make(map[string]bool, len(t.Fields)) + for _, f := range t.Fields { + knownOIDs[f.Oid] = true + } + for _, f := range fields { + if !knownOIDs[f.Oid] { + t.Fields = append(t.Fields, f) + } + } + + return nil +} + +// Build retrieves all the fields specified in the table and constructs the RTable. +func (t Table) Build(gs Connection, walk bool) (*RTable, error) { + rows := make(map[string]RTableRow) + + // translation table for secondary index (when performing join on two tables) + secIdxTab := make(map[string]string) + secGlobalOuterJoin := false + for i, f := range t.Fields { + if f.SecondaryIndexTable { + secGlobalOuterJoin = f.SecondaryOuterJoin + if i != 0 { + t.Fields[0], t.Fields[i] = t.Fields[i], t.Fields[0] + } + break + } + } + + tagCount := 0 + for _, f := range t.Fields { + if f.IsTag { + tagCount++ + } + + if len(f.Oid) == 0 { + return nil, fmt.Errorf("cannot have empty OID on field %s", f.Name) + } + var oid string + if f.Oid[0] == '.' { + oid = f.Oid + } else { + // make sure OID has "." because the BulkWalkAll results do, and the prefix needs to match + oid = "." + f.Oid + } + + // ifv contains a mapping of table OID index to field value + ifv := make(map[string]interface{}) + + if !walk { + // This is used when fetching non-table fields. Fields configured a the top + // scope of the plugin. + // We fetch the fields directly, and add them to ifv as if the index were an + // empty string. This results in all the non-table fields sharing the same + // index, and being added on the same row. + if pkt, err := gs.Get([]string{oid}); err != nil { + if errors.Is(err, gosnmp.ErrUnknownSecurityLevel) { + return nil, errors.New("unknown security level (sec_level)") + } else if errors.Is(err, gosnmp.ErrUnknownUsername) { + return nil, errors.New("unknown username (sec_name)") + } else if errors.Is(err, gosnmp.ErrWrongDigest) { + return nil, errors.New("wrong digest (auth_protocol, auth_password)") + } else if errors.Is(err, gosnmp.ErrDecryption) { + return nil, errors.New("decryption error (priv_protocol, priv_password)") + } + return nil, fmt.Errorf("performing get on field %s: %w", f.Name, err) + } else if pkt != nil && len(pkt.Variables) > 0 && pkt.Variables[0].Type != gosnmp.NoSuchObject && pkt.Variables[0].Type != gosnmp.NoSuchInstance { + ent := pkt.Variables[0] + fv, err := f.Convert(ent) + if err != nil { + return nil, fmt.Errorf("converting %q (OID %s) for field %s: %w", ent.Value, ent.Name, f.Name, err) + } + ifv[""] = fv + } + } else { + err := gs.Walk(oid, func(ent gosnmp.SnmpPDU) error { + if len(ent.Name) <= len(oid) || ent.Name[:len(oid)+1] != oid+"." { + return &walkError{} // break the walk + } + + idx := ent.Name[len(oid):] + if f.OidIndexSuffix != "" { + if !strings.HasSuffix(idx, f.OidIndexSuffix) { + // this entry doesn't match our OidIndexSuffix. skip it + return nil + } + idx = idx[:len(idx)-len(f.OidIndexSuffix)] + } + if f.OidIndexLength != 0 { + i := f.OidIndexLength + 1 // leading separator + idx = strings.Map(func(r rune) rune { + if r == '.' { + i-- + } + if i < 1 { + return -1 + } + return r + }, idx) + } + + fv, err := f.Convert(ent) + if err != nil { + return &walkError{ + msg: fmt.Sprintf("converting %q (OID %s) for field %s", ent.Value, ent.Name, f.Name), + err: err, + } + } + ifv[idx] = fv + return nil + }) + if err != nil { + // Our callback always wraps errors in a walkError. + // If this error isn't a walkError, we know it's not + // from the callback + var walkErr *walkError + if !errors.As(err, &walkErr) { + return nil, fmt.Errorf("performing bulk walk for field %s: %w", f.Name, err) + } + } + } + + for idx, v := range ifv { + if f.SecondaryIndexUse { + if newidx, ok := secIdxTab[idx]; ok { + idx = newidx + } else { + if !secGlobalOuterJoin && !f.SecondaryOuterJoin { + continue + } + idx = ".Secondary" + idx + } + } + rtr, ok := rows[idx] + if !ok { + rtr = RTableRow{} + rtr.Tags = make(map[string]string) + rtr.Fields = make(map[string]interface{}) + rows[idx] = rtr + } + if t.IndexAsTag && idx != "" { + if idx[0] == '.' { + idx = idx[1:] + } + rtr.Tags["index"] = idx + } + // don't add an empty string + if vs, ok := v.(string); !ok || vs != "" { + if f.IsTag { + if ok { + rtr.Tags[f.Name] = vs + } else { + rtr.Tags[f.Name] = fmt.Sprintf("%v", v) + } + } else { + rtr.Fields[f.Name] = v + } + if f.SecondaryIndexTable { + // indexes are stored here with prepending "." so we need to add them if needed + var vss string + if ok { + vss = "." + vs + } else { + vss = fmt.Sprintf(".%v", v) + } + if idx[0] == '.' { + secIdxTab[vss] = idx + } else { + secIdxTab[vss] = "." + idx + } + } + } + } + } + + rt := RTable{ + Name: t.Name, + Time: time.Now(), // TODO record time at start + Rows: make([]RTableRow, 0, len(rows)), + } + for _, r := range rows { + rt.Rows = append(rt.Rows, r) + } + return &rt, nil +} + +type walkError struct { + msg string + err error +} + +func (e *walkError) Error() string { + return e.msg +} + +func (e *walkError) Unwrap() error { + return e.err +} diff --git a/internal/snmp/table_test.go b/internal/snmp/table_test.go new file mode 100644 index 0000000..d97f723 --- /dev/null +++ b/internal/snmp/table_test.go @@ -0,0 +1,246 @@ +package snmp + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestTableJoin_walk(t *testing.T) { + tbl := Table{ + Name: "mytable", + IndexAsTag: true, + Fields: []Field{ + { + Name: "myfield1", + Oid: ".1.0.0.3.1.1", + IsTag: true, + }, + { + Name: "myfield2", + Oid: ".1.0.0.3.1.2", + }, + { + Name: "myfield3", + Oid: ".1.0.0.3.1.3", + SecondaryIndexTable: true, + }, + { + Name: "myfield4", + Oid: ".1.0.0.0.1.1", + SecondaryIndexUse: true, + IsTag: true, + }, + { + Name: "myfield5", + Oid: ".1.0.0.0.1.2", + SecondaryIndexUse: true, + }, + }, + } + + tb, err := tbl.Build(tsc, true) + require.NoError(t, err) + + require.Equal(t, "mytable", tb.Name) + rtr1 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance", + "myfield4": "bar", + "index": "10", + }, + Fields: map[string]interface{}{ + "myfield2": 10, + "myfield3": 1, + "myfield5": 2, + }, + } + rtr2 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance2", + "index": "11", + }, + Fields: map[string]interface{}{ + "myfield2": 20, + "myfield3": 2, + "myfield5": 0, + }, + } + rtr3 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance3", + "index": "12", + }, + Fields: map[string]interface{}{ + "myfield2": 20, + "myfield3": 3, + }, + } + require.Len(t, tb.Rows, 3) + require.Contains(t, tb.Rows, rtr1) + require.Contains(t, tb.Rows, rtr2) + require.Contains(t, tb.Rows, rtr3) +} + +func TestTableOuterJoin_walk(t *testing.T) { + tbl := Table{ + Name: "mytable", + IndexAsTag: true, + Fields: []Field{ + { + Name: "myfield1", + Oid: ".1.0.0.3.1.1", + IsTag: true, + }, + { + Name: "myfield2", + Oid: ".1.0.0.3.1.2", + }, + { + Name: "myfield3", + Oid: ".1.0.0.3.1.3", + SecondaryIndexTable: true, + SecondaryOuterJoin: true, + }, + { + Name: "myfield4", + Oid: ".1.0.0.0.1.1", + SecondaryIndexUse: true, + IsTag: true, + }, + { + Name: "myfield5", + Oid: ".1.0.0.0.1.2", + SecondaryIndexUse: true, + }, + }, + } + + tb, err := tbl.Build(tsc, true) + require.NoError(t, err) + + require.Equal(t, "mytable", tb.Name) + rtr1 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance", + "myfield4": "bar", + "index": "10", + }, + Fields: map[string]interface{}{ + "myfield2": 10, + "myfield3": 1, + "myfield5": 2, + }, + } + rtr2 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance2", + "index": "11", + }, + Fields: map[string]interface{}{ + "myfield2": 20, + "myfield3": 2, + "myfield5": 0, + }, + } + rtr3 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance3", + "index": "12", + }, + Fields: map[string]interface{}{ + "myfield2": 20, + "myfield3": 3, + }, + } + rtr4 := RTableRow{ + Tags: map[string]string{ + "index": "Secondary.0", + "myfield4": "foo", + }, + Fields: map[string]interface{}{ + "myfield5": 1, + }, + } + require.Len(t, tb.Rows, 4) + require.Contains(t, tb.Rows, rtr1) + require.Contains(t, tb.Rows, rtr2) + require.Contains(t, tb.Rows, rtr3) + require.Contains(t, tb.Rows, rtr4) +} + +func TestTableJoinNoIndexAsTag_walk(t *testing.T) { + tbl := Table{ + Name: "mytable", + IndexAsTag: false, + Fields: []Field{ + { + Name: "myfield1", + Oid: ".1.0.0.3.1.1", + IsTag: true, + }, + { + Name: "myfield2", + Oid: ".1.0.0.3.1.2", + }, + { + Name: "myfield3", + Oid: ".1.0.0.3.1.3", + SecondaryIndexTable: true, + }, + { + Name: "myfield4", + Oid: ".1.0.0.0.1.1", + SecondaryIndexUse: true, + IsTag: true, + }, + { + Name: "myfield5", + Oid: ".1.0.0.0.1.2", + SecondaryIndexUse: true, + }, + }, + } + + tb, err := tbl.Build(tsc, true) + require.NoError(t, err) + + require.Equal(t, "mytable", tb.Name) + rtr1 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance", + "myfield4": "bar", + // "index": "10", + }, + Fields: map[string]interface{}{ + "myfield2": 10, + "myfield3": 1, + "myfield5": 2, + }, + } + rtr2 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance2", + // "index": "11", + }, + Fields: map[string]interface{}{ + "myfield2": 20, + "myfield3": 2, + "myfield5": 0, + }, + } + rtr3 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance3", + // "index": "12", + }, + Fields: map[string]interface{}{ + "myfield2": 20, + "myfield3": 3, + }, + } + require.Len(t, tb.Rows, 3) + require.Contains(t, tb.Rows, rtr1) + require.Contains(t, tb.Rows, rtr2) + require.Contains(t, tb.Rows, rtr3) +} diff --git a/internal/snmp/testdata/gosmi/bridgeMib b/internal/snmp/testdata/gosmi/bridgeMib new file mode 100644 index 0000000..96f5627 --- /dev/null +++ b/internal/snmp/testdata/gosmi/bridgeMib @@ -0,0 +1,1467 @@ +BRIDGE-MIB DEFINITIONS ::= BEGIN + +-- ---------------------------------------------------------- -- +-- MIB for IEEE 802.1D devices +-- ---------------------------------------------------------- -- +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, + Counter32, Integer32, TimeTicks, mib-2, TEXTUAL-CONVENTION, MacAddress, + MODULE-COMPLIANCE, NOTIFICATION-GROUP, OBJECT-GROUP, InterfaceIndex + FROM bridgeMibImports; + +dot1dBridge MODULE-IDENTITY + LAST-UPDATED "200509190000Z" + ORGANIZATION "IETF Bridge MIB Working Group" + CONTACT-INFO + "Email: bridge-mib@ietf.org + + K.C. Norseth (Editor) + L-3 Communications + Tel: +1 801-594-2809 + Email: kenyon.c.norseth@L-3com.com + Postal: 640 N. 2200 West. + Salt Lake City, Utah 84116-0850 + + Les Bell (Editor) + 3Com Europe Limited + Phone: +44 1442 438025 + Email: elbell@ntlworld.com + Postal: 3Com Centre, Boundary Way + Hemel Hempstead + Herts. HP2 7YU + UK + + Send comments to " + DESCRIPTION + "The Bridge MIB module for managing devices that support + IEEE 802.1D. + + Copyright (C) The Internet Society (2005). This version of + this MIB module is part of RFC 4188; see the RFC itself for + full legal notices." + REVISION "200509190000Z" + DESCRIPTION + "Third revision, published as part of RFC 4188. + + The MIB module has been converted to SMIv2 format. + Conformance statements have been added and some + description and reference clauses have been updated. + + The object dot1dStpPortPathCost32 was added to + support IEEE 802.1t and the permissible values of + dot1dStpPriority and dot1dStpPortPriority have been + clarified for bridges supporting IEEE 802.1t or + IEEE 802.1w. + + The interpretation of dot1dStpTimeSinceTopologyChange + has been clarified for bridges supporting the Rapid + Spanning Tree Protocol (RSTP)." + REVISION "199307310000Z" + DESCRIPTION + "Second revision, published as part of RFC 1493." + REVISION "199112310000Z" + DESCRIPTION + "Initial revision, published as part of RFC 1286." + ::= { mib-2 17 } + +-- ---------------------------------------------------------- -- +-- Textual Conventions +-- ---------------------------------------------------------- -- + +BridgeId ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The Bridge-Identifier, as used in the Spanning Tree + Protocol, to uniquely identify a bridge. Its first two + octets (in network byte order) contain a priority value, + and its last 6 octets contain the MAC address used to + refer to a bridge in a unique fashion (typically, the + numerically smallest MAC address of all ports on the + bridge)." + SYNTAX OCTET STRING (SIZE (8)) + +Timeout ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "A Spanning Tree Protocol (STP) timer in units of 1/100 + seconds. Several objects in this MIB module represent + values of timers used by the Spanning Tree Protocol. + In this MIB, these timers have values in units of + hundredths of a second (i.e., 1/100 secs). + + These timers, when stored in a Spanning Tree Protocol's + BPDU, are in units of 1/256 seconds. Note, however, that + 802.1D-1998 specifies a settable granularity of no more + than one second for these timers. To avoid ambiguity, + a conversion algorithm is defined below for converting + between the different units, which ensures a timer's + value is not distorted by multiple conversions. + + To convert a Timeout value into a value in units of + 1/256 seconds, the following algorithm should be used: + + b = floor( (n * 256) / 100) + + where: + floor = quotient [ignore remainder] + n is the value in 1/100 second units + b is the value in 1/256 second units + + To convert the value from 1/256 second units back to + 1/100 seconds, the following algorithm should be used: + + n = ceiling( (b * 100) / 256) + + where: + ceiling = quotient [if remainder is 0], or + quotient + 1 [if remainder is nonzero] + n is the value in 1/100 second units + + b is the value in 1/256 second units + + Note: it is important that the arithmetic operations are + done in the order specified (i.e., multiply first, + divide second)." + SYNTAX Integer32 + +-- ---------------------------------------------------------- -- +-- subtrees in the Bridge MIB +-- ---------------------------------------------------------- -- + +dot1dNotifications OBJECT IDENTIFIER ::= { dot1dBridge 0 } + +dot1dBase OBJECT IDENTIFIER ::= { dot1dBridge 1 } +dot1dStp OBJECT IDENTIFIER ::= { dot1dBridge 2 } + +dot1dSr OBJECT IDENTIFIER ::= { dot1dBridge 3 } +-- documented in RFC 1525 + +dot1dTp OBJECT IDENTIFIER ::= { dot1dBridge 4 } +dot1dStatic OBJECT IDENTIFIER ::= { dot1dBridge 5 } + +-- Subtrees used by Bridge MIB Extensions: +-- pBridgeMIB MODULE-IDENTITY ::= { dot1dBridge 6 } +-- qBridgeMIB MODULE-IDENTITY ::= { dot1dBridge 7 } +-- Note that the practice of registering related MIB modules +-- below dot1dBridge has been discouraged since there is no +-- robust mechanism to track such registrations. + +dot1dConformance OBJECT IDENTIFIER ::= { dot1dBridge 8 } + +-- ---------------------------------------------------------- -- +-- the dot1dBase subtree +-- ---------------------------------------------------------- -- +-- Implementation of the dot1dBase subtree is mandatory for all +-- bridges. +-- ---------------------------------------------------------- -- + +dot1dBaseBridgeAddress OBJECT-TYPE + SYNTAX MacAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The MAC address used by this bridge when it must be + referred to in a unique fashion. It is recommended + that this be the numerically smallest MAC address of + all ports that belong to this bridge. However, it is only + + required to be unique. When concatenated with + dot1dStpPriority, a unique BridgeIdentifier is formed, + which is used in the Spanning Tree Protocol." + REFERENCE + "IEEE 802.1D-1998: clauses 14.4.1.1.3 and 7.12.5" + ::= { dot1dBase 1 } + +dot1dBaseNumPorts OBJECT-TYPE + SYNTAX Integer32 + UNITS "ports" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of ports controlled by this bridging + entity." + REFERENCE + "IEEE 802.1D-1998: clause 14.4.1.1.3" + ::= { dot1dBase 2 } + +dot1dBaseType OBJECT-TYPE + SYNTAX INTEGER { + unknown(1), + transparent-only(2), + sourceroute-only(3), + srt(4) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates what type of bridging this bridge can + perform. If a bridge is actually performing a + certain type of bridging, this will be indicated by + entries in the port table for the given type." + ::= { dot1dBase 3 } + +-- ---------------------------------------------------------- -- +-- The Generic Bridge Port Table +-- ---------------------------------------------------------- -- +dot1dBasePortTable OBJECT-TYPE + SYNTAX SEQUENCE OF Dot1dBasePortEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table that contains generic information about every + port that is associated with this bridge. Transparent, + source-route, and srt ports are included." + ::= { dot1dBase 4 } + +dot1dBasePortEntry OBJECT-TYPE + SYNTAX Dot1dBasePortEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of information for each port of the bridge." + REFERENCE + "IEEE 802.1D-1998: clause 14.4.2, 14.6.1" + INDEX { dot1dBasePort } + ::= { dot1dBasePortTable 1 } + +Dot1dBasePortEntry ::= + SEQUENCE { + dot1dBasePort + Integer32, + dot1dBasePortIfIndex + InterfaceIndex, + dot1dBasePortCircuit + OBJECT IDENTIFIER, + dot1dBasePortDelayExceededDiscards + Counter32, + dot1dBasePortMtuExceededDiscards + Counter32 + } + +dot1dBasePort OBJECT-TYPE + SYNTAX Integer32 (1..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The port number of the port for which this entry + contains bridge management information." + ::= { dot1dBasePortEntry 1 } + +dot1dBasePortIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of the instance of the ifIndex object, + defined in IF-MIB, for the interface corresponding + to this port." + ::= { dot1dBasePortEntry 2 } + +dot1dBasePortCircuit OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "For a port that (potentially) has the same value of + dot1dBasePortIfIndex as another port on the same bridge. + This object contains the name of an object instance + unique to this port. For example, in the case where + multiple ports correspond one-to-one with multiple X.25 + virtual circuits, this value might identify an (e.g., + the first) object instance associated with the X.25 + virtual circuit corresponding to this port. + + For a port which has a unique value of + dot1dBasePortIfIndex, this object can have the value + { 0 0 }." + ::= { dot1dBasePortEntry 3 } + +dot1dBasePortDelayExceededDiscards OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of frames discarded by this port due + to excessive transit delay through the bridge. It + is incremented by both transparent and source + route bridges." + REFERENCE + "IEEE 802.1D-1998: clause 14.6.1.1.3" + ::= { dot1dBasePortEntry 4 } + +dot1dBasePortMtuExceededDiscards OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of frames discarded by this port due + to an excessive size. It is incremented by both + transparent and source route bridges." + REFERENCE + "IEEE 802.1D-1998: clause 14.6.1.1.3" + ::= { dot1dBasePortEntry 5 } + +-- ---------------------------------------------------------- -- +-- the dot1dStp subtree +-- ---------------------------------------------------------- -- +-- Implementation of the dot1dStp subtree is optional. It is +-- implemented by those bridges that support the Spanning Tree +-- Protocol. +-- ---------------------------------------------------------- -- + +dot1dStpProtocolSpecification OBJECT-TYPE + SYNTAX INTEGER { + unknown(1), + decLb100(2), + ieee8021d(3) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "An indication of what version of the Spanning Tree + Protocol is being run. The value 'decLb100(2)' + indicates the DEC LANbridge 100 Spanning Tree protocol. + IEEE 802.1D implementations will return 'ieee8021d(3)'. + If future versions of the IEEE Spanning Tree Protocol + that are incompatible with the current version + are released a new value will be defined." + ::= { dot1dStp 1 } + +dot1dStpPriority OBJECT-TYPE + SYNTAX Integer32 (0..65535) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The value of the write-able portion of the Bridge ID + (i.e., the first two octets of the (8 octet long) Bridge + ID). The other (last) 6 octets of the Bridge ID are + given by the value of dot1dBaseBridgeAddress. + On bridges supporting IEEE 802.1t or IEEE 802.1w, + permissible values are 0-61440, in steps of 4096." + REFERENCE + "IEEE 802.1D-1998 clause 8.10.2, Table 8-4, + IEEE 802.1t clause 8.10.2, Table 8-4, clause 14.3." + ::= { dot1dStp 2 } + +dot1dStpTimeSinceTopologyChange OBJECT-TYPE + SYNTAX TimeTicks + UNITS "centi-seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The time (in hundredths of a second) since the + last time a topology change was detected by the + bridge entity. + For RSTP, this reports the time since the tcWhile + timer for any port on this Bridge was nonzero." + REFERENCE + "IEEE 802.1D-1998 clause 14.8.1.1., + IEEE 802.1w clause 14.8.1.1." + ::= { dot1dStp 3 } + +dot1dStpTopChanges OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of topology changes detected by + this bridge since the management entity was last + reset or initialized." + REFERENCE + "IEEE 802.1D-1998 clause 14.8.1.1." + ::= { dot1dStp 4 } + +dot1dStpDesignatedRoot OBJECT-TYPE + SYNTAX BridgeId + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The bridge identifier of the root of the spanning + tree, as determined by the Spanning Tree Protocol, + as executed by this node. This value is used as + the Root Identifier parameter in all Configuration + Bridge PDUs originated by this node." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.3.1" + ::= { dot1dStp 5 } + +dot1dStpRootCost OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The cost of the path to the root as seen from + this bridge." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.3.2" + ::= { dot1dStp 6 } + +dot1dStpRootPort OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The port number of the port that offers the lowest + cost path from this bridge to the root bridge." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.3.3" + ::= { dot1dStp 7 } + +dot1dStpMaxAge OBJECT-TYPE + SYNTAX Timeout + UNITS "centi-seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The maximum age of Spanning Tree Protocol information + learned from the network on any port before it is + discarded, in units of hundredths of a second. This is + the actual value that this bridge is currently using." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.3.4" + ::= { dot1dStp 8 } + +dot1dStpHelloTime OBJECT-TYPE + SYNTAX Timeout + UNITS "centi-seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The amount of time between the transmission of + Configuration bridge PDUs by this node on any port when + it is the root of the spanning tree, or trying to become + so, in units of hundredths of a second. This is the + actual value that this bridge is currently using." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.3.5" + ::= { dot1dStp 9 } + +dot1dStpHoldTime OBJECT-TYPE + SYNTAX Integer32 + UNITS "centi-seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This time value determines the interval length + during which no more than two Configuration bridge + PDUs shall be transmitted by this node, in units + of hundredths of a second." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.3.14" + ::= { dot1dStp 10 } + +dot1dStpForwardDelay OBJECT-TYPE + SYNTAX Timeout + UNITS "centi-seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This time value, measured in units of hundredths of a + second, controls how fast a port changes its spanning + state when moving towards the Forwarding state. The + value determines how long the port stays in each of the + Listening and Learning states, which precede the + Forwarding state. This value is also used when a + topology change has been detected and is underway, to + age all dynamic entries in the Forwarding Database. + [Note that this value is the one that this bridge is + currently using, in contrast to + dot1dStpBridgeForwardDelay, which is the value that this + bridge and all others would start using if/when this + bridge were to become the root.]" + REFERENCE + "IEEE 802.1D-1998: clause 8.5.3.6" + ::= { dot1dStp 11 } + +dot1dStpBridgeMaxAge OBJECT-TYPE + SYNTAX Timeout (600..4000) + UNITS "centi-seconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The value that all bridges use for MaxAge when this + bridge is acting as the root. Note that 802.1D-1998 + specifies that the range for this parameter is related + to the value of dot1dStpBridgeHelloTime. The + granularity of this timer is specified by 802.1D-1998 to + be 1 second. An agent may return a badValue error if a + set is attempted to a value that is not a whole number + of seconds." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.3.8" + ::= { dot1dStp 12 } + +dot1dStpBridgeHelloTime OBJECT-TYPE + SYNTAX Timeout (100..1000) + UNITS "centi-seconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The value that all bridges use for HelloTime when this + bridge is acting as the root. The granularity of this + timer is specified by 802.1D-1998 to be 1 second. An + agent may return a badValue error if a set is attempted + + to a value that is not a whole number of seconds." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.3.9" + ::= { dot1dStp 13 } + +dot1dStpBridgeForwardDelay OBJECT-TYPE + SYNTAX Timeout (400..3000) + UNITS "centi-seconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The value that all bridges use for ForwardDelay when + this bridge is acting as the root. Note that + 802.1D-1998 specifies that the range for this parameter + is related to the value of dot1dStpBridgeMaxAge. The + granularity of this timer is specified by 802.1D-1998 to + be 1 second. An agent may return a badValue error if a + set is attempted to a value that is not a whole number + of seconds." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.3.10" + ::= { dot1dStp 14 } + +-- ---------------------------------------------------------- -- +-- The Spanning Tree Port Table +-- ---------------------------------------------------------- -- + +dot1dStpPortTable OBJECT-TYPE + SYNTAX SEQUENCE OF Dot1dStpPortEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table that contains port-specific information + for the Spanning Tree Protocol." + ::= { dot1dStp 15 } + +dot1dStpPortEntry OBJECT-TYPE + SYNTAX Dot1dStpPortEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of information maintained by every port about + the Spanning Tree Protocol state for that port." + INDEX { dot1dStpPort } + ::= { dot1dStpPortTable 1 } + +Dot1dStpPortEntry ::= + SEQUENCE { + + dot1dStpPort + Integer32, + dot1dStpPortPriority + Integer32, + dot1dStpPortState + INTEGER, + dot1dStpPortEnable + INTEGER, + dot1dStpPortPathCost + Integer32, + dot1dStpPortDesignatedRoot + BridgeId, + dot1dStpPortDesignatedCost + Integer32, + dot1dStpPortDesignatedBridge + BridgeId, + dot1dStpPortDesignatedPort + OCTET STRING, + dot1dStpPortForwardTransitions + Counter32, + dot1dStpPortPathCost32 + Integer32 + } + +dot1dStpPort OBJECT-TYPE + SYNTAX Integer32 (1..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The port number of the port for which this entry + contains Spanning Tree Protocol management information." + REFERENCE + "IEEE 802.1D-1998: clause 14.8.2.1.2" + ::= { dot1dStpPortEntry 1 } + +dot1dStpPortPriority OBJECT-TYPE + SYNTAX Integer32 (0..255) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The value of the priority field that is contained in + the first (in network byte order) octet of the (2 octet + long) Port ID. The other octet of the Port ID is given + by the value of dot1dStpPort. + On bridges supporting IEEE 802.1t or IEEE 802.1w, + permissible values are 0-240, in steps of 16." + REFERENCE + "IEEE 802.1D-1998 clause 8.10.2, Table 8-4, + IEEE 802.1t clause 8.10.2, Table 8-4, clause 14.3." + ::= { dot1dStpPortEntry 2 } + +dot1dStpPortState OBJECT-TYPE + SYNTAX INTEGER { + disabled(1), + blocking(2), + listening(3), + learning(4), + forwarding(5), + broken(6) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The port's current state, as defined by application of + the Spanning Tree Protocol. This state controls what + action a port takes on reception of a frame. If the + bridge has detected a port that is malfunctioning, it + will place that port into the broken(6) state. For + ports that are disabled (see dot1dStpPortEnable), this + object will have a value of disabled(1)." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.5.2" + ::= { dot1dStpPortEntry 3 } + +dot1dStpPortEnable OBJECT-TYPE + SYNTAX INTEGER { + enabled(1), + disabled(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The enabled/disabled status of the port." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.5.2" + ::= { dot1dStpPortEntry 4 } + +dot1dStpPortPathCost OBJECT-TYPE + SYNTAX Integer32 (1..65535) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The contribution of this port to the path cost of + paths towards the spanning tree root which include + this port. 802.1D-1998 recommends that the default + value of this parameter be in inverse proportion to + + the speed of the attached LAN. + + New implementations should support dot1dStpPortPathCost32. + If the port path costs exceeds the maximum value of this + object then this object should report the maximum value, + namely 65535. Applications should try to read the + dot1dStpPortPathCost32 object if this object reports + the maximum value." + REFERENCE "IEEE 802.1D-1998: clause 8.5.5.3" + ::= { dot1dStpPortEntry 5 } + +dot1dStpPortDesignatedRoot OBJECT-TYPE + SYNTAX BridgeId + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The unique Bridge Identifier of the Bridge + recorded as the Root in the Configuration BPDUs + transmitted by the Designated Bridge for the + segment to which the port is attached." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.5.4" + ::= { dot1dStpPortEntry 6 } + +dot1dStpPortDesignatedCost OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The path cost of the Designated Port of the segment + connected to this port. This value is compared to the + Root Path Cost field in received bridge PDUs." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.5.5" + ::= { dot1dStpPortEntry 7 } + +dot1dStpPortDesignatedBridge OBJECT-TYPE + SYNTAX BridgeId + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Bridge Identifier of the bridge that this + port considers to be the Designated Bridge for + this port's segment." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.5.6" + ::= { dot1dStpPortEntry 8 } + +dot1dStpPortDesignatedPort OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (2)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Port Identifier of the port on the Designated + Bridge for this port's segment." + REFERENCE + "IEEE 802.1D-1998: clause 8.5.5.7" + ::= { dot1dStpPortEntry 9 } + +dot1dStpPortForwardTransitions OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times this port has transitioned + from the Learning state to the Forwarding state." + ::= { dot1dStpPortEntry 10 } + +dot1dStpPortPathCost32 OBJECT-TYPE + SYNTAX Integer32 (1..200000000) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The contribution of this port to the path cost of + paths towards the spanning tree root which include + this port. 802.1D-1998 recommends that the default + value of this parameter be in inverse proportion to + the speed of the attached LAN. + + This object replaces dot1dStpPortPathCost to support + IEEE 802.1t." + REFERENCE + "IEEE 802.1t clause 8.10.2, Table 8-5." + ::= { dot1dStpPortEntry 11 } + +-- ---------------------------------------------------------- -- +-- the dot1dTp subtree +-- ---------------------------------------------------------- -- +-- Implementation of the dot1dTp subtree is optional. It is +-- implemented by those bridges that support the transparent +-- bridging mode. A transparent or SRT bridge will implement +-- this subtree. +-- ---------------------------------------------------------- -- + +dot1dTpLearnedEntryDiscards OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Forwarding Database entries that + have been or would have been learned, but have been + discarded due to a lack of storage space in the + Forwarding Database. If this counter is increasing, it + indicates that the Forwarding Database is regularly + becoming full (a condition that has unpleasant + performance effects on the subnetwork). If this counter + has a significant value but is not presently increasing, + it indicates that the problem has been occurring but is + not persistent." + REFERENCE + "IEEE 802.1D-1998: clause 14.7.1.1.3" + ::= { dot1dTp 1 } + +dot1dTpAgingTime OBJECT-TYPE + SYNTAX Integer32 (10..1000000) + UNITS "seconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The timeout period in seconds for aging out + dynamically-learned forwarding information. + 802.1D-1998 recommends a default of 300 seconds." + REFERENCE + "IEEE 802.1D-1998: clause 14.7.1.1.3" + ::= { dot1dTp 2 } + +-- ---------------------------------------------------------- -- +-- The Forwarding Database for Transparent Bridges +-- ---------------------------------------------------------- -- + +dot1dTpFdbTable OBJECT-TYPE + SYNTAX SEQUENCE OF Dot1dTpFdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table that contains information about unicast + entries for which the bridge has forwarding and/or + filtering information. This information is used + by the transparent bridging function in + determining how to propagate a received frame." + ::= { dot1dTp 3 } + +dot1dTpFdbEntry OBJECT-TYPE + SYNTAX Dot1dTpFdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information about a specific unicast MAC address + for which the bridge has some forwarding and/or + filtering information." + INDEX { dot1dTpFdbAddress } + ::= { dot1dTpFdbTable 1 } + +Dot1dTpFdbEntry ::= + SEQUENCE { + dot1dTpFdbAddress + MacAddress, + dot1dTpFdbPort + Integer32, + dot1dTpFdbStatus + INTEGER + } + +dot1dTpFdbAddress OBJECT-TYPE + SYNTAX MacAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A unicast MAC address for which the bridge has + forwarding and/or filtering information." + REFERENCE + "IEEE 802.1D-1998: clause 7.9.1, 7.9.2" + ::= { dot1dTpFdbEntry 1 } + +dot1dTpFdbPort OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Either the value '0', or the port number of the port on + which a frame having a source address equal to the value + of the corresponding instance of dot1dTpFdbAddress has + been seen. A value of '0' indicates that the port + number has not been learned, but that the bridge does + have some forwarding/filtering information about this + address (e.g., in the dot1dStaticTable). Implementors + are encouraged to assign the port value to this object + whenever it is learned, even for addresses for which the + corresponding value of dot1dTpFdbStatus is not + learned(3)." + ::= { dot1dTpFdbEntry 2 } + +dot1dTpFdbStatus OBJECT-TYPE + SYNTAX INTEGER { + other(1), + invalid(2), + learned(3), + self(4), + mgmt(5) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The status of this entry. The meanings of the + values are: + other(1) - none of the following. This would + include the case where some other MIB object + (not the corresponding instance of + dot1dTpFdbPort, nor an entry in the + dot1dStaticTable) is being used to determine if + and how frames addressed to the value of the + corresponding instance of dot1dTpFdbAddress are + being forwarded. + invalid(2) - this entry is no longer valid (e.g., + it was learned but has since aged out), but has + not yet been flushed from the table. + learned(3) - the value of the corresponding instance + of dot1dTpFdbPort was learned, and is being + used. + self(4) - the value of the corresponding instance of + dot1dTpFdbAddress represents one of the bridge's + addresses. The corresponding instance of + dot1dTpFdbPort indicates which of the bridge's + ports has this address. + mgmt(5) - the value of the corresponding instance of + dot1dTpFdbAddress is also the value of an + existing instance of dot1dStaticAddress." + ::= { dot1dTpFdbEntry 3 } + +-- ---------------------------------------------------------- -- +-- Port Table for Transparent Bridges +-- ---------------------------------------------------------- -- + +dot1dTpPortTable OBJECT-TYPE + SYNTAX SEQUENCE OF Dot1dTpPortEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table that contains information about every port that + is associated with this transparent bridge." + ::= { dot1dTp 4 } + +dot1dTpPortEntry OBJECT-TYPE + SYNTAX Dot1dTpPortEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of information for each port of a transparent + bridge." + INDEX { dot1dTpPort } + ::= { dot1dTpPortTable 1 } + +Dot1dTpPortEntry ::= + SEQUENCE { + dot1dTpPort + Integer32, + dot1dTpPortMaxInfo + Integer32, + dot1dTpPortInFrames + Counter32, + dot1dTpPortOutFrames + Counter32, + dot1dTpPortInDiscards + Counter32 + } + +dot1dTpPort OBJECT-TYPE + SYNTAX Integer32 (1..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The port number of the port for which this entry + contains Transparent bridging management information." + ::= { dot1dTpPortEntry 1 } + +-- It would be nice if we could use ifMtu as the size of the +-- largest INFO field, but we can't because ifMtu is defined +-- to be the size that the (inter-)network layer can use, which +-- can differ from the MAC layer (especially if several layers +-- of encapsulation are used). + +dot1dTpPortMaxInfo OBJECT-TYPE + SYNTAX Integer32 + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The maximum size of the INFO (non-MAC) field that + + this port will receive or transmit." + ::= { dot1dTpPortEntry 2 } + +dot1dTpPortInFrames OBJECT-TYPE + SYNTAX Counter32 + UNITS "frames" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of frames that have been received by this + port from its segment. Note that a frame received on the + interface corresponding to this port is only counted by + this object if and only if it is for a protocol being + processed by the local bridging function, including + bridge management frames." + REFERENCE + "IEEE 802.1D-1998: clause 14.6.1.1.3" + ::= { dot1dTpPortEntry 3 } + +dot1dTpPortOutFrames OBJECT-TYPE + SYNTAX Counter32 + UNITS "frames" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of frames that have been transmitted by this + port to its segment. Note that a frame transmitted on + the interface corresponding to this port is only counted + by this object if and only if it is for a protocol being + processed by the local bridging function, including + bridge management frames." + REFERENCE + "IEEE 802.1D-1998: clause 14.6.1.1.3" + ::= { dot1dTpPortEntry 4 } + +dot1dTpPortInDiscards OBJECT-TYPE + SYNTAX Counter32 + UNITS "frames" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Count of received valid frames that were discarded + (i.e., filtered) by the Forwarding Process." + REFERENCE + "IEEE 802.1D-1998: clause 14.6.1.1.3" + ::= { dot1dTpPortEntry 5 } + +-- ---------------------------------------------------------- -- + +-- The Static (Destination-Address Filtering) Database +-- ---------------------------------------------------------- -- +-- Implementation of this subtree is optional. +-- ---------------------------------------------------------- -- + +dot1dStaticTable OBJECT-TYPE + SYNTAX SEQUENCE OF Dot1dStaticEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table containing filtering information configured + into the bridge by (local or network) management + specifying the set of ports to which frames received + from specific ports and containing specific destination + addresses are allowed to be forwarded. The value of + zero in this table, as the port number from which frames + with a specific destination address are received, is + used to specify all ports for which there is no specific + entry in this table for that particular destination + address. Entries are valid for unicast and for + group/broadcast addresses." + REFERENCE + "IEEE 802.1D-1998: clause 14.7.2" + ::= { dot1dStatic 1 } + +dot1dStaticEntry OBJECT-TYPE + SYNTAX Dot1dStaticEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Filtering information configured into the bridge by + (local or network) management specifying the set of + ports to which frames received from a specific port and + containing a specific destination address are allowed to + be forwarded." + REFERENCE + "IEEE 802.1D-1998: clause 14.7.2" + INDEX { dot1dStaticAddress, dot1dStaticReceivePort } + ::= { dot1dStaticTable 1 } + +Dot1dStaticEntry ::= + SEQUENCE { + dot1dStaticAddress MacAddress, + dot1dStaticReceivePort Integer32, + dot1dStaticAllowedToGoTo OCTET STRING, + dot1dStaticStatus INTEGER + } + +dot1dStaticAddress OBJECT-TYPE + SYNTAX MacAddress + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The destination MAC address in a frame to which this + entry's filtering information applies. This object can + take the value of a unicast address, a group address, or + the broadcast address." + REFERENCE + "IEEE 802.1D-1998: clause 7.9.1, 7.9.2" + ::= { dot1dStaticEntry 1 } + +dot1dStaticReceivePort OBJECT-TYPE + SYNTAX Integer32 (0..65535) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Either the value '0', or the port number of the port + from which a frame must be received in order for this + entry's filtering information to apply. A value of zero + indicates that this entry applies on all ports of the + bridge for which there is no other applicable entry." + ::= { dot1dStaticEntry 2 } + +dot1dStaticAllowedToGoTo OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (0..512)) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The set of ports to which frames received from a + specific port and destined for a specific MAC address, + are allowed to be forwarded. Each octet within the + value of this object specifies a set of eight ports, + with the first octet specifying ports 1 through 8, the + second octet specifying ports 9 through 16, etc. Within + each octet, the most significant bit represents the + lowest numbered port, and the least significant bit + represents the highest numbered port. Thus, each port + of the bridge is represented by a single bit within the + value of this object. If that bit has a value of '1', + then that port is included in the set of ports; the port + is not included if its bit has a value of '0'. (Note + that the setting of the bit corresponding to the port + from which a frame is received is irrelevant.) The + default value of this object is a string of ones of + appropriate length. + + The value of this object may exceed the required minimum + maximum message size of some SNMP transport (484 bytes, + in the case of SNMP over UDP, see RFC 3417, section 3.2). + SNMP engines on bridges supporting a large number of + ports must support appropriate maximum message sizes." + ::= { dot1dStaticEntry 3 } + +dot1dStaticStatus OBJECT-TYPE + SYNTAX INTEGER { + other(1), + invalid(2), + permanent(3), + deleteOnReset(4), + deleteOnTimeout(5) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This object indicates the status of this entry. + The default value is permanent(3). + other(1) - this entry is currently in use but the + conditions under which it will remain so are + different from each of the following values. + invalid(2) - writing this value to the object + removes the corresponding entry. + permanent(3) - this entry is currently in use and + will remain so after the next reset of the + bridge. + deleteOnReset(4) - this entry is currently in use + and will remain so until the next reset of the + bridge. + deleteOnTimeout(5) - this entry is currently in use + and will remain so until it is aged out." + ::= { dot1dStaticEntry 4 } + +-- ---------------------------------------------------------- -- +-- Notifications for use by Bridges +-- ---------------------------------------------------------- -- +-- Notifications for the Spanning Tree Protocol +-- ---------------------------------------------------------- -- + +newRoot NOTIFICATION-TYPE + -- OBJECTS { } + STATUS current + DESCRIPTION + "The newRoot trap indicates that the sending agent has + become the new root of the Spanning Tree; the trap is + sent by a bridge soon after its election as the new + + root, e.g., upon expiration of the Topology Change Timer, + immediately subsequent to its election. Implementation + of this trap is optional." + ::= { dot1dNotifications 1 } + +topologyChange NOTIFICATION-TYPE + -- OBJECTS { } + STATUS current + DESCRIPTION + "A topologyChange trap is sent by a bridge when any of + its configured ports transitions from the Learning state + to the Forwarding state, or from the Forwarding state to + the Blocking state. The trap is not sent if a newRoot + trap is sent for the same transition. Implementation of + this trap is optional." + ::= { dot1dNotifications 2 } + +-- ---------------------------------------------------------- -- +-- IEEE 802.1D MIB - Conformance Information +-- ---------------------------------------------------------- -- + +dot1dGroups OBJECT IDENTIFIER ::= { dot1dConformance 1 } +dot1dCompliances OBJECT IDENTIFIER ::= { dot1dConformance 2 } + +-- ---------------------------------------------------------- -- +-- units of conformance +-- ---------------------------------------------------------- -- + +-- ---------------------------------------------------------- -- +-- the dot1dBase group +-- ---------------------------------------------------------- -- + +dot1dBaseBridgeGroup OBJECT-GROUP + OBJECTS { + dot1dBaseBridgeAddress, + dot1dBaseNumPorts, + dot1dBaseType + } + STATUS current + DESCRIPTION + "Bridge level information for this device." + ::= { dot1dGroups 1 } + +dot1dBasePortGroup OBJECT-GROUP + OBJECTS { + dot1dBasePort, + dot1dBasePortIfIndex, + dot1dBasePortCircuit, + dot1dBasePortDelayExceededDiscards, + dot1dBasePortMtuExceededDiscards + } + STATUS current + DESCRIPTION + "Information for each port on this device." + ::= { dot1dGroups 2 } + +-- ---------------------------------------------------------- -- +-- the dot1dStp group +-- ---------------------------------------------------------- -- + +dot1dStpBridgeGroup OBJECT-GROUP + OBJECTS { + dot1dStpProtocolSpecification, + dot1dStpPriority, + dot1dStpTimeSinceTopologyChange, + dot1dStpTopChanges, + dot1dStpDesignatedRoot, + dot1dStpRootCost, + dot1dStpRootPort, + dot1dStpMaxAge, + dot1dStpHelloTime, + dot1dStpHoldTime, + dot1dStpForwardDelay, + dot1dStpBridgeMaxAge, + dot1dStpBridgeHelloTime, + dot1dStpBridgeForwardDelay + } + STATUS current + DESCRIPTION + "Bridge level Spanning Tree data for this device." + ::= { dot1dGroups 3 } + +dot1dStpPortGroup OBJECT-GROUP + OBJECTS { + dot1dStpPort, + dot1dStpPortPriority, + dot1dStpPortState, + dot1dStpPortEnable, + dot1dStpPortPathCost, + dot1dStpPortDesignatedRoot, + dot1dStpPortDesignatedCost, + dot1dStpPortDesignatedBridge, + dot1dStpPortDesignatedPort, + dot1dStpPortForwardTransitions + } + STATUS current + DESCRIPTION + "Spanning Tree data for each port on this device." + ::= { dot1dGroups 4 } + +dot1dStpPortGroup2 OBJECT-GROUP + OBJECTS { + dot1dStpPort, + dot1dStpPortPriority, + dot1dStpPortState, + dot1dStpPortEnable, + dot1dStpPortDesignatedRoot, + dot1dStpPortDesignatedCost, + dot1dStpPortDesignatedBridge, + dot1dStpPortDesignatedPort, + dot1dStpPortForwardTransitions, + dot1dStpPortPathCost32 + } + STATUS current + DESCRIPTION + "Spanning Tree data for each port on this device." + ::= { dot1dGroups 5 } + +dot1dStpPortGroup3 OBJECT-GROUP + OBJECTS { + dot1dStpPortPathCost32 + } + STATUS current + DESCRIPTION + "Spanning Tree data for devices supporting 32-bit + path costs." + ::= { dot1dGroups 6 } + +-- ---------------------------------------------------------- -- +-- the dot1dTp group +-- ---------------------------------------------------------- -- + +dot1dTpBridgeGroup OBJECT-GROUP + OBJECTS { + dot1dTpLearnedEntryDiscards, + dot1dTpAgingTime + } + STATUS current + DESCRIPTION + "Bridge level Transparent Bridging data." + ::= { dot1dGroups 7 } + +dot1dTpFdbGroup OBJECT-GROUP + OBJECTS { + + dot1dTpFdbAddress, + dot1dTpFdbPort, + dot1dTpFdbStatus + } + STATUS current + DESCRIPTION + "Filtering Database information for the Bridge." + ::= { dot1dGroups 8 } + +dot1dTpGroup OBJECT-GROUP + OBJECTS { + dot1dTpPort, + dot1dTpPortMaxInfo, + dot1dTpPortInFrames, + dot1dTpPortOutFrames, + dot1dTpPortInDiscards + } + STATUS current + DESCRIPTION + "Dynamic Filtering Database information for each port of + the Bridge." + ::= { dot1dGroups 9 } + +-- ---------------------------------------------------------- -- +-- The Static (Destination-Address Filtering) Database +-- ---------------------------------------------------------- -- + +dot1dStaticGroup OBJECT-GROUP + OBJECTS { + dot1dStaticAddress, + dot1dStaticReceivePort, + dot1dStaticAllowedToGoTo, + dot1dStaticStatus + } + STATUS current + DESCRIPTION + "Static Filtering Database information for each port of + the Bridge." + ::= { dot1dGroups 10 } + +-- ---------------------------------------------------------- -- +-- The Trap Notification Group +-- ---------------------------------------------------------- -- + +dot1dNotificationGroup NOTIFICATION-GROUP + NOTIFICATIONS { + newRoot, + topologyChange + } + STATUS current + DESCRIPTION + "Group of objects describing notifications (traps)." + ::= { dot1dGroups 11 } + +-- ---------------------------------------------------------- -- +-- compliance statements +-- ---------------------------------------------------------- -- + +bridgeCompliance1493 MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for device support of bridging + services, as per RFC1493." + + MODULE + MANDATORY-GROUPS { + dot1dBaseBridgeGroup, + dot1dBasePortGroup + } + + GROUP dot1dStpBridgeGroup + DESCRIPTION + "Implementation of this group is mandatory for bridges + that support the Spanning Tree Protocol." + + GROUP dot1dStpPortGroup + DESCRIPTION + "Implementation of this group is mandatory for bridges + that support the Spanning Tree Protocol." + + GROUP dot1dTpBridgeGroup + DESCRIPTION + "Implementation of this group is mandatory for bridges + that support the transparent bridging mode. A + transparent or SRT bridge will implement this group." + + GROUP dot1dTpFdbGroup + DESCRIPTION + "Implementation of this group is mandatory for bridges + that support the transparent bridging mode. A + transparent or SRT bridge will implement this group." + + GROUP dot1dTpGroup + DESCRIPTION + "Implementation of this group is mandatory for bridges + + that support the transparent bridging mode. A + transparent or SRT bridge will implement this group." + + GROUP dot1dStaticGroup + DESCRIPTION + "Implementation of this group is optional." + + GROUP dot1dNotificationGroup + DESCRIPTION + "Implementation of this group is optional." + ::= { dot1dCompliances 1 } + +bridgeCompliance4188 MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for device support of bridging + services. This supports 32-bit Path Cost values and the + more restricted bridge and port priorities, as per IEEE + 802.1t. + + Full support for the 802.1D management objects requires that + the SNMPv2-MIB [RFC3418] objects sysDescr, and sysUpTime, as + well as the IF-MIB [RFC2863] objects ifIndex, ifType, + ifDescr, ifPhysAddress, and ifLastChange are implemented." + + MODULE + MANDATORY-GROUPS { + dot1dBaseBridgeGroup, + dot1dBasePortGroup + } + + GROUP dot1dStpBridgeGroup + DESCRIPTION + "Implementation of this group is mandatory for + bridges that support the Spanning Tree Protocol." + + OBJECT dot1dStpPriority + SYNTAX Integer32 (0|4096|8192|12288|16384|20480|24576 + |28672|32768|36864|40960|45056|49152 + |53248|57344|61440) + DESCRIPTION + "The possible values defined by IEEE 802.1t." + + GROUP dot1dStpPortGroup2 + DESCRIPTION + "Implementation of this group is mandatory for + bridges that support the Spanning Tree Protocol." + + GROUP dot1dStpPortGroup3 + DESCRIPTION + "Implementation of this group is mandatory for bridges + that support the Spanning Tree Protocol and 32-bit path + costs. In particular, this includes devices supporting + IEEE 802.1t and IEEE 802.1w." + + OBJECT dot1dStpPortPriority + SYNTAX Integer32 (0|16|32|48|64|80|96|112|128 + |144|160|176|192|208|224|240) + DESCRIPTION + "The possible values defined by IEEE 802.1t." + + GROUP dot1dTpBridgeGroup + DESCRIPTION + "Implementation of this group is mandatory for + bridges that support the transparent bridging + mode. A transparent or SRT bridge will implement + this group." + + GROUP dot1dTpFdbGroup + DESCRIPTION + "Implementation of this group is mandatory for + bridges that support the transparent bridging + mode. A transparent or SRT bridge will implement + this group." + + GROUP dot1dTpGroup + DESCRIPTION + "Implementation of this group is mandatory for + bridges that support the transparent bridging + mode. A transparent or SRT bridge will implement + this group." + + GROUP dot1dStaticGroup + DESCRIPTION + "Implementation of this group is optional." + + GROUP dot1dNotificationGroup + DESCRIPTION + "Implementation of this group is optional." + ::= { dot1dCompliances 2 } + +END diff --git a/internal/snmp/testdata/gosmi/bridgeMibImports b/internal/snmp/testdata/gosmi/bridgeMibImports new file mode 100644 index 0000000..8f6a52b --- /dev/null +++ b/internal/snmp/testdata/gosmi/bridgeMibImports @@ -0,0 +1,554 @@ +SNMPv2-SMI DEFINITIONS ::= BEGIN + +-- the path to the root + +org OBJECT IDENTIFIER ::= { iso 3 } -- "iso" = 1 +dod OBJECT IDENTIFIER ::= { org 6 } +internet OBJECT IDENTIFIER ::= { dod 1 } + +directory OBJECT IDENTIFIER ::= { internet 1 } + +mgmt OBJECT IDENTIFIER ::= { internet 2 } +mib-2 OBJECT IDENTIFIER ::= { mgmt 1 } +transmission OBJECT IDENTIFIER ::= { mib-2 10 } + +experimental OBJECT IDENTIFIER ::= { internet 3 } + +private OBJECT IDENTIFIER ::= { internet 4 } +enterprises OBJECT IDENTIFIER ::= { private 1 } + +security OBJECT IDENTIFIER ::= { internet 5 } + +snmpV2 OBJECT IDENTIFIER ::= { internet 6 } + +-- transport domains +snmpDomains OBJECT IDENTIFIER ::= { snmpV2 1 } + +-- transport proxies +snmpProxys OBJECT IDENTIFIER ::= { snmpV2 2 } + +-- module identities +snmpModules OBJECT IDENTIFIER ::= { snmpV2 3 } + +-- Extended UTCTime, to allow dates with four-digit years +-- (Note that this definition of ExtUTCTime is not to be IMPORTed +-- by MIB modules.) +ExtUTCTime ::= OCTET STRING(SIZE(11 | 13)) + -- format is YYMMDDHHMMZ or YYYYMMDDHHMMZ + + -- where: YY - last two digits of year (only years + -- between 1900-1999) + -- YYYY - last four digits of the year (any year) + -- MM - month (01 through 12) + -- DD - day of month (01 through 31) + -- HH - hours (00 through 23) + -- MM - minutes (00 through 59) + -- Z - denotes GMT (the ASCII character Z) + -- + -- For example, "9502192015Z" and "199502192015Z" represent + -- 8:15pm GMT on 19 February 1995. Years after 1999 must use + -- the four digit year format. Years 1900-1999 may use the + -- two or four digit format. + +-- definitions for information modules + +MODULE-IDENTITY MACRO ::= +BEGIN + TYPE NOTATION ::= + "LAST-UPDATED" value(Update ExtUTCTime) + "ORGANIZATION" Text + "CONTACT-INFO" Text + "DESCRIPTION" Text + RevisionPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + RevisionPart ::= + Revisions + | empty + Revisions ::= + Revision + | Revisions Revision + Revision ::= + "REVISION" value(Update ExtUTCTime) + "DESCRIPTION" Text + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +OBJECT-IDENTITY MACRO ::= +BEGIN + TYPE NOTATION ::= + "STATUS" Status + "DESCRIPTION" Text + + ReferPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +-- names of objects +-- (Note that these definitions of ObjectName and NotificationName +-- are not to be IMPORTed by MIB modules.) + +ObjectName ::= + OBJECT IDENTIFIER + +NotificationName ::= + OBJECT IDENTIFIER + +-- syntax of objects + +-- the "base types" defined here are: +-- 3 built-in ASN.1 types: INTEGER, OCTET STRING, OBJECT IDENTIFIER +-- 8 application-defined types: Integer32, IpAddress, Counter32, +-- Gauge32, Unsigned32, TimeTicks, Opaque, and Counter64 + +ObjectSyntax ::= + CHOICE { + simple + SimpleSyntax, + -- note that SEQUENCEs for conceptual tables and + -- rows are not mentioned here... + + application-wide + ApplicationSyntax + } + +-- built-in ASN.1 types + +SimpleSyntax ::= + CHOICE { + -- INTEGERs with a more restrictive range + -- may also be used + integer-value -- includes Integer32 + INTEGER (-2147483648..2147483647), + -- OCTET STRINGs with a more restrictive size + -- may also be used + string-value + OCTET STRING (SIZE (0..65535)), + objectID-value + OBJECT IDENTIFIER + } + +-- indistinguishable from INTEGER, but never needs more than +-- 32-bits for a two's complement representation +Integer32 ::= + INTEGER (-2147483648..2147483647) + +-- application-wide types + +ApplicationSyntax ::= + CHOICE { + ipAddress-value + IpAddress, + counter-value + Counter32, + timeticks-value + TimeTicks, + arbitrary-value + Opaque, + big-counter-value + Counter64, + unsigned-integer-value -- includes Gauge32 + Unsigned32 + } + +-- in network-byte order + +-- (this is a tagged type for historical reasons) +IpAddress ::= + [APPLICATION 0] + IMPLICIT OCTET STRING (SIZE (4)) + +-- this wraps +Counter32 ::= + [APPLICATION 1] + IMPLICIT INTEGER (0..4294967295) + +-- this doesn't wrap +Gauge32 ::= + [APPLICATION 2] + IMPLICIT INTEGER (0..4294967295) + +-- an unsigned 32-bit quantity +-- indistinguishable from Gauge32 +Unsigned32 ::= + [APPLICATION 2] + IMPLICIT INTEGER (0..4294967295) + +-- hundredths of seconds since an epoch +TimeTicks ::= + [APPLICATION 3] + IMPLICIT INTEGER (0..4294967295) + +-- for backward-compatibility only +Opaque ::= + [APPLICATION 4] + IMPLICIT OCTET STRING + +-- for counters that wrap in less than one hour with only 32 bits +Counter64 ::= + [APPLICATION 6] + IMPLICIT INTEGER (0..18446744073709551615) + +-- definition for objects + +OBJECT-TYPE MACRO ::= +BEGIN + TYPE NOTATION ::= + "SYNTAX" Syntax + UnitsPart + "MAX-ACCESS" Access + "STATUS" Status + "DESCRIPTION" Text + ReferPart + + IndexPart + DefValPart + + VALUE NOTATION ::= + value(VALUE ObjectName) + + Syntax ::= -- Must be one of the following: + -- a base type (or its refinement), + -- a textual convention (or its refinement), or + -- a BITS pseudo-type + type + | "BITS" "{" NamedBits "}" + + NamedBits ::= NamedBit + | NamedBits "," NamedBit + + NamedBit ::= identifier "(" number ")" -- number is nonnegative + + UnitsPart ::= + "UNITS" Text + | empty + + Access ::= + "not-accessible" + | "accessible-for-notify" + | "read-only" + | "read-write" + | "read-create" + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + IndexPart ::= + "INDEX" "{" IndexTypes "}" + | "AUGMENTS" "{" Entry "}" + | empty + IndexTypes ::= + IndexType + | IndexTypes "," IndexType + IndexType ::= + "IMPLIED" Index + | Index + + Index ::= + -- use the SYNTAX value of the + -- correspondent OBJECT-TYPE invocation + value(ObjectName) + Entry ::= + -- use the INDEX value of the + -- correspondent OBJECT-TYPE invocation + value(ObjectName) + + DefValPart ::= "DEFVAL" "{" Defvalue "}" + | empty + + Defvalue ::= -- must be valid for the type specified in + -- SYNTAX clause of same OBJECT-TYPE macro + value(ObjectSyntax) + | "{" BitsValue "}" + + BitsValue ::= BitNames + | empty + + BitNames ::= BitName + | BitNames "," BitName + + BitName ::= identifier + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +-- definitions for notifications + +NOTIFICATION-TYPE MACRO ::= +BEGIN + TYPE NOTATION ::= + ObjectsPart + "STATUS" Status + "DESCRIPTION" Text + ReferPart + + VALUE NOTATION ::= + value(VALUE NotificationName) + + ObjectsPart ::= + "OBJECTS" "{" Objects "}" + | empty + Objects ::= + Object + + | Objects "," Object + Object ::= + value(ObjectName) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +-- definitions of administrative identifiers + +zeroDotZero OBJECT-IDENTITY + STATUS current + DESCRIPTION + "A value used for null identifiers." + ::= { 0 0 } + + + +TEXTUAL-CONVENTION MACRO ::= + +BEGIN + TYPE NOTATION ::= + DisplayPart + "STATUS" Status + "DESCRIPTION" Text + ReferPart + "SYNTAX" Syntax + + VALUE NOTATION ::= + value(VALUE Syntax) -- adapted ASN.1 + + DisplayPart ::= + "DISPLAY-HINT" Text + | empty + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in [2] + Text ::= value(IA5String) + + Syntax ::= -- Must be one of the following: + -- a base type (or its refinement), or + -- a BITS pseudo-type + type + | "BITS" "{" NamedBits "}" + + NamedBits ::= NamedBit + | NamedBits "," NamedBit + + NamedBit ::= identifier "(" number ")" -- number is nonnegative + +END + +MODULE-COMPLIANCE MACRO ::= +BEGIN + TYPE NOTATION ::= + "STATUS" Status + "DESCRIPTION" Text + ReferPart + ModulePart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + ModulePart ::= + Modules + Modules ::= + Module + | Modules Module + Module ::= + -- name of module -- + "MODULE" ModuleName + MandatoryPart + CompliancePart + + ModuleName ::= + -- identifier must start with uppercase letter + identifier ModuleIdentifier + -- must not be empty unless contained + -- in MIB Module + | empty + ModuleIdentifier ::= + value(OBJECT IDENTIFIER) + | empty + + MandatoryPart ::= + "MANDATORY-GROUPS" "{" Groups "}" + | empty + + Groups ::= + + Group + | Groups "," Group + Group ::= + value(OBJECT IDENTIFIER) + + CompliancePart ::= + Compliances + | empty + + Compliances ::= + Compliance + | Compliances Compliance + Compliance ::= + ComplianceGroup + | Object + + ComplianceGroup ::= + "GROUP" value(OBJECT IDENTIFIER) + "DESCRIPTION" Text + + Object ::= + "OBJECT" value(ObjectName) + SyntaxPart + WriteSyntaxPart + AccessPart + "DESCRIPTION" Text + + -- must be a refinement for object's SYNTAX clause + SyntaxPart ::= "SYNTAX" Syntax + | empty + + -- must be a refinement for object's SYNTAX clause + WriteSyntaxPart ::= "WRITE-SYNTAX" Syntax + | empty + + Syntax ::= -- Must be one of the following: + -- a base type (or its refinement), + -- a textual convention (or its refinement), or + -- a BITS pseudo-type + type + | "BITS" "{" NamedBits "}" + + NamedBits ::= NamedBit + | NamedBits "," NamedBit + + NamedBit ::= identifier "(" number ")" -- number is nonnegative + + AccessPart ::= + "MIN-ACCESS" Access + | empty + Access ::= + "not-accessible" + | "accessible-for-notify" + | "read-only" + | "read-write" + | "read-create" + + -- a character string as defined in [2] + Text ::= value(IA5String) +END + +OBJECT-GROUP MACRO ::= +BEGIN + TYPE NOTATION ::= + ObjectsPart + "STATUS" Status + "DESCRIPTION" Text + ReferPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + ObjectsPart ::= + "OBJECTS" "{" Objects "}" + Objects ::= + Object + | Objects "," Object + Object ::= + + value(ObjectName) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in [2] + Text ::= value(IA5String) +END + +InterfaceIndex ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "A unique value, greater than zero, for each interface or + interface sub-layer in the managed system. It is + recommended that values are assigned contiguously starting + from 1. The value for each interface sub-layer must remain + constant at least from one re-initialization of the entity's + network management system to the next re-initialization." + SYNTAX Integer32 (1..2147483647) + + + +MacAddress ::= TEXTUAL-CONVENTION + DISPLAY-HINT "1x:" + STATUS current + DESCRIPTION + "Represents an 802 MAC address represented in the + `canonical' order defined by IEEE 802.1a, i.e., as if it + were transmitted least significant bit first, even though + 802.5 (in contrast to other 802.x protocols) requires MAC + addresses to be transmitted most significant bit first." + SYNTAX OCTET STRING (SIZE (6)) + +END \ No newline at end of file diff --git a/internal/snmp/testdata/gosmi/foo b/internal/snmp/testdata/gosmi/foo new file mode 100644 index 0000000..4e9bf7f --- /dev/null +++ b/internal/snmp/testdata/gosmi/foo @@ -0,0 +1,30 @@ +FOOTEST-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Integer32 FROM fooImports; + +fooTestMIB MODULE-IDENTITY + LAST-UPDATED "2021090800Z" + ORGANIZATION "influx" + CONTACT-INFO + "EMail: influx@email.com" + DESCRIPTION + "MIB module for testing snmp plugin + for telegraf + " + ::= { iso 1 } + +fooMIBObjects OBJECT IDENTIFIER ::= { iso 2 } +fooOne OBJECT IDENTIFIER ::= { iso 1 } +six OBJECT IDENTIFIER ::= { fooOne 1 } +three OBJECT IDENTIFIER ::= { six 3 } + +foo OBJECT-TYPE + SYNTAX Integer32 + ACCESS read-only + STATUS current + DESCRIPTION + "foo mib for testing" + ::= { fooMIBObjects 3 } + +END \ No newline at end of file diff --git a/internal/snmp/testdata/gosmi/fooImports b/internal/snmp/testdata/gosmi/fooImports new file mode 100644 index 0000000..6cbed24 --- /dev/null +++ b/internal/snmp/testdata/gosmi/fooImports @@ -0,0 +1,169 @@ +fooImports DEFINITIONS ::= BEGIN + +-- the path to the root + +org OBJECT IDENTIFIER ::= { iso 1 } -- "iso" = 1 +dod OBJECT IDENTIFIER ::= { org 2 } +internet OBJECT IDENTIFIER ::= { dod 3 } + +ExtUTCTime ::= OCTET STRING(SIZE(11 | 13)) + -- format is YYMMDDHHMMZ or YYYYMMDDHHMMZ + + -- where: YY - last two digits of year (only years + -- between 1900-1999) + -- YYYY - last four digits of the year (any year) + -- MM - month (01 through 12) + -- DD - day of month (01 through 31) + -- HH - hours (00 through 23) + -- MM - minutes (00 through 59) + -- Z - denotes GMT (the ASCII character Z) + -- + -- For example, "9502192015Z" and "199502192015Z" represent + -- 8:15pm GMT on 19 February 1995. Years after 1999 must use + -- the four digit year format. Years 1900-1999 may use the + -- two or four digit format. + +-- definitions for information modules + +MODULE-IDENTITY MACRO ::= +BEGIN + TYPE NOTATION ::= + "LAST-UPDATED" value(Update ExtUTCTime) + "ORGANIZATION" Text + "CONTACT-INFO" Text + "DESCRIPTION" Text + RevisionPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + RevisionPart ::= + Revisions + | empty + Revisions ::= + Revision + | Revisions Revision + Revision ::= + "REVISION" value(Update ExtUTCTime) + "DESCRIPTION" Text + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +OBJECT-IDENTITY MACRO ::= +BEGIN + TYPE NOTATION ::= + "STATUS" Status + "DESCRIPTION" Text + + ReferPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +-- names of objects +-- (Note that these definitions of ObjectName and NotificationName +-- are not to be IMPORTed by MIB modules.) + +ObjectName ::= + OBJECT IDENTIFIER + +NotificationName ::= + OBJECT IDENTIFIER + + +-- indistinguishable from INTEGER, but never needs more than +-- 32-bits for a two's complement representation +Integer32 ::= + INTEGER (-2147483648..2147483647) + + + +-- definition for objects + +OBJECT-TYPE MACRO ::= +BEGIN + TYPE NOTATION ::= + UnitsPart + "MAX-ACCESS" Access + "STATUS" Status + "DESCRIPTION" Text + ReferPart + + IndexPart + DefValPart + + VALUE NOTATION ::= + value(VALUE ObjectName) + + NamedBits ::= NamedBit + | NamedBits "," NamedBit + + NamedBit ::= identifier "(" number ")" -- number is nonnegative + + UnitsPart ::= + "UNITS" Text + | empty + + Access ::= + "not-accessible" + | "accessible-for-notify" + | "read-only" + | "read-write" + | "read-create" + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + IndexPart ::= + "INDEX" "{" IndexTypes "}" + | "AUGMENTS" "{" Entry "}" + | empty + IndexTypes ::= + IndexType + | IndexTypes "," IndexType + IndexType ::= + "IMPLIED" Index + | Index + + Entry ::= + -- use the INDEX value of the + -- correspondent OBJECT-TYPE invocation + value(ObjectName) + + DefValPart ::= "DEFVAL" "{" Defvalue "}" + | empty + + BitsValue ::= BitNames + | empty + + BitNames ::= BitName + | BitNames "," BitName + + BitName ::= identifier + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +END \ No newline at end of file diff --git a/internal/snmp/testdata/gosmi/ifPhysAddress b/internal/snmp/testdata/gosmi/ifPhysAddress new file mode 100644 index 0000000..8ac5b5a --- /dev/null +++ b/internal/snmp/testdata/gosmi/ifPhysAddress @@ -0,0 +1,84 @@ +IF-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Integer32, mib-2, + PhysAddress FROM ifPhysAddressImports; + +ifMIB MODULE-IDENTITY + LAST-UPDATED "200006140000Z" + ORGANIZATION "IETF Interfaces MIB Working Group" + CONTACT-INFO + " Keith McCloghrie + Cisco Systems, Inc. + 170 West Tasman Drive + San Jose, CA 95134-1706 + US + + 408-526-5260 + kzm@cisco.com" + DESCRIPTION + "The MIB module to describe generic objects for network + interface sub-layers. This MIB is an updated version of + MIB-II's ifTable, and incorporates the extensions defined in + RFC 1229." + + REVISION "200006140000Z" + DESCRIPTION + "Clarifications agreed upon by the Interfaces MIB WG, and + published as RFC 2863." + REVISION "199602282155Z" + DESCRIPTION + "Revisions made by the Interfaces MIB WG, and published in + RFC 2233." + REVISION "199311082155Z" + DESCRIPTION + "Initial revision, published as part of RFC 1573." + ::= { mib-2 31 } + +ifMIBObjects OBJECT IDENTIFIER ::= { ifMIB 1 } + +interfaces OBJECT IDENTIFIER ::= { mib-2 2 } + + +ifTable OBJECT-TYPE + SYNTAX SEQUENCE OF IfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of interface entries. The number of entries is + given by the value of ifNumber." + ::= { interfaces 2 } + +ifEntry OBJECT-TYPE + SYNTAX IfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry containing management information applicable to a + particular interface." + INDEX { ifIndex } + ::= { ifTable 1 } + + + +ifPhysAddress OBJECT-TYPE + SYNTAX PhysAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The interface's address at the protocol layer + immediately `below' the network layer in the + protocol stack. For interfaces which do not have + such an address (e.g., a serial line), this object + should contain an octet string of zero length." + ::= { ifEntry 6 } + +foo OBJECT-TYPE + SYNTAX Integer32 + ACCESS read-only + STATUS current + DESCRIPTION + "foo mib for testing" + ::= { ifEntry 9 } + +END diff --git a/internal/snmp/testdata/gosmi/ifPhysAddressImports b/internal/snmp/testdata/gosmi/ifPhysAddressImports new file mode 100644 index 0000000..316f665 --- /dev/null +++ b/internal/snmp/testdata/gosmi/ifPhysAddressImports @@ -0,0 +1,254 @@ +SNMPv2-SMI DEFINITIONS ::= BEGIN + +-- the path to the root + +org OBJECT IDENTIFIER ::= { iso 3 } -- "iso" = 1 +dod OBJECT IDENTIFIER ::= { org 6 } +internet OBJECT IDENTIFIER ::= { dod 1 } + +directory OBJECT IDENTIFIER ::= { internet 1 } + +mgmt OBJECT IDENTIFIER ::= { internet 2 } +mib-2 OBJECT IDENTIFIER ::= { mgmt 1 } +transmission OBJECT IDENTIFIER ::= { mib-2 10 } + +experimental OBJECT IDENTIFIER ::= { internet 3 } + +private OBJECT IDENTIFIER ::= { internet 4 } +enterprises OBJECT IDENTIFIER ::= { private 1 } + +security OBJECT IDENTIFIER ::= { internet 5 } + +snmpV2 OBJECT IDENTIFIER ::= { internet 6 } + +-- transport domains +snmpDomains OBJECT IDENTIFIER ::= { snmpV2 1 } + +-- transport proxies +snmpProxys OBJECT IDENTIFIER ::= { snmpV2 2 } + +-- module identities +snmpModules OBJECT IDENTIFIER ::= { snmpV2 3 } + +-- Extended UTCTime, to allow dates with four-digit years +-- (Note that this definition of ExtUTCTime is not to be IMPORTed +-- by MIB modules.) +ExtUTCTime ::= OCTET STRING(SIZE(11 | 13)) + -- format is YYMMDDHHMMZ or YYYYMMDDHHMMZ + + -- where: YY - last two digits of year (only years + -- between 1900-1999) + -- YYYY - last four digits of the year (any year) + -- MM - month (01 through 12) + -- DD - day of month (01 through 31) + -- HH - hours (00 through 23) + -- MM - minutes (00 through 59) + -- Z - denotes GMT (the ASCII character Z) + -- + -- For example, "9502192015Z" and "199502192015Z" represent + -- 8:15pm GMT on 19 February 1995. Years after 1999 must use + -- the four digit year format. Years 1900-1999 may use the + -- two or four digit format. + +-- definitions for information modules + +MODULE-IDENTITY MACRO ::= +BEGIN + TYPE NOTATION ::= + "LAST-UPDATED" value(Update ExtUTCTime) + "ORGANIZATION" Text + "CONTACT-INFO" Text + "DESCRIPTION" Text + RevisionPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + RevisionPart ::= + Revisions + | empty + Revisions ::= + Revision + | Revisions Revision + Revision ::= + "REVISION" value(Update ExtUTCTime) + "DESCRIPTION" Text + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +OBJECT-IDENTITY MACRO ::= +BEGIN + TYPE NOTATION ::= + "STATUS" Status + "DESCRIPTION" Text + + ReferPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +-- names of objects +-- (Note that these definitions of ObjectName and NotificationName +-- are not to be IMPORTed by MIB modules.) + +ObjectName ::= + OBJECT IDENTIFIER + +NotificationName ::= + OBJECT IDENTIFIER + +-- syntax of objects + +-- the "base types" defined here are: +-- 3 built-in ASN.1 types: INTEGER, OCTET STRING, OBJECT IDENTIFIER +-- 8 application-defined types: Integer32, IpAddress, Counter32, +-- Gauge32, Unsigned32, TimeTicks, Opaque, and Counter64 + +ObjectSyntax ::= + CHOICE { + simple + SimpleSyntax, + -- note that SEQUENCEs for conceptual tables and + -- rows are not mentioned here... + + application-wide + ApplicationSyntax + } + +-- built-in ASN.1 types + +SimpleSyntax ::= + CHOICE { + -- INTEGERs with a more restrictive range + -- may also be used + integer-value -- includes Integer32 + INTEGER (-2147483648..2147483647), + -- OCTET STRINGs with a more restrictive size + -- may also be used + string-value + OCTET STRING (SIZE (0..65535)), + objectID-value + OBJECT IDENTIFIER + } + +-- indistinguishable from INTEGER, but never needs more than +-- 32-bits for a two's complement representation +Integer32 ::= + INTEGER (-2147483648..2147483647) + + + +-- definition for objects + +OBJECT-TYPE MACRO ::= +BEGIN + TYPE NOTATION ::= + "SYNTAX" Syntax + UnitsPart + "MAX-ACCESS" Access + "STATUS" Status + "DESCRIPTION" Text + ReferPart + + IndexPart + DefValPart + + VALUE NOTATION ::= + value(VALUE ObjectName) + + Syntax ::= -- Must be one of the following: + -- a base type (or its refinement), + -- a textual convention (or its refinement), or + -- a BITS pseudo-type + type + | "BITS" "{" NamedBits "}" + + NamedBits ::= NamedBit + | NamedBits "," NamedBit + + NamedBit ::= identifier "(" number ")" -- number is nonnegative + + UnitsPart ::= + "UNITS" Text + | empty + + Access ::= + "not-accessible" + | "accessible-for-notify" + | "read-only" + | "read-write" + | "read-create" + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + IndexPart ::= + "INDEX" "{" IndexTypes "}" + | "AUGMENTS" "{" Entry "}" + | empty + IndexTypes ::= + IndexType + | IndexTypes "," IndexType + IndexType ::= + "IMPLIED" Index + | Index + + Index ::= + -- use the SYNTAX value of the + -- correspondent OBJECT-TYPE invocation + value(ObjectName) + Entry ::= + -- use the INDEX value of the + -- correspondent OBJECT-TYPE invocation + value(ObjectName) + + DefValPart ::= "DEFVAL" "{" Defvalue "}" + | empty + + Defvalue ::= -- must be valid for the type specified in + -- SYNTAX clause of same OBJECT-TYPE macro + value(ObjectSyntax) + | "{" BitsValue "}" + + BitsValue ::= BitNames + | empty + + BitNames ::= BitName + | BitNames "," BitName + + BitName ::= identifier + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +PhysAddress ::= TEXTUAL-CONVENTION + DISPLAY-HINT "1x:" + STATUS current + DESCRIPTION + "Represents media- or physical-level addresses." + SYNTAX OCTET STRING + + +END diff --git a/internal/snmp/testdata/gosmi/server b/internal/snmp/testdata/gosmi/server new file mode 100644 index 0000000..a091d7a --- /dev/null +++ b/internal/snmp/testdata/gosmi/server @@ -0,0 +1,98 @@ +TEST DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Integer32 FROM fooImports; + +TestMIB MODULE-IDENTITY + LAST-UPDATED "2021090800Z" + ORGANIZATION "influx" + CONTACT-INFO + "EMail: influx@email.com" + DESCRIPTION + "MIB module for testing snmp plugin + for telegraf + " + ::= { iso 1 } + +DateAndTime ::= TEXTUAL-CONVENTION + DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d" + STATUS current + DESCRIPTION + "A date-time specification. + + field octets contents range + ----- ------ -------- ----- + 1 1-2 year* 0..65536 + 2 3 month 1..12 + 3 4 day 1..31 + 4 5 hour 0..23 + 5 6 minutes 0..59 + 6 7 seconds 0..60 + (use 60 for leap-second) + 7 8 deci-seconds 0..9 + 8 9 direction from UTC '+' / '-' + 9 10 hours from UTC* 0..13 + 10 11 minutes from UTC 0..59 + + * Notes: + - the value of year is in network-byte order + - daylight saving time in New Zealand is +13 + + For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be + displayed as: + + 1992-5-26,13:30:15.0,-4:0 + + Note that if only local time is known, then timezone + information (fields 8-10) is not present." + SYNTAX OCTET STRING (SIZE (8 | 11)) + +testingObjects OBJECT IDENTIFIER ::= { iso 0 } +testObjects OBJECT IDENTIFIER ::= { testingObjects 0 } +hostnameone OBJECT IDENTIFIER ::= {testObjects 1 } +hostname OBJECT IDENTIFIER ::= { hostnameone 1 } +testTable OBJECT IDENTIFIER ::= { testObjects 0 } +testMIBObjects OBJECT IDENTIFIER ::= { testTable 1 } + + +server OBJECT-TYPE + SYNTAX Integer32 + ACCESS read-only + STATUS current + DESCRIPTION + "server mib for testing" + ::= { testMIBObjects 1 } + +connections OBJECT-TYPE + SYNTAX Integer32 + ACCESS read-only + STATUS current + DESCRIPTION + "server mib for testing" + ::= { testMIBObjects 2 } + +latency OBJECT-TYPE + SYNTAX Integer32 + ACCESS read-only + STATUS current + DESCRIPTION + "server mib for testing" + ::= { testMIBObjects 3 } + +description OBJECT-TYPE + SYNTAX Integer32 + ACCESS read-only + STATUS current + DESCRIPTION + "server mib for testing" + ::= { testMIBObjects 4 } + +dateAndTime OBJECT-TYPE + SYNTAX DateAndTime + ACCESS read-only + STATUS current + DESCRIPTION + "A date-time specification." + ::= { testMIBObjects 5 } + +END diff --git a/internal/snmp/testdata/gosmi/serverImports b/internal/snmp/testdata/gosmi/serverImports new file mode 100644 index 0000000..6bfb238 --- /dev/null +++ b/internal/snmp/testdata/gosmi/serverImports @@ -0,0 +1,174 @@ +fooImports DEFINITIONS ::= BEGIN + +-- the path to the root + +org OBJECT IDENTIFIER ::= { iso 1 } -- "iso" = 1 +dod OBJECT IDENTIFIER ::= { org 1 } +internet OBJECT IDENTIFIER ::= { dod 1 } + +directory OBJECT IDENTIFIER ::= { internet 1 } + +mgmt OBJECT IDENTIFIER ::= { internet 1 } +mib-2 OBJECT IDENTIFIER ::= { mgmt 1 } + +ExtUTCTime ::= OCTET STRING(SIZE(11 | 13)) + -- format is YYMMDDHHMMZ or YYYYMMDDHHMMZ + + -- where: YY - last two digits of year (only years + -- between 1900-1999) + -- YYYY - last four digits of the year (any year) + -- MM - month (01 through 12) + -- DD - day of month (01 through 31) + -- HH - hours (00 through 23) + -- MM - minutes (00 through 59) + -- Z - denotes GMT (the ASCII character Z) + -- + -- For example, "9502192015Z" and "199502192015Z" represent + -- 8:15pm GMT on 19 February 1995. Years after 1999 must use + -- the four digit year format. Years 1900-1999 may use the + -- two or four digit format. + +-- definitions for information modules + +MODULE-IDENTITY MACRO ::= +BEGIN + TYPE NOTATION ::= + "LAST-UPDATED" value(Update ExtUTCTime) + "ORGANIZATION" Text + "CONTACT-INFO" Text + "DESCRIPTION" Text + RevisionPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + RevisionPart ::= + Revisions + | empty + Revisions ::= + Revision + | Revisions Revision + Revision ::= + "REVISION" value(Update ExtUTCTime) + "DESCRIPTION" Text + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +OBJECT-IDENTITY MACRO ::= +BEGIN + TYPE NOTATION ::= + "STATUS" Status + "DESCRIPTION" Text + + ReferPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +-- names of objects +-- (Note that these definitions of ObjectName and NotificationName +-- are not to be IMPORTed by MIB modules.) + +ObjectName ::= + OBJECT IDENTIFIER + +NotificationName ::= + OBJECT IDENTIFIER + + +-- indistinguishable from INTEGER, but never needs more than +-- 32-bits for a two's complement representation +Integer32 ::= + INTEGER (-2147483648..2147483647) + + + +-- definition for objects + +OBJECT-TYPE MACRO ::= +BEGIN + TYPE NOTATION ::= + UnitsPart + "MAX-ACCESS" Access + "STATUS" Status + "DESCRIPTION" Text + ReferPart + + IndexPart + DefValPart + + VALUE NOTATION ::= + value(VALUE ObjectName) + + NamedBits ::= NamedBit + | NamedBits "," NamedBit + + NamedBit ::= identifier "(" number ")" -- number is nonnegative + + UnitsPart ::= + "UNITS" Text + | empty + + Access ::= + "not-accessible" + | "accessible-for-notify" + | "read-only" + | "read-write" + | "read-create" + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + IndexPart ::= + "INDEX" "{" IndexTypes "}" + | "AUGMENTS" "{" Entry "}" + | empty + IndexTypes ::= + IndexType + | IndexTypes "," IndexType + IndexType ::= + "IMPLIED" Index + | Index + + Entry ::= + -- use the INDEX value of the + -- correspondent OBJECT-TYPE invocation + value(ObjectName) + + DefValPart ::= "DEFVAL" "{" Defvalue "}" + | empty + + BitsValue ::= BitNames + | empty + + BitNames ::= BitName + | BitNames "," BitName + + BitName ::= identifier + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +END \ No newline at end of file diff --git a/internal/snmp/testdata/gosmi/tableBuild b/internal/snmp/testdata/gosmi/tableBuild new file mode 100644 index 0000000..0551bfd --- /dev/null +++ b/internal/snmp/testdata/gosmi/tableBuild @@ -0,0 +1,57 @@ +TEST DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Integer32 FROM fooImports; + +TestMIB MODULE-IDENTITY + LAST-UPDATED "2021090800Z" + ORGANIZATION "influx" + CONTACT-INFO + "EMail: influx@email.com" + DESCRIPTION + "MIB module for testing snmp plugin + for telegraf + " + ::= { iso 1 } + +testingObjects OBJECT IDENTIFIER ::= { iso 0 } +testObjects OBJECT IDENTIFIER ::= { testingObjects 0 } +hostnameone OBJECT IDENTIFIER ::= {testObjects 1 } +hostname OBJECT IDENTIFIER ::= { hostnameone 1 } +testTable OBJECT IDENTIFIER ::= { testObjects 0 } +testMIBObjects OBJECT IDENTIFIER ::= { testTable 1 } + + +myfield1 OBJECT-TYPE + SYNTAX Integer32 + ACCESS read-only + STATUS current + DESCRIPTION + "server mib for testing" + ::= { testMIBObjects 1 } + +myfield2 OBJECT-TYPE + SYNTAX Integer32 + ACCESS read-only + STATUS current + DESCRIPTION + "server mib for testing" + ::= { testMIBObjects 2 } + +myfield3 OBJECT-TYPE + SYNTAX Integer32 + ACCESS read-only + STATUS current + DESCRIPTION + "server mib for testing" + ::= { testMIBObjects 3 } + +myfield4 OBJECT-TYPE + SYNTAX Integer32 + ACCESS read-only + STATUS current + DESCRIPTION + "server mib for testing" + ::= { testMIBObjects 4 } + +END \ No newline at end of file diff --git a/internal/snmp/testdata/gosmi/tableMib b/internal/snmp/testdata/gosmi/tableMib new file mode 100644 index 0000000..af6cc52 --- /dev/null +++ b/internal/snmp/testdata/gosmi/tableMib @@ -0,0 +1,2613 @@ +RFC1213-MIB DEFINITIONS ::= BEGIN + +IMPORTS + mgmt, NetworkAddress, IpAddress, Counter, Gauge, + TimeTicks + FROM RFC1155-SMI + OBJECT-TYPE + FROM fooImports; + +-- This MIB module uses the extended OBJECT-TYPE macro as +-- defined in [14]; + +-- MIB-II (same prefix as MIB-I) + +mib-2 OBJECT IDENTIFIER ::= { mgmt 1 } + +-- textual conventions + +DisplayString ::= + OCTET STRING +-- This data type is used to model textual information taken +-- from the NVT ASCII character set. By convention, objects +-- with this syntax are declared as having + +-- +-- SIZE (0..255) + +PhysAddress ::= TEXTUAL-CONVENTION + DISPLAY-HINT "1x:" + STATUS current + DESCRIPTION + "Represents media- or physical-level addresses." + SYNTAX OCTET STRING + +-- groups in MIB-II + +system OBJECT IDENTIFIER ::= { mib-2 1 } + +interfaces OBJECT IDENTIFIER ::= { mib-2 2 } + +at OBJECT IDENTIFIER ::= { mib-2 3 } + +ip OBJECT IDENTIFIER ::= { mib-2 4 } + +icmp OBJECT IDENTIFIER ::= { mib-2 5 } + +tcp OBJECT IDENTIFIER ::= { mib-2 6 } + +udp OBJECT IDENTIFIER ::= { mib-2 7 } + +egp OBJECT IDENTIFIER ::= { mib-2 8 } + +-- historical (some say hysterical) +-- cmot OBJECT IDENTIFIER ::= { mib-2 9 } + +transmission OBJECT IDENTIFIER ::= { mib-2 10 } + +snmp OBJECT IDENTIFIER ::= { mib-2 11 } + +-- the System group + +-- Implementation of the System group is mandatory for all +-- systems. If an agent is not configured to have a value +-- for any of these variables, a string of length 0 is +-- returned. + +sysDescr OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A textual description of the entity. This value + should include the full name and version + identification of the system's hardware type, + software operating-system, and networking + software. It is mandatory that this only contain + printable ASCII characters." + ::= { system 1 } + +sysObjectID OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The vendor's authoritative identification of the + network management subsystem contained in the + entity. This value is allocated within the SMI + enterprises subtree (1.3.6.1.4.1) and provides an + easy and unambiguous means for determining `what + kind of box' is being managed. For example, if + vendor `Flintstones, Inc.' was assigned the + subtree 1.3.6.1.4.1.4242, it could assign the + identifier 1.3.6.1.4.1.4242.1.1 to its `Fred + Router'." + ::= { system 2 } + +sysUpTime OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The time (in hundredths of a second) since the + network management portion of the system was last + re-initialized." + ::= { system 3 } + +sysContact OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The textual identification of the contact person + for this managed node, together with information + on how to contact this person." + ::= { system 4 } + +sysName OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An administratively-assigned name for this + managed node. By convention, this is the node's + fully-qualified domain name." + ::= { system 5 } + +sysLocation OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The physical location of this node (e.g., + `telephone closet, 3rd floor')." + ::= { system 6 } + +sysServices OBJECT-TYPE + SYNTAX INTEGER (0..127) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A value which indicates the set of services that + this entity primarily offers. + + The value is a sum. This sum initially takes the + value zero, Then, for each layer, L, in the range + 1 through 7, that this node performs transactions + for, 2 raised to (L - 1) is added to the sum. For + example, a node which performs primarily routing + functions would have a value of 4 (2^(3-1)). In + contrast, a node which is a host offering + application services would have a value of 72 + (2^(4-1) + 2^(7-1)). Note that in the context of + the Internet suite of protocols, values should be + calculated accordingly: + + layer functionality + 1 physical (e.g., repeaters) + 2 datalink/subnetwork (e.g., bridges) + 3 internet (e.g., IP gateways) + 4 end-to-end (e.g., IP hosts) + 7 applications (e.g., mail relays) + + For systems including OSI protocols, layers 5 and + 6 may also be counted." + ::= { system 7 } + +-- the Interfaces group + +-- Implementation of the Interfaces group is mandatory for +-- all systems. + +ifNumber OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of network interfaces (regardless of + their current state) present on this system." + ::= { interfaces 1 } + +-- the Interfaces table + +-- The Interfaces table contains information on the entity's +-- interfaces. Each interface is thought of as being +-- attached to a `subnetwork'. Note that this term should +-- not be confused with `subnet' which refers to an +-- addressing partitioning scheme used in the Internet suite +-- of protocols. + +ifTable OBJECT-TYPE + SYNTAX SEQUENCE OF IfEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A list of interface entries. The number of + entries is given by the value of ifNumber." + ::= { interfaces 2 } + +ifEntry OBJECT-TYPE + SYNTAX IfEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "An interface entry containing objects at the + subnetwork layer and below for a particular + interface." + INDEX { ifIndex } + ::= { ifTable 1 } + +IfEntry ::= + SEQUENCE { + ifIndex + INTEGER, + ifDescr + DisplayString, + ifType + INTEGER, + ifMtu + INTEGER, + ifSpeed + Gauge, + ifPhysAddress + PhysAddress, + ifAdminStatus + INTEGER, + ifOperStatus + INTEGER, + ifLastChange + TimeTicks, + ifInOctets + Counter, + ifInUcastPkts + Counter, + ifInNUcastPkts + Counter, + ifInDiscards + Counter, + ifInErrors + Counter, + ifInUnknownProtos + Counter, + ifOutOctets + Counter, + ifOutUcastPkts + Counter, + ifOutNUcastPkts + Counter, + ifOutDiscards + Counter, + ifOutErrors + Counter, + ifOutQLen + Gauge, + ifSpecific + OBJECT IDENTIFIER + } + +ifIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A unique value for each interface. Its value + ranges between 1 and the value of ifNumber. The + value for each interface must remain constant at + least from one re-initialization of the entity's + network management system to the next re- + initialization." + ::= { ifEntry 1 } + +ifDescr OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A textual string containing information about the + interface. This string should include the name of + the manufacturer, the product name and the version + of the hardware interface." + ::= { ifEntry 2 } + +ifType OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + regular1822(2), + hdh1822(3), + ddn-x25(4), + rfc877-x25(5), + ethernet-csmacd(6), + iso88023-csmacd(7), + iso88024-tokenBus(8), + iso88025-tokenRing(9), + iso88026-man(10), + starLan(11), + proteon-10Mbit(12), + proteon-80Mbit(13), + hyperchannel(14), + fddi(15), + lapb(16), + sdlc(17), + ds1(18), -- T-1 + e1(19), -- european equiv. of T-1 + basicISDN(20), + primaryISDN(21), -- proprietary serial + propPointToPointSerial(22), + ppp(23), + softwareLoopback(24), + eon(25), -- CLNP over IP [11] + ethernet-3Mbit(26), + nsip(27), -- XNS over IP + slip(28), -- generic SLIP + ultra(29), -- ULTRA technologies + ds3(30), -- T-3 + sip(31), -- SMDS + frame-relay(32) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The type of interface, distinguished according to + the physical/link protocol(s) immediately `below' + the network layer in the protocol stack." + ::= { ifEntry 3 } + +ifMtu OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The size of the largest datagram which can be + sent/received on the interface, specified in + octets. For interfaces that are used for + transmitting network datagrams, this is the size + of the largest network datagram that can be sent + on the interface." + ::= { ifEntry 4 } + +ifSpeed OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "An estimate of the interface's current bandwidth + in bits per second. For interfaces which do not + vary in bandwidth or for those where no accurate + estimation can be made, this object should contain + the nominal bandwidth." + ::= { ifEntry 5 } + +ifPhysAddress OBJECT-TYPE + SYNTAX PhysAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The interface's address at the protocol layer + immediately `below' the network layer in the + protocol stack. For interfaces which do not have + + such an address (e.g., a serial line), this object + should contain an octet string of zero length." + ::= { ifEntry 6 } + +ifAdminStatus OBJECT-TYPE + SYNTAX INTEGER { + up(1), -- ready to pass packets + down(2), + testing(3) -- in some test mode + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The desired state of the interface. The + testing(3) state indicates that no operational + packets can be passed." + ::= { ifEntry 7 } + +ifOperStatus OBJECT-TYPE + SYNTAX INTEGER { + up(1), -- ready to pass packets + down(2), + testing(3) -- in some test mode + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The current operational state of the interface. + The testing(3) state indicates that no operational + packets can be passed." + ::= { ifEntry 8 } + +ifLastChange OBJECT-TYPE + SYNTAX TimeTicks + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The value of sysUpTime at the time the interface + entered its current operational state. If the + current state was entered prior to the last re- + initialization of the local network management + subsystem, then this object contains a zero + value." + ::= { ifEntry 9 } + +ifInOctets OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of octets received on the + interface, including framing characters." + ::= { ifEntry 10 } + +ifInUcastPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of subnetwork-unicast packets + delivered to a higher-layer protocol." + ::= { ifEntry 11 } + +ifInNUcastPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of non-unicast (i.e., subnetwork- + broadcast or subnetwork-multicast) packets + delivered to a higher-layer protocol." + ::= { ifEntry 12 } + +ifInDiscards OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of inbound packets which were chosen + to be discarded even though no errors had been + detected to prevent their being deliverable to a + higher-layer protocol. One possible reason for + discarding such a packet could be to free up + buffer space." + ::= { ifEntry 13 } + +ifInErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of inbound packets that contained + errors preventing them from being deliverable to a + higher-layer protocol." + ::= { ifEntry 14 } + +ifInUnknownProtos OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of packets received via the interface + which were discarded because of an unknown or + unsupported protocol." + ::= { ifEntry 15 } + +ifOutOctets OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of octets transmitted out of the + interface, including framing characters." + ::= { ifEntry 16 } + +ifOutUcastPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of packets that higher-level + protocols requested be transmitted to a + subnetwork-unicast address, including those that + were discarded or not sent." + ::= { ifEntry 17 } + +ifOutNUcastPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of packets that higher-level + protocols requested be transmitted to a non- + unicast (i.e., a subnetwork-broadcast or + subnetwork-multicast) address, including those + that were discarded or not sent." + ::= { ifEntry 18 } + +ifOutDiscards OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of outbound packets which were chosen + + to be discarded even though no errors had been + detected to prevent their being transmitted. One + possible reason for discarding such a packet could + be to free up buffer space." + ::= { ifEntry 19 } + +ifOutErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of outbound packets that could not be + transmitted because of errors." + ::= { ifEntry 20 } + +ifOutQLen OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The length of the output packet queue (in + packets)." + ::= { ifEntry 21 } + +ifSpecific OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A reference to MIB definitions specific to the + particular media being used to realize the + interface. For example, if the interface is + realized by an ethernet, then the value of this + object refers to a document defining objects + specific to ethernet. If this information is not + present, its value should be set to the OBJECT + IDENTIFIER { 0 0 }, which is a syntactically valid + object identifier, and any conformant + implementation of ASN.1 and BER must be able to + generate and recognize this value." + ::= { ifEntry 22 } + +-- the Address Translation group + +-- Implementation of the Address Translation group is +-- mandatory for all systems. Note however that this group +-- is deprecated by MIB-II. That is, it is being included + +-- solely for compatibility with MIB-I nodes, and will most +-- likely be excluded from MIB-III nodes. From MIB-II and +-- onwards, each network protocol group contains its own +-- address translation tables. + +-- The Address Translation group contains one table which is +-- the union across all interfaces of the translation tables +-- for converting a NetworkAddress (e.g., an IP address) into +-- a subnetwork-specific address. For lack of a better term, +-- this document refers to such a subnetwork-specific address +-- as a `physical' address. + +-- Examples of such translation tables are: for broadcast +-- media where ARP is in use, the translation table is +-- equivalent to the ARP cache; or, on an X.25 network where +-- non-algorithmic translation to X.121 addresses is +-- required, the translation table contains the +-- NetworkAddress to X.121 address equivalences. + +atTable OBJECT-TYPE + SYNTAX SEQUENCE OF AtEntry + ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "The Address Translation tables contain the + NetworkAddress to `physical' address equivalences. + Some interfaces do not use translation tables for + determining address equivalences (e.g., DDN-X.25 + has an algorithmic method); if all interfaces are + of this type, then the Address Translation table + is empty, i.e., has zero entries." + ::= { at 1 } + +atEntry OBJECT-TYPE + SYNTAX AtEntry + ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "Each entry contains one NetworkAddress to + `physical' address equivalence." + INDEX { atIfIndex, + atNetAddress } + ::= { atTable 1 } + +AtEntry ::= + SEQUENCE { + atIfIndex + INTEGER, + atPhysAddress + PhysAddress, + atNetAddress + NetworkAddress + } + +atIfIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS deprecated + DESCRIPTION + "The interface on which this entry's equivalence + is effective. The interface identified by a + particular value of this index is the same + interface as identified by the same value of + ifIndex." + ::= { atEntry 1 } + +atPhysAddress OBJECT-TYPE + SYNTAX PhysAddress + ACCESS read-write + STATUS deprecated + DESCRIPTION + "The media-dependent `physical' address. + + Setting this object to a null string (one of zero + length) has the effect of invaliding the + corresponding entry in the atTable object. That + is, it effectively disassociates the interface + identified with said entry from the mapping + identified with said entry. It is an + implementation-specific matter as to whether the + agent removes an invalidated entry from the table. + Accordingly, management stations must be prepared + to receive tabular information from agents that + corresponds to entries not currently in use. + Proper interpretation of such entries requires + examination of the relevant atPhysAddress object." + ::= { atEntry 2 } + +atNetAddress OBJECT-TYPE + SYNTAX NetworkAddress + ACCESS read-write + STATUS deprecated + DESCRIPTION + "The NetworkAddress (e.g., the IP address) + corresponding to the media-dependent `physical' + address." + ::= { atEntry 3 } + +-- the IP group + +-- Implementation of the IP group is mandatory for all +-- systems. + +ipForwarding OBJECT-TYPE + SYNTAX INTEGER { + forwarding(1), -- acting as a gateway + not-forwarding(2) -- NOT acting as a gateway + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The indication of whether this entity is acting + as an IP gateway in respect to the forwarding of + datagrams received by, but not addressed to, this + entity. IP gateways forward datagrams. IP hosts + do not (except those source-routed via the host). + + Note that for some managed nodes, this object may + take on only a subset of the values possible. + Accordingly, it is appropriate for an agent to + return a `badValue' response if a management + station attempts to change this object to an + inappropriate value." + ::= { ip 1 } + +ipDefaultTTL OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The default value inserted into the Time-To-Live + field of the IP header of datagrams originated at + this entity, whenever a TTL value is not supplied + by the transport layer protocol." + ::= { ip 2 } + +ipInReceives OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of input datagrams received from + interfaces, including those received in error." + ::= { ip 3 } + +ipInHdrErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input datagrams discarded due to + errors in their IP headers, including bad + checksums, version number mismatch, other format + errors, time-to-live exceeded, errors discovered + in processing their IP options, etc." + ::= { ip 4 } + +ipInAddrErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input datagrams discarded because + the IP address in their IP header's destination + field was not a valid address to be received at + this entity. This count includes invalid + addresses (e.g., 0.0.0.0) and addresses of + unsupported Classes (e.g., Class E). For entities + which are not IP Gateways and therefore do not + forward datagrams, this counter includes datagrams + discarded because the destination address was not + a local address." + ::= { ip 5 } + +ipForwDatagrams OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input datagrams for which this + entity was not their final IP destination, as a + result of which an attempt was made to find a + route to forward them to that final destination. + In entities which do not act as IP Gateways, this + counter will include only those packets which were + Source-Routed via this entity, and the Source- + Route option processing was successful." + ::= { ip 6 } + +ipInUnknownProtos OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of locally-addressed datagrams + received successfully but discarded because of an + unknown or unsupported protocol." + ::= { ip 7 } + +ipInDiscards OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of input IP datagrams for which no + problems were encountered to prevent their + continued processing, but which were discarded + (e.g., for lack of buffer space). Note that this + counter does not include any datagrams discarded + while awaiting re-assembly." + ::= { ip 8 } + +ipInDelivers OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of input datagrams successfully + delivered to IP user-protocols (including ICMP)." + ::= { ip 9 } + +ipOutRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of IP datagrams which local IP + user-protocols (including ICMP) supplied to IP in + requests for transmission. Note that this counter + does not include any datagrams counted in + ipForwDatagrams." + ::= { ip 10 } + +ipOutDiscards OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of output IP datagrams for which no + + problem was encountered to prevent their + transmission to their destination, but which were + discarded (e.g., for lack of buffer space). Note + that this counter would include datagrams counted + in ipForwDatagrams if any such packets met this + (discretionary) discard criterion." + ::= { ip 11 } + +ipOutNoRoutes OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of IP datagrams discarded because no + route could be found to transmit them to their + destination. Note that this counter includes any + packets counted in ipForwDatagrams which meet this + `no-route' criterion. Note that this includes any + datagarms which a host cannot route because all of + its default gateways are down." + ::= { ip 12 } + +ipReasmTimeout OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum number of seconds which received + fragments are held while they are awaiting + reassembly at this entity." + ::= { ip 13 } + +ipReasmReqds OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of IP fragments received which needed + to be reassembled at this entity." + ::= { ip 14 } + +ipReasmOKs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of IP datagrams successfully re- + assembled." + ::= { ip 15 } + +ipReasmFails OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of failures detected by the IP re- + assembly algorithm (for whatever reason: timed + out, errors, etc). Note that this is not + necessarily a count of discarded IP fragments + since some algorithms (notably the algorithm in + RFC 815) can lose track of the number of fragments + by combining them as they are received." + ::= { ip 16 } + +ipFragOKs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of IP datagrams that have been + successfully fragmented at this entity." + ::= { ip 17 } + +ipFragFails OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of IP datagrams that have been + discarded because they needed to be fragmented at + this entity but could not be, e.g., because their + Don't Fragment flag was set." + ::= { ip 18 } + +ipFragCreates OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of IP datagram fragments that have + been generated as a result of fragmentation at + this entity." + ::= { ip 19 } + +-- the IP address table + +-- The IP address table contains this entity's IP addressing +-- information. + +ipAddrTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpAddrEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The table of addressing information relevant to + this entity's IP addresses." + ::= { ip 20 } + +ipAddrEntry OBJECT-TYPE + SYNTAX IpAddrEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The addressing information for one of this + entity's IP addresses." + INDEX { ipAdEntAddr } + ::= { ipAddrTable 1 } + +IpAddrEntry ::= + SEQUENCE { + ipAdEntAddr + IpAddress, + ipAdEntIfIndex + INTEGER, + ipAdEntNetMask + IpAddress, + ipAdEntBcastAddr + INTEGER, + ipAdEntReasmMaxSize + INTEGER (0..65535) + } + +ipAdEntAddr OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The IP address to which this entry's addressing + information pertains." + ::= { ipAddrEntry 1 } + +ipAdEntIfIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The index value which uniquely identifies the + interface to which this entry is applicable. The + interface identified by a particular value of this + index is the same interface as identified by the + same value of ifIndex." + ::= { ipAddrEntry 2 } + +ipAdEntNetMask OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The subnet mask associated with the IP address of + this entry. The value of the mask is an IP + address with all the network bits set to 1 and all + the hosts bits set to 0." + ::= { ipAddrEntry 3 } + +ipAdEntBcastAddr OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The value of the least-significant bit in the IP + broadcast address used for sending datagrams on + the (logical) interface associated with the IP + address of this entry. For example, when the + Internet standard all-ones broadcast address is + used, the value will be 1. This value applies to + both the subnet and network broadcasts addresses + used by the entity on this (logical) interface." + ::= { ipAddrEntry 4 } + +ipAdEntReasmMaxSize OBJECT-TYPE + SYNTAX INTEGER (0..65535) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The size of the largest IP datagram which this + entity can re-assemble from incoming IP fragmented + datagrams received on this interface." + ::= { ipAddrEntry 5 } + +-- the IP routing table + +-- The IP routing table contains an entry for each route +-- presently known to this entity. + +ipRouteTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpRouteEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "This entity's IP Routing table." + ::= { ip 21 } + +ipRouteEntry OBJECT-TYPE + SYNTAX IpRouteEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A route to a particular destination." + INDEX { ipRouteDest } + ::= { ipRouteTable 1 } + +IpRouteEntry ::= + SEQUENCE { + ipRouteDest + IpAddress, + ipRouteIfIndex + INTEGER, + ipRouteMetric1 + INTEGER, + ipRouteMetric2 + INTEGER, + ipRouteMetric3 + INTEGER, + ipRouteMetric4 + INTEGER, + ipRouteNextHop + IpAddress, + ipRouteType + INTEGER, + ipRouteProto + INTEGER, + ipRouteAge + INTEGER, + ipRouteMask + IpAddress, + ipRouteMetric5 + INTEGER, + ipRouteInfo + OBJECT IDENTIFIER + } + +ipRouteDest OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The destination IP address of this route. An + entry with a value of 0.0.0.0 is considered a + default route. Multiple routes to a single + destination can appear in the table, but access to + such multiple entries is dependent on the table- + access mechanisms defined by the network + management protocol in use." + ::= { ipRouteEntry 1 } + +ipRouteIfIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The index value which uniquely identifies the + local interface through which the next hop of this + route should be reached. The interface identified + by a particular value of this index is the same + interface as identified by the same value of + ifIndex." + ::= { ipRouteEntry 2 } + +ipRouteMetric1 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The primary routing metric for this route. The + semantics of this metric are determined by the + routing-protocol specified in the route's + ipRouteProto value. If this metric is not used, + its value should be set to -1." + ::= { ipRouteEntry 3 } + +ipRouteMetric2 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An alternate routing metric for this route. The + semantics of this metric are determined by the + routing-protocol specified in the route's + ipRouteProto value. If this metric is not used, + its value should be set to -1." + ::= { ipRouteEntry 4 } + +ipRouteMetric3 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An alternate routing metric for this route. The + semantics of this metric are determined by the + routing-protocol specified in the route's + ipRouteProto value. If this metric is not used, + its value should be set to -1." + ::= { ipRouteEntry 5 } + +ipRouteMetric4 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An alternate routing metric for this route. The + semantics of this metric are determined by the + routing-protocol specified in the route's + ipRouteProto value. If this metric is not used, + its value should be set to -1." + ::= { ipRouteEntry 6 } + +ipRouteNextHop OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The IP address of the next hop of this route. + (In the case of a route bound to an interface + which is realized via a broadcast media, the value + of this field is the agent's IP address on that + interface.)" + ::= { ipRouteEntry 7 } + +ipRouteType OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + + invalid(2), -- an invalidated route + + -- route to directly + direct(3), -- connected (sub-)network + + -- route to a non-local + indirect(4) -- host/network/sub-network + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The type of route. Note that the values + direct(3) and indirect(4) refer to the notion of + direct and indirect routing in the IP + architecture. + + Setting this object to the value invalid(2) has + the effect of invalidating the corresponding entry + in the ipRouteTable object. That is, it + effectively disassociates the destination + identified with said entry from the route + identified with said entry. It is an + implementation-specific matter as to whether the + agent removes an invalidated entry from the table. + Accordingly, management stations must be prepared + to receive tabular information from agents that + corresponds to entries not currently in use. + Proper interpretation of such entries requires + examination of the relevant ipRouteType object." + ::= { ipRouteEntry 8 } + +ipRouteProto OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + + -- non-protocol information, + -- e.g., manually configured + local(2), -- entries + + -- set via a network + netmgmt(3), -- management protocol + + -- obtained via ICMP, + icmp(4), -- e.g., Redirect + + -- the remaining values are + -- all gateway routing + -- protocols + egp(5), + ggp(6), + hello(7), + rip(8), + is-is(9), + es-is(10), + ciscoIgrp(11), + bbnSpfIgp(12), + ospf(13), + bgp(14) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The routing mechanism via which this route was + learned. Inclusion of values for gateway routing + protocols is not intended to imply that hosts + should support those protocols." + ::= { ipRouteEntry 9 } + +ipRouteAge OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The number of seconds since this route was last + updated or otherwise determined to be correct. + Note that no semantics of `too old' can be implied + except through knowledge of the routing protocol + by which the route was learned." + ::= { ipRouteEntry 10 } + +ipRouteMask OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Indicate the mask to be logical-ANDed with the + destination address before being compared to the + value in the ipRouteDest field. For those systems + that do not support arbitrary subnet masks, an + agent constructs the value of the ipRouteMask by + determining whether the value of the correspondent + ipRouteDest field belong to a class-A, B, or C + network, and then using one of: + + mask network + 255.0.0.0 class-A + 255.255.0.0 class-B + 255.255.255.0 class-C + + If the value of the ipRouteDest is 0.0.0.0 (a + default route), then the mask value is also + 0.0.0.0. It should be noted that all IP routing + subsystems implicitly use this mechanism." + ::= { ipRouteEntry 11 } + +ipRouteMetric5 OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "An alternate routing metric for this route. The + semantics of this metric are determined by the + routing-protocol specified in the route's + ipRouteProto value. If this metric is not used, + its value should be set to -1." + ::= { ipRouteEntry 12 } + +ipRouteInfo OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "A reference to MIB definitions specific to the + particular routing protocol which is responsible + for this route, as determined by the value + specified in the route's ipRouteProto value. If + this information is not present, its value should + be set to the OBJECT IDENTIFIER { 0 0 }, which is + a syntactically valid object identifier, and any + conformant implementation of ASN.1 and BER must be + able to generate and recognize this value." + ::= { ipRouteEntry 13 } + +-- the IP Address Translation table + +-- The IP address translation table contain the IpAddress to +-- `physical' address equivalences. Some interfaces do not +-- use translation tables for determining address +-- equivalences (e.g., DDN-X.25 has an algorithmic method); +-- if all interfaces are of this type, then the Address +-- Translation table is empty, i.e., has zero entries. + +ipNetToMediaTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpNetToMediaEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The IP Address Translation table used for mapping + from IP addresses to physical addresses." + ::= { ip 22 } + +ipNetToMediaEntry OBJECT-TYPE + SYNTAX IpNetToMediaEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Each entry contains one IpAddress to `physical' + address equivalence." + INDEX { ipNetToMediaIfIndex, + ipNetToMediaNetAddress } + ::= { ipNetToMediaTable 1 } + +IpNetToMediaEntry ::= + SEQUENCE { + ipNetToMediaIfIndex + INTEGER, + ipNetToMediaPhysAddress + PhysAddress, + ipNetToMediaNetAddress + IpAddress, + ipNetToMediaType + INTEGER + } + +ipNetToMediaIfIndex OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The interface on which this entry's equivalence + is effective. The interface identified by a + particular value of this index is the same + interface as identified by the same value of + ifIndex." + ::= { ipNetToMediaEntry 1 } + +ipNetToMediaPhysAddress OBJECT-TYPE + SYNTAX PhysAddress + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The media-dependent `physical' address." + ::= { ipNetToMediaEntry 2 } + +ipNetToMediaNetAddress OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The IpAddress corresponding to the media- + dependent `physical' address." + ::= { ipNetToMediaEntry 3 } + +ipNetToMediaType OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + invalid(2), -- an invalidated mapping + dynamic(3), + static(4) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The type of mapping. + + Setting this object to the value invalid(2) has + the effect of invalidating the corresponding entry + in the ipNetToMediaTable. That is, it effectively + disassociates the interface identified with said + entry from the mapping identified with said entry. + It is an implementation-specific matter as to + whether the agent removes an invalidated entry + from the table. Accordingly, management stations + must be prepared to receive tabular information + from agents that corresponds to entries not + currently in use. Proper interpretation of such + entries requires examination of the relevant + ipNetToMediaType object." + ::= { ipNetToMediaEntry 4 } + +-- additional IP objects + +ipRoutingDiscards OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of routing entries which were chosen + to be discarded even though they are valid. One + possible reason for discarding such an entry could + be to free-up buffer space for other routing + + entries." + ::= { ip 23 } + +-- the ICMP group + +-- Implementation of the ICMP group is mandatory for all +-- systems. + +icmpInMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of ICMP messages which the + entity received. Note that this counter includes + all those counted by icmpInErrors." + ::= { icmp 1 } + +icmpInErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP messages which the entity + received but determined as having ICMP-specific + errors (bad ICMP checksums, bad length, etc.)." + ::= { icmp 2 } + +icmpInDestUnreachs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Destination Unreachable + messages received." + ::= { icmp 3 } + +icmpInTimeExcds OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Time Exceeded messages + received." + ::= { icmp 4 } + +icmpInParmProbs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Parameter Problem messages + received." + ::= { icmp 5 } + +icmpInSrcQuenchs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Source Quench messages + received." + ::= { icmp 6 } + +icmpInRedirects OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Redirect messages received." + ::= { icmp 7 } + +icmpInEchos OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Echo (request) messages + received." + ::= { icmp 8 } + +icmpInEchoReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Echo Reply messages received." + ::= { icmp 9 } + +icmpInTimestamps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Timestamp (request) messages + received." + ::= { icmp 10 } + +icmpInTimestampReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Timestamp Reply messages + received." + ::= { icmp 11 } + +icmpInAddrMasks OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Address Mask Request messages + received." + ::= { icmp 12 } + +icmpInAddrMaskReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Address Mask Reply messages + received." + ::= { icmp 13 } + +icmpOutMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of ICMP messages which this + entity attempted to send. Note that this counter + includes all those counted by icmpOutErrors." + ::= { icmp 14 } + +icmpOutErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP messages which this entity did + not send due to problems discovered within ICMP + + such as a lack of buffers. This value should not + include errors discovered outside the ICMP layer + such as the inability of IP to route the resultant + datagram. In some implementations there may be no + types of error which contribute to this counter's + value." + ::= { icmp 15 } + +icmpOutDestUnreachs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Destination Unreachable + messages sent." + ::= { icmp 16 } + +icmpOutTimeExcds OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Time Exceeded messages sent." + ::= { icmp 17 } + +icmpOutParmProbs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Parameter Problem messages + sent." + ::= { icmp 18 } + +icmpOutSrcQuenchs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Source Quench messages sent." + ::= { icmp 19 } + +icmpOutRedirects OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Redirect messages sent. For a + + host, this object will always be zero, since hosts + do not send redirects." + ::= { icmp 20 } + +icmpOutEchos OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Echo (request) messages sent." + ::= { icmp 21 } + +icmpOutEchoReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Echo Reply messages sent." + ::= { icmp 22 } + +icmpOutTimestamps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Timestamp (request) messages + sent." + ::= { icmp 23 } + +icmpOutTimestampReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Timestamp Reply messages + sent." + ::= { icmp 24 } + +icmpOutAddrMasks OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Address Mask Request messages + sent." + ::= { icmp 25 } + +icmpOutAddrMaskReps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of ICMP Address Mask Reply messages + sent." + ::= { icmp 26 } + +-- the TCP group + +-- Implementation of the TCP group is mandatory for all +-- systems that implement the TCP. + +-- Note that instances of object types that represent +-- information about a particular TCP connection are +-- transient; they persist only as long as the connection +-- in question. + +tcpRtoAlgorithm OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + + constant(2), -- a constant rto + rsre(3), -- MIL-STD-1778, Appendix B + vanj(4) -- Van Jacobson's algorithm [10] + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The algorithm used to determine the timeout value + used for retransmitting unacknowledged octets." + ::= { tcp 1 } + +tcpRtoMin OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The minimum value permitted by a TCP + implementation for the retransmission timeout, + measured in milliseconds. More refined semantics + for objects of this type depend upon the algorithm + used to determine the retransmission timeout. In + particular, when the timeout algorithm is rsre(3), + an object of this type has the semantics of the + LBOUND quantity described in RFC 793." + ::= { tcp 2 } + +tcpRtoMax OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The maximum value permitted by a TCP + implementation for the retransmission timeout, + measured in milliseconds. More refined semantics + for objects of this type depend upon the algorithm + used to determine the retransmission timeout. In + particular, when the timeout algorithm is rsre(3), + an object of this type has the semantics of the + UBOUND quantity described in RFC 793." + ::= { tcp 3 } + +tcpMaxConn OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The limit on the total number of TCP connections + the entity can support. In entities where the + maximum number of connections is dynamic, this + object should contain the value -1." + ::= { tcp 4 } + +tcpActiveOpens OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of times TCP connections have made a + direct transition to the SYN-SENT state from the + CLOSED state." + ::= { tcp 5 } + +tcpPassiveOpens OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of times TCP connections have made a + direct transition to the SYN-RCVD state from the + LISTEN state." + ::= { tcp 6 } + +tcpAttemptFails OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of times TCP connections have made a + direct transition to the CLOSED state from either + the SYN-SENT state or the SYN-RCVD state, plus the + number of times TCP connections have made a direct + transition to the LISTEN state from the SYN-RCVD + state." + ::= { tcp 7 } + +tcpEstabResets OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of times TCP connections have made a + direct transition to the CLOSED state from either + the ESTABLISHED state or the CLOSE-WAIT state." + ::= { tcp 8 } + +tcpCurrEstab OBJECT-TYPE + SYNTAX Gauge + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of TCP connections for which the + current state is either ESTABLISHED or CLOSE- + WAIT." + ::= { tcp 9 } + +tcpInSegs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of segments received, including + those received in error. This count includes + segments received on currently established + connections." + ::= { tcp 10 } + +tcpOutSegs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of segments sent, including + those on current connections but excluding those + containing only retransmitted octets." + ::= { tcp 11 } + +tcpRetransSegs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of segments retransmitted - that + is, the number of TCP segments transmitted + containing one or more previously transmitted + octets." + ::= { tcp 12 } + +-- the TCP Connection table + +-- The TCP connection table contains information about this +-- entity's existing TCP connections. + +tcpConnTable OBJECT-TYPE + SYNTAX SEQUENCE OF TcpConnEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A table containing TCP connection-specific + information." + ::= { tcp 13 } + +tcpConnEntry OBJECT-TYPE + SYNTAX TcpConnEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Information about a particular current TCP + connection. An object of this type is transient, + in that it ceases to exist when (or soon after) + the connection makes the transition to the CLOSED + state." + INDEX { tcpConnLocalAddress, + tcpConnLocalPort, + tcpConnRemAddress, + tcpConnRemPort } + ::= { tcpConnTable 1 } + +TcpConnEntry ::= + SEQUENCE { + tcpConnState + INTEGER, + tcpConnLocalAddress + IpAddress, + tcpConnLocalPort + INTEGER (0..65535), + tcpConnRemAddress + IpAddress, + tcpConnRemPort + INTEGER (0..65535) + } + +tcpConnState OBJECT-TYPE + SYNTAX INTEGER { + closed(1), + listen(2), + synSent(3), + synReceived(4), + established(5), + finWait1(6), + finWait2(7), + closeWait(8), + lastAck(9), + closing(10), + timeWait(11), + deleteTCB(12) + } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "The state of this TCP connection. + + The only value which may be set by a management + station is deleteTCB(12). Accordingly, it is + appropriate for an agent to return a `badValue' + response if a management station attempts to set + this object to any other value. + + If a management station sets this object to the + value deleteTCB(12), then this has the effect of + deleting the TCB (as defined in RFC 793) of the + corresponding connection on the managed node, + resulting in immediate termination of the + connection. + + As an implementation-specific option, a RST + + segment may be sent from the managed node to the + other TCP endpoint (note however that RST segments + are not sent reliably)." + ::= { tcpConnEntry 1 } + +tcpConnLocalAddress OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The local IP address for this TCP connection. In + the case of a connection in the listen state which + is willing to accept connections for any IP + interface associated with the node, the value + 0.0.0.0 is used." + ::= { tcpConnEntry 2 } + +tcpConnLocalPort OBJECT-TYPE + SYNTAX INTEGER (0..65535) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The local port number for this TCP connection." + ::= { tcpConnEntry 3 } + +tcpConnRemAddress OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The remote IP address for this TCP connection." + ::= { tcpConnEntry 4 } + +tcpConnRemPort OBJECT-TYPE + SYNTAX INTEGER (0..65535) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The remote port number for this TCP connection." + ::= { tcpConnEntry 5 } + +-- additional TCP objects + +tcpInErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of segments received in error + (e.g., bad TCP checksums)." + ::= { tcp 14 } + +tcpOutRsts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of TCP segments sent containing the + RST flag." + ::= { tcp 15 } + +-- the UDP group + +-- Implementation of the UDP group is mandatory for all +-- systems which implement the UDP. + +udpInDatagrams OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of UDP datagrams delivered to + UDP users." + ::= { udp 1 } + +udpNoPorts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of received UDP datagrams for + which there was no application at the destination + port." + ::= { udp 2 } + +udpInErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of received UDP datagrams that could + not be delivered for reasons other than the lack + of an application at the destination port." + ::= { udp 3 } + +udpOutDatagrams OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of UDP datagrams sent from this + entity." + ::= { udp 4 } + +-- the UDP Listener table + +-- The UDP listener table contains information about this +-- entity's UDP end-points on which a local application is +-- currently accepting datagrams. + +udpTable OBJECT-TYPE + SYNTAX SEQUENCE OF UdpEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "A table containing UDP listener information." + ::= { udp 5 } + +udpEntry OBJECT-TYPE + SYNTAX UdpEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Information about a particular current UDP + listener." + INDEX { udpLocalAddress, udpLocalPort } + ::= { udpTable 1 } + +UdpEntry ::= + SEQUENCE { + udpLocalAddress + IpAddress, + udpLocalPort + INTEGER (0..65535) + } + +udpLocalAddress OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The local IP address for this UDP listener. In + + the case of a UDP listener which is willing to + accept datagrams for any IP interface associated + with the node, the value 0.0.0.0 is used." + ::= { udpEntry 1 } + +udpLocalPort OBJECT-TYPE + SYNTAX INTEGER (0..65535) + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The local port number for this UDP listener." + ::= { udpEntry 2 } + +-- the EGP group + +-- Implementation of the EGP group is mandatory for all +-- systems which implement the EGP. + +egpInMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP messages received without + error." + ::= { egp 1 } + +egpInErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP messages received that proved + to be in error." + ::= { egp 2 } + +egpOutMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of locally generated EGP + messages." + ::= { egp 3 } + +egpOutErrors OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of locally generated EGP messages not + sent due to resource limitations within an EGP + entity." + ::= { egp 4 } + +-- the EGP Neighbor table + +-- The EGP neighbor table contains information about this +-- entity's EGP neighbors. + +egpNeighTable OBJECT-TYPE + SYNTAX SEQUENCE OF EgpNeighEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "The EGP neighbor table." + ::= { egp 5 } + +egpNeighEntry OBJECT-TYPE + SYNTAX EgpNeighEntry + ACCESS not-accessible + STATUS mandatory + DESCRIPTION + "Information about this entity's relationship with + a particular EGP neighbor." + INDEX { egpNeighAddr } + ::= { egpNeighTable 1 } + +EgpNeighEntry ::= + SEQUENCE { + egpNeighState + INTEGER, + egpNeighAddr + IpAddress, + egpNeighAs + INTEGER, + egpNeighInMsgs + Counter, + egpNeighInErrs + Counter, + egpNeighOutMsgs + Counter, + egpNeighOutErrs + Counter, + egpNeighInErrMsgs + Counter, + egpNeighOutErrMsgs + Counter, + egpNeighStateUps + Counter, + egpNeighStateDowns + Counter, + egpNeighIntervalHello + INTEGER, + egpNeighIntervalPoll + INTEGER, + egpNeighMode + INTEGER, + egpNeighEventTrigger + INTEGER + } + +egpNeighState OBJECT-TYPE + SYNTAX INTEGER { + idle(1), + acquisition(2), + down(3), + up(4), + cease(5) + } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The EGP state of the local system with respect to + this entry's EGP neighbor. Each EGP state is + represented by a value that is one greater than + the numerical value associated with said state in + RFC 904." + ::= { egpNeighEntry 1 } + +egpNeighAddr OBJECT-TYPE + SYNTAX IpAddress + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The IP address of this entry's EGP neighbor." + ::= { egpNeighEntry 2 } + +egpNeighAs OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The autonomous system of this EGP peer. Zero + should be specified if the autonomous system + number of the neighbor is not yet known." + ::= { egpNeighEntry 3 } + +egpNeighInMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP messages received without error + from this EGP peer." + ::= { egpNeighEntry 4 } + +egpNeighInErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP messages received from this EGP + peer that proved to be in error (e.g., bad EGP + checksum)." + ::= { egpNeighEntry 5 } + +egpNeighOutMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of locally generated EGP messages to + this EGP peer." + ::= { egpNeighEntry 6 } + +egpNeighOutErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of locally generated EGP messages not + sent to this EGP peer due to resource limitations + within an EGP entity." + ::= { egpNeighEntry 7 } + +egpNeighInErrMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP-defined error messages received + from this EGP peer." + ::= { egpNeighEntry 8 } + +egpNeighOutErrMsgs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP-defined error messages sent to + this EGP peer." + ::= { egpNeighEntry 9 } + +egpNeighStateUps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP state transitions to the UP + state with this EGP peer." + ::= { egpNeighEntry 10 } + +egpNeighStateDowns OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The number of EGP state transitions from the UP + state to any other state with this EGP peer." + ::= { egpNeighEntry 11 } + +egpNeighIntervalHello OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The interval between EGP Hello command + retransmissions (in hundredths of a second). This + represents the t1 timer as defined in RFC 904." + ::= { egpNeighEntry 12 } + +egpNeighIntervalPoll OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The interval between EGP poll command + + retransmissions (in hundredths of a second). This + represents the t3 timer as defined in RFC 904." + ::= { egpNeighEntry 13 } + +egpNeighMode OBJECT-TYPE + SYNTAX INTEGER { active(1), passive(2) } + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The polling mode of this EGP entity, either + passive or active." + ::= { egpNeighEntry 14 } + +egpNeighEventTrigger OBJECT-TYPE + SYNTAX INTEGER { start(1), stop(2) } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "A control variable used to trigger operator- + initiated Start and Stop events. When read, this + variable always returns the most recent value that + egpNeighEventTrigger was set to. If it has not + been set since the last initialization of the + network management subsystem on the node, it + returns a value of `stop'. + + When set, this variable causes a Start or Stop + event on the specified neighbor, as specified on + pages 8-10 of RFC 904. Briefly, a Start event + causes an Idle peer to begin neighbor acquisition + and a non-Idle peer to reinitiate neighbor + acquisition. A stop event causes a non-Idle peer + to return to the Idle state until a Start event + occurs, either via egpNeighEventTrigger or + otherwise." + ::= { egpNeighEntry 15 } + +-- additional EGP objects + +egpAs OBJECT-TYPE + SYNTAX INTEGER + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The autonomous system number of this EGP entity." + ::= { egp 6 } + +-- the Transmission group + +-- Based on the transmission media underlying each interface +-- on a system, the corresponding portion of the Transmission +-- group is mandatory for that system. + +-- When Internet-standard definitions for managing +-- transmission media are defined, the transmission group is +-- used to provide a prefix for the names of those objects. + +-- Typically, such definitions reside in the experimental +-- portion of the MIB until they are "proven", then as a +-- part of the Internet standardization process, the +-- definitions are accordingly elevated and a new object +-- identifier, under the transmission group is defined. By +-- convention, the name assigned is: +-- +-- type OBJECT IDENTIFIER ::= { transmission number } +-- +-- where "type" is the symbolic value used for the media in +-- the ifType column of the ifTable object, and "number" is +-- the actual integer value corresponding to the symbol. + +-- the SNMP group + +-- Implementation of the SNMP group is mandatory for all +-- systems which support an SNMP protocol entity. Some of +-- the objects defined below will be zero-valued in those +-- SNMP implementations that are optimized to support only +-- those functions specific to either a management agent or +-- a management station. In particular, it should be +-- observed that the objects below refer to an SNMP entity, +-- and there may be several SNMP entities residing on a +-- managed node (e.g., if the node is hosting acting as +-- a management station). + +snmpInPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of Messages delivered to the + SNMP entity from the transport service." + ::= { snmp 1 } + +snmpOutPkts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Messages which were + passed from the SNMP protocol entity to the + transport service." + ::= { snmp 2 } + +snmpInBadVersions OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Messages which were + delivered to the SNMP protocol entity and were for + an unsupported SNMP version." + ::= { snmp 3 } + +snmpInBadCommunityNames OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Messages delivered to + the SNMP protocol entity which used a SNMP + community name not known to said entity." + ::= { snmp 4 } + +snmpInBadCommunityUses OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Messages delivered to + the SNMP protocol entity which represented an SNMP + operation which was not allowed by the SNMP + community named in the Message." + ::= { snmp 5 } + +snmpInASNParseErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of ASN.1 or BER errors + encountered by the SNMP protocol entity when + decoding received SNMP Messages." + ::= { snmp 6 } + +-- { snmp 7 } is not used + +snmpInTooBigs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + delivered to the SNMP protocol entity and for + which the value of the error-status field is + `tooBig'." + ::= { snmp 8 } + +snmpInNoSuchNames OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + delivered to the SNMP protocol entity and for + which the value of the error-status field is + `noSuchName'." + ::= { snmp 9 } + +snmpInBadValues OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + delivered to the SNMP protocol entity and for + which the value of the error-status field is + `badValue'." + ::= { snmp 10 } + +snmpInReadOnlys OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number valid SNMP PDUs which were + delivered to the SNMP protocol entity and for + which the value of the error-status field is + `readOnly'. It should be noted that it is a + protocol error to generate an SNMP PDU which + contains the value `readOnly' in the error-status + field, as such this object is provided as a means + of detecting incorrect implementations of the + + SNMP." + ::= { snmp 11 } + +snmpInGenErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + delivered to the SNMP protocol entity and for + which the value of the error-status field is + `genErr'." + ::= { snmp 12 } + +snmpInTotalReqVars OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of MIB objects which have been + retrieved successfully by the SNMP protocol entity + as the result of receiving valid SNMP Get-Request + and Get-Next PDUs." + ::= { snmp 13 } + +snmpInTotalSetVars OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of MIB objects which have been + altered successfully by the SNMP protocol entity + as the result of receiving valid SNMP Set-Request + PDUs." + ::= { snmp 14 } + +snmpInGetRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Get-Request PDUs which + have been accepted and processed by the SNMP + protocol entity." + ::= { snmp 15 } + +snmpInGetNexts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Get-Next PDUs which have + been accepted and processed by the SNMP protocol + entity." + ::= { snmp 16 } + +snmpInSetRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Set-Request PDUs which + have been accepted and processed by the SNMP + protocol entity." + ::= { snmp 17 } + +snmpInGetResponses OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Get-Response PDUs which + have been accepted and processed by the SNMP + protocol entity." + ::= { snmp 18 } + +snmpInTraps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Trap PDUs which have + been accepted and processed by the SNMP protocol + entity." + ::= { snmp 19 } + +snmpOutTooBigs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + generated by the SNMP protocol entity and for + which the value of the error-status field is + `tooBig.'" + ::= { snmp 20 } + +snmpOutNoSuchNames OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + generated by the SNMP protocol entity and for + which the value of the error-status is + `noSuchName'." + ::= { snmp 21 } + +snmpOutBadValues OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + generated by the SNMP protocol entity and for + which the value of the error-status field is + `badValue'." + ::= { snmp 22 } + +-- { snmp 23 } is not used + +snmpOutGenErrs OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP PDUs which were + generated by the SNMP protocol entity and for + which the value of the error-status field is + `genErr'." + ::= { snmp 24 } + +snmpOutGetRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Get-Request PDUs which + have been generated by the SNMP protocol entity." + ::= { snmp 25 } + +snmpOutGetNexts OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Get-Next PDUs which have + been generated by the SNMP protocol entity." + ::= { snmp 26 } + +snmpOutSetRequests OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Set-Request PDUs which + have been generated by the SNMP protocol entity." + ::= { snmp 27 } + +snmpOutGetResponses OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Get-Response PDUs which + have been generated by the SNMP protocol entity." + ::= { snmp 28 } + +snmpOutTraps OBJECT-TYPE + SYNTAX Counter + ACCESS read-only + STATUS mandatory + DESCRIPTION + "The total number of SNMP Trap PDUs which have + been generated by the SNMP protocol entity." + ::= { snmp 29 } + +snmpEnableAuthenTraps OBJECT-TYPE + SYNTAX INTEGER { enabled(1), disabled(2) } + ACCESS read-write + STATUS mandatory + DESCRIPTION + "Indicates whether the SNMP agent process is + permitted to generate authentication-failure + traps. The value of this object overrides any + configuration information; as such, it provides a + means whereby all authentication-failure traps may + be disabled. + + Note that it is strongly recommended that this + object be stored in non-volatile memory so that it + remains constant between re-initializations of the + network management system." + ::= { snmp 30 } + +END \ No newline at end of file diff --git a/internal/snmp/testdata/gosmi/tableMibImports b/internal/snmp/testdata/gosmi/tableMibImports new file mode 100644 index 0000000..1516e7c --- /dev/null +++ b/internal/snmp/testdata/gosmi/tableMibImports @@ -0,0 +1,119 @@ +RFC1155-SMI DEFINITIONS ::= BEGIN + +EXPORTS -- EVERYTHING + internet, directory, mgmt, + experimental, private, enterprises, + OBJECT-TYPE, ObjectName, ObjectSyntax, SimpleSyntax, + ApplicationSyntax, NetworkAddress, IpAddress, + Counter, Gauge, TimeTicks, Opaque; + + -- the path to the root + + internet OBJECT IDENTIFIER ::= { iso org(3) dod(6) 1 } + + directory OBJECT IDENTIFIER ::= { internet 1 } + + mgmt OBJECT IDENTIFIER ::= { internet 2 } + + experimental OBJECT IDENTIFIER ::= { internet 3 } + + private OBJECT IDENTIFIER ::= { internet 4 } + enterprises OBJECT IDENTIFIER ::= { private 1 } + + -- definition of object types + + OBJECT-TYPE MACRO ::= + BEGIN + TYPE NOTATION ::= "SYNTAX" type (TYPE ObjectSyntax) + "ACCESS" Access + "STATUS" Status + VALUE NOTATION ::= value (VALUE ObjectName) + + Access ::= "read-only" + | "read-write" + | "write-only" + | "not-accessible" + Status ::= "mandatory" + | "optional" + | "obsolete" + END + + -- names of objects in the MIB + + ObjectName ::= + OBJECT IDENTIFIER + + -- syntax of objects in the MIB + + ObjectSyntax ::= + CHOICE { + simple + SimpleSyntax, + -- note that simple SEQUENCEs are not directly + -- mentioned here to keep things simple (i.e., + -- prevent mis-use). However, application-wide + -- types which are IMPLICITly encoded simple + -- SEQUENCEs may appear in the following CHOICE + + application-wide + ApplicationSyntax + } + + SimpleSyntax ::= + CHOICE { + number + INTEGER, + string + OCTET STRING, + object + OBJECT IDENTIFIER, + empty + NULL + } + + ApplicationSyntax ::= + CHOICE { + address + NetworkAddress, + counter + Counter, + gauge + Gauge, + ticks + TimeTicks, + arbitrary + Opaque + + -- other application-wide types, as they are + -- defined, will be added here + } + + -- application-wide types + + NetworkAddress ::= + CHOICE { + internet + IpAddress + } + + IpAddress ::= + [APPLICATION 0] -- in network-byte order + IMPLICIT OCTET STRING (SIZE (4)) + + Counter ::= + [APPLICATION 1] + IMPLICIT INTEGER (0..4294967295) + + Gauge ::= + [APPLICATION 2] + IMPLICIT INTEGER (0..4294967295) + + TimeTicks ::= + [APPLICATION 3] + IMPLICIT INTEGER (0..4294967295) + + Opaque ::= + [APPLICATION 4] -- arbitrary ASN.1 value, + IMPLICIT OCTET STRING -- "double-wrapped" + + END \ No newline at end of file diff --git a/internal/snmp/testdata/gosmi/tcpMib b/internal/snmp/testdata/gosmi/tcpMib new file mode 100644 index 0000000..03c4722 --- /dev/null +++ b/internal/snmp/testdata/gosmi/tcpMib @@ -0,0 +1,786 @@ +TCP-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Integer32, Unsigned32, + Gauge32, Counter32, Counter64, IpAddress, mib-2, + MODULE-COMPLIANCE, OBJECT-GROUP, InetAddress, + InetAddressType, InetPortNumber + FROM tcpMibImports; + + + +tcpMIB MODULE-IDENTITY + LAST-UPDATED "200502180000Z" -- 18 February 2005 + ORGANIZATION + "IETF IPv6 MIB Revision Team + http://www.ietf.org/html.charters/ipv6-charter.html" + CONTACT-INFO + "Rajiv Raghunarayan (editor) + + Cisco Systems Inc. + 170 West Tasman Drive + San Jose, CA 95134 + + Phone: +1 408 853 9612 + Email: + + Send comments to " + DESCRIPTION + "The MIB module for managing TCP implementations. + + Copyright (C) The Internet Society (2005). This version + of this MIB module is a part of RFC 4022; see the RFC + itself for full legal notices." + REVISION "200502180000Z" -- 18 February 2005 + DESCRIPTION + "IP version neutral revision, published as RFC 4022." + REVISION "9411010000Z" + DESCRIPTION + "Initial SMIv2 version, published as RFC 2012." + REVISION "9103310000Z" + DESCRIPTION + "The initial revision of this MIB module was part of + MIB-II." + ::= { mib-2 49 } + +-- the TCP base variables group + +tcp OBJECT IDENTIFIER ::= { mib-2 6 } + +-- Scalars + +tcpRtoAlgorithm OBJECT-TYPE + SYNTAX INTEGER { + other(1), -- none of the following + constant(2), -- a constant rto + rsre(3), -- MIL-STD-1778, Appendix B + vanj(4), -- Van Jacobson's algorithm + rfc2988(5) -- RFC 2988 + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The algorithm used to determine the timeout value used for + retransmitting unacknowledged octets." + ::= { tcp 1 } + +tcpRtoMin OBJECT-TYPE + SYNTAX Integer32 (0..2147483647) + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The minimum value permitted by a TCP implementation for + the retransmission timeout, measured in milliseconds. + More refined semantics for objects of this type depend + on the algorithm used to determine the retransmission + timeout; in particular, the IETF standard algorithm + rfc2988(5) provides a minimum value." + ::= { tcp 2 } + +tcpRtoMax OBJECT-TYPE + SYNTAX Integer32 (0..2147483647) + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The maximum value permitted by a TCP implementation for + the retransmission timeout, measured in milliseconds. + More refined semantics for objects of this type depend + on the algorithm used to determine the retransmission + timeout; in particular, the IETF standard algorithm + rfc2988(5) provides an upper bound (as part of an + adaptive backoff algorithm)." + ::= { tcp 3 } + +tcpMaxConn OBJECT-TYPE + SYNTAX Integer32 (-1 | 0..2147483647) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The limit on the total number of TCP connections the entity + can support. In entities where the maximum number of + connections is dynamic, this object should contain the + value -1." + ::= { tcp 4 } + +tcpActiveOpens OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times that TCP connections have made a direct + transition to the SYN-SENT state from the CLOSED state. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 5 } + +tcpPassiveOpens OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times TCP connections have made a direct + transition to the SYN-RCVD state from the LISTEN state. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 6 } + +tcpAttemptFails OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times that TCP connections have made a direct + transition to the CLOSED state from either the SYN-SENT + state or the SYN-RCVD state, plus the number of times that + TCP connections have made a direct transition to the + LISTEN state from the SYN-RCVD state. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 7 } + +tcpEstabResets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times that TCP connections have made a direct + transition to the CLOSED state from either the ESTABLISHED + state or the CLOSE-WAIT state. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 8 } + +tcpCurrEstab OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of TCP connections for which the current state + is either ESTABLISHED or CLOSE-WAIT." + ::= { tcp 9 } + +tcpInSegs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of segments received, including those + received in error. This count includes segments received + on currently established connections. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 10 } + +tcpOutSegs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of segments sent, including those on + current connections but excluding those containing only + retransmitted octets. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 11 } + +tcpRetransSegs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of segments retransmitted; that is, the + number of TCP segments transmitted containing one or more + previously transmitted octets. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 12 } + +tcpInErrs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of segments received in error (e.g., bad + TCP checksums). + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 14 } + +tcpOutRsts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of TCP segments sent containing the RST flag. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 15 } + +-- { tcp 16 } was used to represent the ipv6TcpConnTable in RFC 2452, +-- which has since been obsoleted. It MUST not be used. + +tcpHCInSegs OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of segments received, including those + received in error. This count includes segments received + + on currently established connections. This object is + the 64-bit equivalent of tcpInSegs. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 17 } + +tcpHCOutSegs OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of segments sent, including those on + current connections but excluding those containing only + retransmitted octets. This object is the 64-bit + equivalent of tcpOutSegs. + + Discontinuities in the value of this counter are + indicated via discontinuities in the value of sysUpTime." + ::= { tcp 18 } + +-- The TCP Connection table + +tcpConnectionTable OBJECT-TYPE + SYNTAX SEQUENCE OF TcpConnectionEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table containing information about existing TCP + connections. Note that unlike earlier TCP MIBs, there + is a separate table for connections in the LISTEN state." + ::= { tcp 19 } + +tcpConnectionEntry OBJECT-TYPE + SYNTAX TcpConnectionEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A conceptual row of the tcpConnectionTable containing + information about a particular current TCP connection. + Each row of this table is transient in that it ceases to + exist when (or soon after) the connection makes the + transition to the CLOSED state." + INDEX { tcpConnectionLocalAddressType, + tcpConnectionLocalAddress, + tcpConnectionLocalPort, + tcpConnectionRemAddressType, + tcpConnectionRemAddress, + tcpConnectionRemPort } + ::= { tcpConnectionTable 1 } + +TcpConnectionEntry ::= SEQUENCE { + tcpConnectionLocalAddressType InetAddressType, + tcpConnectionLocalAddress InetAddress, + tcpConnectionLocalPort InetPortNumber, + tcpConnectionRemAddressType InetAddressType, + tcpConnectionRemAddress InetAddress, + tcpConnectionRemPort InetPortNumber, + tcpConnectionState INTEGER, + tcpConnectionProcess Unsigned32 + } + +tcpConnectionLocalAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The address type of tcpConnectionLocalAddress." + ::= { tcpConnectionEntry 1 } + +tcpConnectionLocalAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The local IP address for this TCP connection. The type + of this address is determined by the value of + tcpConnectionLocalAddressType. + + As this object is used in the index for the + tcpConnectionTable, implementors should be + careful not to create entries that would result in OIDs + with more than 128 subidentifiers; otherwise the information + cannot be accessed by using SNMPv1, SNMPv2c, or SNMPv3." + ::= { tcpConnectionEntry 2 } + +tcpConnectionLocalPort OBJECT-TYPE + SYNTAX InetPortNumber + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The local port number for this TCP connection." + ::= { tcpConnectionEntry 3 } + +tcpConnectionRemAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The address type of tcpConnectionRemAddress." + ::= { tcpConnectionEntry 4 } + +tcpConnectionRemAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The remote IP address for this TCP connection. The type + of this address is determined by the value of + tcpConnectionRemAddressType. + + As this object is used in the index for the + tcpConnectionTable, implementors should be + careful not to create entries that would result in OIDs + with more than 128 subidentifiers; otherwise the information + cannot be accessed by using SNMPv1, SNMPv2c, or SNMPv3." + ::= { tcpConnectionEntry 5 } + +tcpConnectionRemPort OBJECT-TYPE + SYNTAX InetPortNumber + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The remote port number for this TCP connection." + ::= { tcpConnectionEntry 6 } + +tcpConnectionState OBJECT-TYPE + SYNTAX INTEGER { + closed(1), + listen(2), + synSent(3), + synReceived(4), + established(5), + finWait1(6), + finWait2(7), + closeWait(8), + lastAck(9), + closing(10), + timeWait(11), + deleteTCB(12) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The state of this TCP connection. + + The value listen(2) is included only for parallelism to the + old tcpConnTable and should not be used. A connection in + LISTEN state should be present in the tcpListenerTable. + + The only value that may be set by a management station is + deleteTCB(12). Accordingly, it is appropriate for an agent + to return a `badValue' response if a management station + attempts to set this object to any other value. + + If a management station sets this object to the value + deleteTCB(12), then the TCB (as defined in [RFC793]) of + the corresponding connection on the managed node is + deleted, resulting in immediate termination of the + connection. + + As an implementation-specific option, a RST segment may be + sent from the managed node to the other TCP endpoint (note, + however, that RST segments are not sent reliably)." + ::= { tcpConnectionEntry 7 } + +tcpConnectionProcess OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The system's process ID for the process associated with + this connection, or zero if there is no such process. This + value is expected to be the same as HOST-RESOURCES-MIB:: + hrSWRunIndex or SYSAPPL-MIB::sysApplElmtRunIndex for some + row in the appropriate tables." + ::= { tcpConnectionEntry 8 } + +-- The TCP Listener table + +tcpListenerTable OBJECT-TYPE + SYNTAX SEQUENCE OF TcpListenerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table containing information about TCP listeners. A + listening application can be represented in three + possible ways: + + 1. An application that is willing to accept both IPv4 and + IPv6 datagrams is represented by + + a tcpListenerLocalAddressType of unknown (0) and + a tcpListenerLocalAddress of ''h (a zero-length + octet-string). + + 2. An application that is willing to accept only IPv4 or + IPv6 datagrams is represented by a + tcpListenerLocalAddressType of the appropriate address + type and a tcpListenerLocalAddress of '0.0.0.0' or '::' + respectively. + + 3. An application that is listening for data destined + only to a specific IP address, but from any remote + system, is represented by a tcpListenerLocalAddressType + of an appropriate address type, with + tcpListenerLocalAddress as the specific local address. + + NOTE: The address type in this table represents the + address type used for the communication, irrespective + of the higher-layer abstraction. For example, an + application using IPv6 'sockets' to communicate via + IPv4 between ::ffff:10.0.0.1 and ::ffff:10.0.0.2 would + use InetAddressType ipv4(1))." + ::= { tcp 20 } + +tcpListenerEntry OBJECT-TYPE + SYNTAX TcpListenerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A conceptual row of the tcpListenerTable containing + information about a particular TCP listener." + INDEX { tcpListenerLocalAddressType, + tcpListenerLocalAddress, + tcpListenerLocalPort } + ::= { tcpListenerTable 1 } + +TcpListenerEntry ::= SEQUENCE { + tcpListenerLocalAddressType InetAddressType, + tcpListenerLocalAddress InetAddress, + tcpListenerLocalPort InetPortNumber, + tcpListenerProcess Unsigned32 + } + +tcpListenerLocalAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The address type of tcpListenerLocalAddress. The value + should be unknown (0) if connection initiations to all + local IP addresses are accepted." + ::= { tcpListenerEntry 1 } + +tcpListenerLocalAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The local IP address for this TCP connection. + + The value of this object can be represented in three + possible ways, depending on the characteristics of the + listening application: + + 1. For an application willing to accept both IPv4 and + IPv6 datagrams, the value of this object must be + ''h (a zero-length octet-string), with the value + of the corresponding tcpListenerLocalAddressType + object being unknown (0). + + 2. For an application willing to accept only IPv4 or + IPv6 datagrams, the value of this object must be + '0.0.0.0' or '::' respectively, with + tcpListenerLocalAddressType representing the + appropriate address type. + + 3. For an application which is listening for data + destined only to a specific IP address, the value + of this object is the specific local address, with + tcpListenerLocalAddressType representing the + appropriate address type. + + As this object is used in the index for the + tcpListenerTable, implementors should be + careful not to create entries that would result in OIDs + with more than 128 subidentifiers; otherwise the information + cannot be accessed, using SNMPv1, SNMPv2c, or SNMPv3." + ::= { tcpListenerEntry 2 } + +tcpListenerLocalPort OBJECT-TYPE + SYNTAX InetPortNumber + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The local port number for this TCP connection." + ::= { tcpListenerEntry 3 } + +tcpListenerProcess OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The system's process ID for the process associated with + this listener, or zero if there is no such process. This + value is expected to be the same as HOST-RESOURCES-MIB:: + hrSWRunIndex or SYSAPPL-MIB::sysApplElmtRunIndex for some + row in the appropriate tables." + ::= { tcpListenerEntry 4 } + +-- The deprecated TCP Connection table + +tcpConnTable OBJECT-TYPE + SYNTAX SEQUENCE OF TcpConnEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "A table containing information about existing IPv4-specific + TCP connections or listeners. This table has been + deprecated in favor of the version neutral + tcpConnectionTable." + ::= { tcp 13 } + +tcpConnEntry OBJECT-TYPE + SYNTAX TcpConnEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "A conceptual row of the tcpConnTable containing information + about a particular current IPv4 TCP connection. Each row + of this table is transient in that it ceases to exist when + (or soon after) the connection makes the transition to the + CLOSED state." + INDEX { tcpConnLocalAddress, + tcpConnLocalPort, + tcpConnRemAddress, + tcpConnRemPort } + ::= { tcpConnTable 1 } + +TcpConnEntry ::= SEQUENCE { + tcpConnState INTEGER, + tcpConnLocalAddress IpAddress, + tcpConnLocalPort Integer32, + tcpConnRemAddress IpAddress, + tcpConnRemPort Integer32 + + } + +tcpConnState OBJECT-TYPE + SYNTAX INTEGER { + closed(1), + listen(2), + synSent(3), + synReceived(4), + established(5), + finWait1(6), + finWait2(7), + closeWait(8), + lastAck(9), + closing(10), + timeWait(11), + deleteTCB(12) + } + MAX-ACCESS read-write + STATUS deprecated + DESCRIPTION + "The state of this TCP connection. + + The only value that may be set by a management station is + deleteTCB(12). Accordingly, it is appropriate for an agent + to return a `badValue' response if a management station + attempts to set this object to any other value. + + If a management station sets this object to the value + deleteTCB(12), then the TCB (as defined in [RFC793]) of + the corresponding connection on the managed node is + deleted, resulting in immediate termination of the + connection. + + As an implementation-specific option, a RST segment may be + sent from the managed node to the other TCP endpoint (note, + however, that RST segments are not sent reliably)." + ::= { tcpConnEntry 1 } + +tcpConnLocalAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The local IP address for this TCP connection. In the case + of a connection in the listen state willing to + accept connections for any IP interface associated with the + node, the value 0.0.0.0 is used." + ::= { tcpConnEntry 2 } + +tcpConnLocalPort OBJECT-TYPE + SYNTAX Integer32 (0..65535) + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The local port number for this TCP connection." + ::= { tcpConnEntry 3 } + +tcpConnRemAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The remote IP address for this TCP connection." + ::= { tcpConnEntry 4 } + +tcpConnRemPort OBJECT-TYPE + SYNTAX Integer32 (0..65535) + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The remote port number for this TCP connection." + ::= { tcpConnEntry 5 } + +-- conformance information + +tcpMIBConformance OBJECT IDENTIFIER ::= { tcpMIB 2 } + +tcpMIBCompliances OBJECT IDENTIFIER ::= { tcpMIBConformance 1 } +tcpMIBGroups OBJECT IDENTIFIER ::= { tcpMIBConformance 2 } + +-- compliance statements + +tcpMIBCompliance2 MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for systems that implement TCP. + + A number of INDEX objects cannot be + represented in the form of OBJECT clauses in SMIv2 but + have the following compliance requirements, + expressed in OBJECT clause form in this description + clause: + + -- OBJECT tcpConnectionLocalAddressType + -- SYNTAX InetAddressType { ipv4(1), ipv6(2) } + -- DESCRIPTION + -- This MIB requires support for only global IPv4 + + -- and IPv6 address types. + -- + -- OBJECT tcpConnectionRemAddressType + -- SYNTAX InetAddressType { ipv4(1), ipv6(2) } + -- DESCRIPTION + -- This MIB requires support for only global IPv4 + -- and IPv6 address types. + -- + -- OBJECT tcpListenerLocalAddressType + -- SYNTAX InetAddressType { unknown(0), ipv4(1), + -- ipv6(2) } + -- DESCRIPTION + -- This MIB requires support for only global IPv4 + -- and IPv6 address types. The type unknown also + -- needs to be supported to identify a special + -- case in the listener table: a listen using + -- both IPv4 and IPv6 addresses on the device. + -- + " + MODULE -- this module + MANDATORY-GROUPS { tcpBaseGroup, tcpConnectionGroup, + tcpListenerGroup } + GROUP tcpHCGroup + DESCRIPTION + "This group is mandatory for systems that are capable + of receiving or transmitting more than 1 million TCP + segments per second. 1 million segments per second will + cause a Counter32 to wrap in just over an hour." + OBJECT tcpConnectionState + SYNTAX INTEGER { closed(1), listen(2), synSent(3), + synReceived(4), established(5), + finWait1(6), finWait2(7), closeWait(8), + lastAck(9), closing(10), timeWait(11) } + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required, nor is support for the value + deleteTCB (12)." + ::= { tcpMIBCompliances 2 } + +tcpMIBCompliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement for IPv4-only systems that + implement TCP. In order to be IP version independent, this + compliance statement is deprecated in favor of + tcpMIBCompliance2. However, agents are still encouraged + to implement these objects in order to interoperate with + the deployed base of managers." + + MODULE -- this module + MANDATORY-GROUPS { tcpGroup } + OBJECT tcpConnState + MIN-ACCESS read-only + DESCRIPTION + "Write access is not required." + ::= { tcpMIBCompliances 1 } + +-- units of conformance + +tcpGroup OBJECT-GROUP + OBJECTS { tcpRtoAlgorithm, tcpRtoMin, tcpRtoMax, + tcpMaxConn, tcpActiveOpens, + tcpPassiveOpens, tcpAttemptFails, + tcpEstabResets, tcpCurrEstab, tcpInSegs, + tcpOutSegs, tcpRetransSegs, tcpConnState, + tcpConnLocalAddress, tcpConnLocalPort, + tcpConnRemAddress, tcpConnRemPort, + tcpInErrs, tcpOutRsts } + STATUS deprecated + DESCRIPTION + "The tcp group of objects providing for management of TCP + entities." + ::= { tcpMIBGroups 1 } + +tcpBaseGroup OBJECT-GROUP + OBJECTS { tcpRtoAlgorithm, tcpRtoMin, tcpRtoMax, + tcpMaxConn, tcpActiveOpens, + tcpPassiveOpens, tcpAttemptFails, + tcpEstabResets, tcpCurrEstab, tcpInSegs, + tcpOutSegs, tcpRetransSegs, + tcpInErrs, tcpOutRsts } + STATUS current + DESCRIPTION + "The group of counters common to TCP entities." + ::= { tcpMIBGroups 2 } + +tcpConnectionGroup OBJECT-GROUP + OBJECTS { tcpConnectionState, tcpConnectionProcess } + STATUS current + DESCRIPTION + "The group provides general information about TCP + connections." + ::= { tcpMIBGroups 3 } + +tcpListenerGroup OBJECT-GROUP + OBJECTS { tcpListenerProcess } + STATUS current + DESCRIPTION + "This group has objects providing general information about + TCP listeners." + ::= { tcpMIBGroups 4 } + +tcpHCGroup OBJECT-GROUP + OBJECTS { tcpHCInSegs, tcpHCOutSegs } + STATUS current + DESCRIPTION + "The group of objects providing for counters of high speed + TCP implementations." + ::= { tcpMIBGroups 5 } + +END diff --git a/internal/snmp/testdata/gosmi/tcpMibImports b/internal/snmp/testdata/gosmi/tcpMibImports new file mode 100644 index 0000000..f3b6b9d --- /dev/null +++ b/internal/snmp/testdata/gosmi/tcpMibImports @@ -0,0 +1,639 @@ +SNMPv2-SMI DEFINITIONS ::= BEGIN + +-- the path to the root + +org OBJECT IDENTIFIER ::= { iso 3 } -- "iso" = 1 +dod OBJECT IDENTIFIER ::= { org 6 } +internet OBJECT IDENTIFIER ::= { dod 1 } + +directory OBJECT IDENTIFIER ::= { internet 1 } + +mgmt OBJECT IDENTIFIER ::= { internet 2 } +mib-2 OBJECT IDENTIFIER ::= { mgmt 1 } +transmission OBJECT IDENTIFIER ::= { mib-2 10 } + +experimental OBJECT IDENTIFIER ::= { internet 3 } + +private OBJECT IDENTIFIER ::= { internet 4 } +enterprises OBJECT IDENTIFIER ::= { private 1 } + +security OBJECT IDENTIFIER ::= { internet 5 } + +snmpV2 OBJECT IDENTIFIER ::= { internet 6 } + +-- transport domains +snmpDomains OBJECT IDENTIFIER ::= { snmpV2 1 } + +-- transport proxies +snmpProxys OBJECT IDENTIFIER ::= { snmpV2 2 } + +-- module identities +snmpModules OBJECT IDENTIFIER ::= { snmpV2 3 } + +-- Extended UTCTime, to allow dates with four-digit years +-- (Note that this definition of ExtUTCTime is not to be IMPORTed +-- by MIB modules.) +ExtUTCTime ::= OCTET STRING(SIZE(11 | 13)) + -- format is YYMMDDHHMMZ or YYYYMMDDHHMMZ + + -- where: YY - last two digits of year (only years + -- between 1900-1999) + -- YYYY - last four digits of the year (any year) + -- MM - month (01 through 12) + -- DD - day of month (01 through 31) + -- HH - hours (00 through 23) + -- MM - minutes (00 through 59) + -- Z - denotes GMT (the ASCII character Z) + -- + -- For example, "9502192015Z" and "199502192015Z" represent + -- 8:15pm GMT on 19 February 1995. Years after 1999 must use + -- the four digit year format. Years 1900-1999 may use the + -- two or four digit format. + +-- definitions for information modules + +MODULE-IDENTITY MACRO ::= +BEGIN + TYPE NOTATION ::= + "LAST-UPDATED" value(Update ExtUTCTime) + "ORGANIZATION" Text + "CONTACT-INFO" Text + "DESCRIPTION" Text + RevisionPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + RevisionPart ::= + Revisions + | empty + Revisions ::= + Revision + | Revisions Revision + Revision ::= + "REVISION" value(Update ExtUTCTime) + "DESCRIPTION" Text + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +OBJECT-IDENTITY MACRO ::= +BEGIN + TYPE NOTATION ::= + "STATUS" Status + "DESCRIPTION" Text + + ReferPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +-- names of objects +-- (Note that these definitions of ObjectName and NotificationName +-- are not to be IMPORTed by MIB modules.) + +ObjectName ::= + OBJECT IDENTIFIER + +NotificationName ::= + OBJECT IDENTIFIER + +-- syntax of objects + +-- the "base types" defined here are: +-- 3 built-in ASN.1 types: INTEGER, OCTET STRING, OBJECT IDENTIFIER +-- 8 application-defined types: Integer32, IpAddress, Counter32, +-- Gauge32, Unsigned32, TimeTicks, Opaque, and Counter64 + +ObjectSyntax ::= + CHOICE { + simple + SimpleSyntax, + -- note that SEQUENCEs for conceptual tables and + -- rows are not mentioned here... + + application-wide + ApplicationSyntax + } + +-- built-in ASN.1 types + +SimpleSyntax ::= + CHOICE { + -- INTEGERs with a more restrictive range + -- may also be used + integer-value -- includes Integer32 + INTEGER (-2147483648..2147483647), + -- OCTET STRINGs with a more restrictive size + -- may also be used + string-value + OCTET STRING (SIZE (0..65535)), + objectID-value + OBJECT IDENTIFIER + } + +-- indistinguishable from INTEGER, but never needs more than +-- 32-bits for a two's complement representation +Integer32 ::= + INTEGER (-2147483648..2147483647) + +-- application-wide types + +ApplicationSyntax ::= + CHOICE { + ipAddress-value + IpAddress, + counter-value + Counter32, + timeticks-value + TimeTicks, + arbitrary-value + Opaque, + big-counter-value + Counter64, + unsigned-integer-value -- includes Gauge32 + Unsigned32 + } + +-- in network-byte order + +-- (this is a tagged type for historical reasons) +IpAddress ::= + [APPLICATION 0] + IMPLICIT OCTET STRING (SIZE (4)) + +-- this wraps +Counter32 ::= + [APPLICATION 1] + IMPLICIT INTEGER (0..4294967295) + +-- this doesn't wrap +Gauge32 ::= + [APPLICATION 2] + IMPLICIT INTEGER (0..4294967295) + +-- an unsigned 32-bit quantity +-- indistinguishable from Gauge32 +Unsigned32 ::= + [APPLICATION 2] + IMPLICIT INTEGER (0..4294967295) + +-- hundredths of seconds since an epoch +TimeTicks ::= + [APPLICATION 3] + IMPLICIT INTEGER (0..4294967295) + +-- for backward-compatibility only +Opaque ::= + [APPLICATION 4] + IMPLICIT OCTET STRING + +-- for counters that wrap in less than one hour with only 32 bits +Counter64 ::= + [APPLICATION 6] + IMPLICIT INTEGER (0..18446744073709551615) + +-- definition for objects + +OBJECT-TYPE MACRO ::= +BEGIN + TYPE NOTATION ::= + "SYNTAX" Syntax + UnitsPart + "MAX-ACCESS" Access + "STATUS" Status + "DESCRIPTION" Text + ReferPart + + IndexPart + DefValPart + + VALUE NOTATION ::= + value(VALUE ObjectName) + + Syntax ::= -- Must be one of the following: + -- a base type (or its refinement), + -- a textual convention (or its refinement), or + -- a BITS pseudo-type + type + | "BITS" "{" NamedBits "}" + + NamedBits ::= NamedBit + | NamedBits "," NamedBit + + NamedBit ::= identifier "(" number ")" -- number is nonnegative + + UnitsPart ::= + "UNITS" Text + | empty + + Access ::= + "not-accessible" + | "accessible-for-notify" + | "read-only" + | "read-write" + | "read-create" + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + IndexPart ::= + "INDEX" "{" IndexTypes "}" + | "AUGMENTS" "{" Entry "}" + | empty + IndexTypes ::= + IndexType + | IndexTypes "," IndexType + IndexType ::= + "IMPLIED" Index + | Index + + Index ::= + -- use the SYNTAX value of the + -- correspondent OBJECT-TYPE invocation + value(ObjectName) + Entry ::= + -- use the INDEX value of the + -- correspondent OBJECT-TYPE invocation + value(ObjectName) + + DefValPart ::= "DEFVAL" "{" Defvalue "}" + | empty + + Defvalue ::= -- must be valid for the type specified in + -- SYNTAX clause of same OBJECT-TYPE macro + value(ObjectSyntax) + | "{" BitsValue "}" + + BitsValue ::= BitNames + | empty + + BitNames ::= BitName + | BitNames "," BitName + + BitName ::= identifier + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +-- definitions for notifications + +NOTIFICATION-TYPE MACRO ::= +BEGIN + TYPE NOTATION ::= + ObjectsPart + "STATUS" Status + "DESCRIPTION" Text + ReferPart + + VALUE NOTATION ::= + value(VALUE NotificationName) + + ObjectsPart ::= + "OBJECTS" "{" Objects "}" + | empty + Objects ::= + Object + + | Objects "," Object + Object ::= + value(ObjectName) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in section 3.1.1 + Text ::= value(IA5String) +END + +-- definitions of administrative identifiers + +zeroDotZero OBJECT-IDENTITY + STATUS current + DESCRIPTION + "A value used for null identifiers." + ::= { 0 0 } + + + +TEXTUAL-CONVENTION MACRO ::= + +BEGIN + TYPE NOTATION ::= + DisplayPart + "STATUS" Status + "DESCRIPTION" Text + ReferPart + "SYNTAX" Syntax + + VALUE NOTATION ::= + value(VALUE Syntax) -- adapted ASN.1 + + DisplayPart ::= + "DISPLAY-HINT" Text + | empty + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in [2] + Text ::= value(IA5String) + + Syntax ::= -- Must be one of the following: + -- a base type (or its refinement), or + -- a BITS pseudo-type + type + | "BITS" "{" NamedBits "}" + + NamedBits ::= NamedBit + | NamedBits "," NamedBit + + NamedBit ::= identifier "(" number ")" -- number is nonnegative + +END + +MODULE-COMPLIANCE MACRO ::= +BEGIN + TYPE NOTATION ::= + "STATUS" Status + "DESCRIPTION" Text + ReferPart + ModulePart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + ModulePart ::= + Modules + Modules ::= + Module + | Modules Module + Module ::= + -- name of module -- + "MODULE" ModuleName + MandatoryPart + CompliancePart + + ModuleName ::= + -- identifier must start with uppercase letter + identifier ModuleIdentifier + -- must not be empty unless contained + -- in MIB Module + | empty + ModuleIdentifier ::= + value(OBJECT IDENTIFIER) + | empty + + MandatoryPart ::= + "MANDATORY-GROUPS" "{" Groups "}" + | empty + + Groups ::= + + Group + | Groups "," Group + Group ::= + value(OBJECT IDENTIFIER) + + CompliancePart ::= + Compliances + | empty + + Compliances ::= + Compliance + | Compliances Compliance + Compliance ::= + ComplianceGroup + | Object + + ComplianceGroup ::= + "GROUP" value(OBJECT IDENTIFIER) + "DESCRIPTION" Text + + Object ::= + "OBJECT" value(ObjectName) + SyntaxPart + WriteSyntaxPart + AccessPart + "DESCRIPTION" Text + + -- must be a refinement for object's SYNTAX clause + SyntaxPart ::= "SYNTAX" Syntax + | empty + + -- must be a refinement for object's SYNTAX clause + WriteSyntaxPart ::= "WRITE-SYNTAX" Syntax + | empty + + Syntax ::= -- Must be one of the following: + -- a base type (or its refinement), + -- a textual convention (or its refinement), or + -- a BITS pseudo-type + type + | "BITS" "{" NamedBits "}" + + NamedBits ::= NamedBit + | NamedBits "," NamedBit + + NamedBit ::= identifier "(" number ")" -- number is nonnegative + + AccessPart ::= + "MIN-ACCESS" Access + | empty + Access ::= + "not-accessible" + | "accessible-for-notify" + | "read-only" + | "read-write" + | "read-create" + + -- a character string as defined in [2] + Text ::= value(IA5String) +END + +OBJECT-GROUP MACRO ::= +BEGIN + TYPE NOTATION ::= + ObjectsPart + "STATUS" Status + "DESCRIPTION" Text + ReferPart + + VALUE NOTATION ::= + value(VALUE OBJECT IDENTIFIER) + + ObjectsPart ::= + "OBJECTS" "{" Objects "}" + Objects ::= + Object + | Objects "," Object + Object ::= + + value(ObjectName) + + Status ::= + "current" + | "deprecated" + | "obsolete" + + ReferPart ::= + "REFERENCE" Text + | empty + + -- a character string as defined in [2] + Text ::= value(IA5String) +END + +InetPortNumber ::= TEXTUAL-CONVENTION + DISPLAY-HINT "d" + STATUS current + DESCRIPTION + "Represents a 16 bit port number of an Internet transport + + layer protocol. Port numbers are assigned by IANA. A + current list of all assignments is available from + . + + The value zero is object-specific and must be defined as + part of the description of any object that uses this + syntax. Examples of the usage of zero might include + situations where a port number is unknown, or when the + value zero is used as a wildcard in a filter." + REFERENCE "STD 6 (RFC 768), STD 7 (RFC 793) and RFC 2960" + SYNTAX Unsigned32 (0..65535) + + +InetAddress ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Denotes a generic Internet address. + + An InetAddress value is always interpreted within the context + of an InetAddressType value. Every usage of the InetAddress + textual convention is required to specify the InetAddressType + object that provides the context. It is suggested that the + InetAddressType object be logically registered before the + object(s) that use the InetAddress textual convention, if + they appear in the same logical row. + + The value of an InetAddress object must always be + consistent with the value of the associated InetAddressType + object. Attempts to set an InetAddress object to a value + inconsistent with the associated InetAddressType + must fail with an inconsistentValue error. + + When this textual convention is used as the syntax of an + index object, there may be issues with the limit of 128 + sub-identifiers specified in SMIv2, STD 58. In this case, + the object definition MUST include a 'SIZE' clause to + limit the number of potential instance sub-identifiers; + otherwise the applicable constraints MUST be stated in + the appropriate conceptual row DESCRIPTION clauses, or + in the surrounding documentation if there is no single + DESCRIPTION clause that is appropriate." + SYNTAX OCTET STRING (SIZE (0..255)) + +InetAddressType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A value that represents a type of Internet address. + + unknown(0) An unknown address type. This value MUST + be used if the value of the corresponding + InetAddress object is a zero-length string. + It may also be used to indicate an IP address + that is not in one of the formats defined + below. + + ipv4(1) An IPv4 address as defined by the + InetAddressIPv4 textual convention. + + ipv6(2) An IPv6 address as defined by the + InetAddressIPv6 textual convention. + + ipv4z(3) A non-global IPv4 address including a zone + index as defined by the InetAddressIPv4z + textual convention. + + ipv6z(4) A non-global IPv6 address including a zone + index as defined by the InetAddressIPv6z + textual convention. + + dns(16) A DNS domain name as defined by the + InetAddressDNS textual convention. + + Each definition of a concrete InetAddressType value must be + accompanied by a definition of a textual convention for use + with that InetAddressType. + + To support future extensions, the InetAddressType textual + convention SHOULD NOT be sub-typed in object type definitions. + It MAY be sub-typed in compliance statements in order to + require only a subset of these address types for a compliant + implementation. + + Implementations must ensure that InetAddressType objects + and any dependent objects (e.g., InetAddress objects) are + consistent. An inconsistentValue error must be generated + if an attempt to change an InetAddressType object would, + for example, lead to an undefined InetAddress value. In + + particular, InetAddressType/InetAddress pairs must be + changed together if the address type changes (e.g., from + ipv6(2) to ipv4(1))." + SYNTAX INTEGER { + unknown(0), + ipv4(1), + ipv6(2), + ipv4z(3), + ipv6z(4), + dns(16) + } + + + + + +END \ No newline at end of file diff --git a/internal/snmp/testdata/loadMibsFromPath/linkTarget/emptyFile b/internal/snmp/testdata/loadMibsFromPath/linkTarget/emptyFile new file mode 100644 index 0000000..e69de29 diff --git a/internal/snmp/testdata/loadMibsFromPath/root/dirOne/dirTwo/empty b/internal/snmp/testdata/loadMibsFromPath/root/dirOne/dirTwo/empty new file mode 100644 index 0000000..e69de29 diff --git a/internal/snmp/testdata/loadMibsFromPath/root/symlink b/internal/snmp/testdata/loadMibsFromPath/root/symlink new file mode 120000 index 0000000..a10e5b8 --- /dev/null +++ b/internal/snmp/testdata/loadMibsFromPath/root/symlink @@ -0,0 +1 @@ +../linkTarget/ \ No newline at end of file diff --git a/internal/snmp/testdata/mibs/testmib b/internal/snmp/testdata/mibs/testmib new file mode 100644 index 0000000..ce44a13 --- /dev/null +++ b/internal/snmp/testdata/mibs/testmib @@ -0,0 +1,22 @@ +TGTEST-MIB DEFINITIONS ::= BEGIN + +org OBJECT IDENTIFIER ::= { iso 3 } -- "iso" = 1 +dod OBJECT IDENTIFIER ::= { org 6 } +internet OBJECT IDENTIFIER ::= { dod 1 } +mgmt OBJECT IDENTIFIER ::= { internet 2 } +mibs OBJECT IDENTIFIER ::= { mgmt 1 } +system OBJECT IDENTIFIER ::= { mibs 1 } +systemUpTime OBJECT IDENTIFIER ::= { system 3 } +sysUpTimeInstance OBJECT IDENTIFIER ::= { systemUpTime 0 } + +private OBJECT IDENTIFIER ::= { internet 4 } +enterprises OBJECT IDENTIFIER ::= { private 1 } + +snmpV2 OBJECT IDENTIFIER ::= { internet 6 } +snmpModules OBJECT IDENTIFIER ::= { snmpV2 3 } +snmpMIB OBJECT IDENTIFIER ::= { snmpModules 1 } +snmpMIBObjects OBJECT IDENTIFIER ::= { snmpMIB 1 } +snmpTraps OBJECT IDENTIFIER ::= { snmpMIBObjects 5 } +coldStart OBJECT IDENTIFIER ::= { snmpTraps 1 } + +END diff --git a/internal/snmp/translator.go b/internal/snmp/translator.go new file mode 100644 index 0000000..3bf2257 --- /dev/null +++ b/internal/snmp/translator.go @@ -0,0 +1,29 @@ +package snmp + +type TranslatorPlugin interface { + SetTranslator(name string) // Agent calls this on inputs before Init +} + +type Translator interface { + SnmpTranslate(oid string) ( + mibName string, oidNum string, oidText string, + conversion string, + err error, + ) + + SnmpTable(oid string) ( + mibName string, oidNum string, oidText string, + fields []Field, + err error, + ) + + SnmpFormatEnum(oid string, value interface{}, full bool) ( + formatted string, + err error, + ) + + SnmpFormatDisplayHint(oid string, value interface{}) ( + formatted string, + err error, + ) +} diff --git a/internal/snmp/translator_gosmi.go b/internal/snmp/translator_gosmi.go new file mode 100644 index 0000000..0a2f27b --- /dev/null +++ b/internal/snmp/translator_gosmi.go @@ -0,0 +1,240 @@ +package snmp + +import ( + "errors" + "fmt" + "strings" + + "github.com/sleepinggenius2/gosmi" + "github.com/sleepinggenius2/gosmi/models" + "github.com/sleepinggenius2/gosmi/types" + + "github.com/influxdata/telegraf" +) + +var errCannotFormatUnkownType = errors.New("cannot format value, unknown type") + +type gosmiTranslator struct { +} + +func NewGosmiTranslator(paths []string, log telegraf.Logger) (*gosmiTranslator, error) { + err := LoadMibsFromPath(paths, log, &GosmiMibLoader{}) + if err == nil { + return &gosmiTranslator{}, nil + } + return nil, err +} + +//nolint:revive //function-result-limit conditionally 5 return results allowed +func (g *gosmiTranslator) SnmpTranslate(oid string) (mibName string, oidNum string, oidText string, conversion string, err error) { + mibName, oidNum, oidText, conversion, _, err = snmpTranslateCall(oid) + return mibName, oidNum, oidText, conversion, err +} + +// snmpTable resolves the given OID as a table, providing information about the +// table and fields within. +// +//nolint:revive //Too many return variable but necessary +func (g *gosmiTranslator) SnmpTable(oid string) ( + mibName string, oidNum string, oidText string, + fields []Field, + err error) { + mibName, oidNum, oidText, _, node, err := snmpTranslateCall(oid) + if err != nil { + return "", "", "", nil, fmt.Errorf("translating: %w", err) + } + + mibPrefix := mibName + "::" + + col, tagOids := getIndex(mibPrefix, node) + for _, c := range col { + _, isTag := tagOids[mibPrefix+c] + fields = append(fields, Field{Name: c, Oid: mibPrefix + c, IsTag: isTag}) + } + + return mibName, oidNum, oidText, fields, nil +} + +func (*gosmiTranslator) SnmpFormatEnum(oid string, value interface{}, full bool) (string, error) { + if value == nil { + return "", nil + } + + //nolint:dogsled // only need to get the node + _, _, _, _, node, err := snmpTranslateCall(oid) + if err != nil { + return "", err + } + + if node.Type == nil { + return "", errCannotFormatUnkownType + } + + var v models.Value + if full { + v = node.FormatValue(value, models.FormatEnumName, models.FormatEnumValue) + } else { + v = node.FormatValue(value, models.FormatEnumName) + } + + return v.String(), nil +} + +func (*gosmiTranslator) SnmpFormatDisplayHint(oid string, value interface{}) (string, error) { + if value == nil { + return "", nil + } + + //nolint:dogsled // only need to get the node + _, _, _, _, node, err := snmpTranslateCall(oid) + if err != nil { + return "", err + } + + if node.Type == nil { + return "", errCannotFormatUnkownType + } + + return node.FormatValue(value).String(), nil +} + +func getIndex(mibPrefix string, node gosmi.SmiNode) (col []string, tagOids map[string]struct{}) { + // first attempt to get the table's tags + // mimcks grabbing INDEX {} that is returned from snmptranslate -Td MibName + indices := node.GetIndex() + tagOids = make(map[string]struct{}, len(indices)) + for _, index := range indices { + tagOids[mibPrefix+index.Name] = struct{}{} + } + + // grabs all columns from the table + // mimmicks grabbing everything returned from snmptable -Ch -Cl -c public 127.0.0.1 oidFullName + _, col = node.GetColumns() + + return col, tagOids +} + +//nolint:revive //Too many return variable but necessary +func snmpTranslateCall(oid string) (mibName string, oidNum string, oidText string, conversion string, node gosmi.SmiNode, err error) { + var out gosmi.SmiNode + var end string + if strings.ContainsAny(oid, "::") { + // split given oid + // for example RFC1213-MIB::sysUpTime.0 + s := strings.SplitN(oid, "::", 2) + // moduleName becomes RFC1213 + moduleName := s[0] + module, err := gosmi.GetModule(moduleName) + if err != nil { + return oid, oid, oid, "", gosmi.SmiNode{}, err + } + if s[1] == "" { + return "", oid, oid, "", gosmi.SmiNode{}, fmt.Errorf("cannot parse %v", oid) + } + // node becomes sysUpTime.0 + node := s[1] + if strings.ContainsAny(node, ".") { + s = strings.SplitN(node, ".", 2) + // node becomes sysUpTime + node = s[0] + end = "." + s[1] + } + + out, err = module.GetNode(node) + if err != nil { + return oid, oid, oid, "", out, err + } + + if oidNum = out.RenderNumeric(); oidNum == "" { + return oid, oid, oid, "", out, fmt.Errorf("cannot translate %v into a numeric OID, please ensure all imported MIBs are in the path", oid) + } + + oidNum = "." + oidNum + end + } else if strings.ContainsAny(oid, "abcdefghijklnmopqrstuvwxyz") { + //handle mixed oid ex. .iso.2.3 + s := strings.Split(oid, ".") + for i := range s { + if strings.ContainsAny(s[i], "abcdefghijklmnopqrstuvwxyz") { + out, err = gosmi.GetNode(s[i]) + if err != nil { + return oid, oid, oid, "", out, err + } + s[i] = out.RenderNumeric() + } + } + oidNum = strings.Join(s, ".") + out, err = gosmi.GetNodeByOID(types.OidMustFromString(oidNum)) + if err != nil { + return oid, oid, oid, "", out, err + } + } else { + out, err = gosmi.GetNodeByOID(types.OidMustFromString(oid)) + oidNum = oid + // ensure modules are loaded or node will be empty (might not error) + //nolint:nilerr // do not return the err as the oid is numeric and telegraf can continue + if err != nil || out.Name == "iso" { + return oid, oid, oid, "", out, nil + } + } + + tc := out.GetSubtree() + for i := range tc { + // case where the mib doesn't have a conversion so Type struct will be nil + // prevents seg fault + if tc[i].Type == nil { + break + } + + if tc[i].Type.Format != "" { + conversion = "displayhint" + } else { + switch tc[i].Type.Name { + case "InetAddress", "IPSIpAddress": + conversion = "ipaddr" + } + } + } + + oidText = out.RenderQualified() + i := strings.Index(oidText, "::") + if i == -1 { + return "", oid, oid, "", out, errors.New("not found") + } + mibName = oidText[:i] + oidText = oidText[i+2:] + end + + return mibName, oidNum, oidText, conversion, out, nil +} + +// The following is for snmp_trap +type MibEntry struct { + MibName string + OidText string +} + +func TrapLookup(oid string) (e MibEntry, err error) { + var givenOid types.Oid + if givenOid, err = types.OidFromString(oid); err != nil { + return e, fmt.Errorf("could not convert OID %s: %w", oid, err) + } + + // Get node name + var node gosmi.SmiNode + if node, err = gosmi.GetNodeByOID(givenOid); err != nil { + return e, err + } + e.OidText = node.Name + + // Add not found OID part + if !givenOid.Equals(node.Oid) { + e.OidText += "." + givenOid[len(node.Oid):].String() + } + + // Get module name + module := node.GetModule() + if module.Name != "" { + e.MibName = module.Name + } + + return e, nil +} diff --git a/internal/snmp/translator_gosmi_test.go b/internal/snmp/translator_gosmi_test.go new file mode 100644 index 0000000..123ca11 --- /dev/null +++ b/internal/snmp/translator_gosmi_test.go @@ -0,0 +1,728 @@ +package snmp + +import ( + "path/filepath" + "testing" + + "github.com/gosnmp/gosnmp" + "github.com/stretchr/testify/require" + + "github.com/influxdata/telegraf/testutil" +) + +func getGosmiTr(t *testing.T) Translator { + testDataPath, err := filepath.Abs("./testdata/gosmi") + require.NoError(t, err) + + tr, err := NewGosmiTranslator([]string{testDataPath}, testutil.Logger{}) + require.NoError(t, err) + return tr +} + +func TestGosmiTranslator(t *testing.T) { + var tr Translator + var err error + + tr, err = NewGosmiTranslator([]string{"testdata"}, testutil.Logger{}) + require.NoError(t, err) + require.NotNil(t, tr) +} + +func TestFieldInitGosmi(t *testing.T) { + tr := getGosmiTr(t) + + translations := []struct { + inputOid string + inputName string + inputConversion string + expectedOid string + expectedName string + expectedConversion string + }{ + {".1.2.3", "foo", "", ".1.2.3", "foo", ""}, + {".iso.2.3", "foo", "", ".1.2.3", "foo", ""}, + {".1.0.0.0.1.1", "", "", ".1.0.0.0.1.1", "server", ""}, + {".1.0.0.0.1.5", "", "", ".1.0.0.0.1.5", "dateAndTime", "displayhint"}, + {"IF-MIB::ifPhysAddress.1", "", "", ".1.3.6.1.2.1.2.2.1.6.1", "ifPhysAddress.1", "displayhint"}, + {"IF-MIB::ifPhysAddress.1", "", "none", ".1.3.6.1.2.1.2.2.1.6.1", "ifPhysAddress.1", "none"}, + {"BRIDGE-MIB::dot1dTpFdbAddress.1", "", "", ".1.3.6.1.2.1.17.4.3.1.1.1", "dot1dTpFdbAddress.1", "displayhint"}, + {"TCP-MIB::tcpConnectionLocalAddress.1", "", "", ".1.3.6.1.2.1.6.19.1.2.1", "tcpConnectionLocalAddress.1", "ipaddr"}, + {".999", "", "", ".999", ".999", ""}, + } + + for _, txl := range translations { + f := Field{Oid: txl.inputOid, Name: txl.inputName, Conversion: txl.inputConversion} + require.NoError(t, f.Init(tr), "inputOid=%q inputName=%q", txl.inputOid, txl.inputName) + + require.Equal(t, txl.expectedOid, f.Oid, "inputOid=%q inputName=%q inputConversion=%q", txl.inputOid, txl.inputName, txl.inputConversion) + require.Equal(t, txl.expectedName, f.Name, "inputOid=%q inputName=%q inputConversion=%q", txl.inputOid, txl.inputName, txl.inputConversion) + require.Equal(t, txl.expectedConversion, f.Conversion, "inputOid=%q inputName=%q inputConversion=%q", txl.inputOid, txl.inputName, txl.inputConversion) + } +} + +func TestTableInitGosmi(t *testing.T) { + tbl := Table{ + Oid: ".1.3.6.1.2.1.3.1", + Fields: []Field{ + {Oid: ".999", Name: "foo"}, + {Oid: ".1.3.6.1.2.1.3.1.1.1", Name: "atIfIndex", IsTag: true}, + {Oid: "RFC1213-MIB::atPhysAddress", Name: "atPhysAddress"}, + }, + } + + tr := getGosmiTr(t) + require.NoError(t, tbl.Init(tr)) + + require.Equal(t, "atTable", tbl.Name) + + require.Len(t, tbl.Fields, 5) + + require.Equal(t, ".999", tbl.Fields[0].Oid) + require.Equal(t, "foo", tbl.Fields[0].Name) + require.False(t, tbl.Fields[0].IsTag) + require.Empty(t, tbl.Fields[0].Conversion) + + require.Equal(t, ".1.3.6.1.2.1.3.1.1.1", tbl.Fields[1].Oid) + require.Equal(t, "atIfIndex", tbl.Fields[1].Name) + require.True(t, tbl.Fields[1].IsTag) + require.Empty(t, tbl.Fields[1].Conversion) + + require.Equal(t, ".1.3.6.1.2.1.3.1.1.2", tbl.Fields[2].Oid) + require.Equal(t, "atPhysAddress", tbl.Fields[2].Name) + require.False(t, tbl.Fields[2].IsTag) + require.Equal(t, "displayhint", tbl.Fields[2].Conversion) + + require.Equal(t, ".1.3.6.1.2.1.3.1.1.3", tbl.Fields[4].Oid) + require.Equal(t, "atNetAddress", tbl.Fields[4].Name) + require.True(t, tbl.Fields[4].IsTag) + require.Empty(t, tbl.Fields[4].Conversion) +} + +// TestTableBuild_walk in snmp_test.go is split into two tests here, +// noTranslate and Translate. +// +// This is only running with gosmi translator but should be valid with +// netsnmp too. +func TestTableBuild_walk_noTranslate(t *testing.T) { + tbl := Table{ + Name: "mytable", + IndexAsTag: true, + Fields: []Field{ + { + Name: "myfield1", + Oid: ".1.0.0.0.1.1", + IsTag: true, + }, + { + Name: "myfield2", + Oid: ".1.0.0.0.1.2", + }, + { + Name: "myfield3", + Oid: ".1.0.0.0.1.3", + Conversion: "float", + }, + { + Name: "myfield4", + Oid: ".1.0.0.2.1.5", + OidIndexSuffix: ".9.9", + }, + { + Name: "myfield5", + Oid: ".1.0.0.2.1.5", + OidIndexLength: 1, + }, + }, + } + + tb, err := tbl.Build(tsc, true) + require.NoError(t, err) + require.Equal(t, "mytable", tb.Name) + rtr1 := RTableRow{ + Tags: map[string]string{ + "myfield1": "foo", + "index": "0", + }, + Fields: map[string]interface{}{ + "myfield2": 1, + "myfield3": float64(0.123), + "myfield4": 11, + "myfield5": 11, + }, + } + rtr2 := RTableRow{ + Tags: map[string]string{ + "myfield1": "bar", + "index": "1", + }, + Fields: map[string]interface{}{ + "myfield2": 2, + "myfield3": float64(0.456), + "myfield4": 22, + "myfield5": 22, + }, + } + rtr3 := RTableRow{ + Tags: map[string]string{ + "index": "2", + }, + Fields: map[string]interface{}{ + "myfield2": 0, + "myfield3": float64(0.0), + }, + } + rtr4 := RTableRow{ + Tags: map[string]string{ + "index": "3", + }, + Fields: map[string]interface{}{ + "myfield3": float64(9.999), + }, + } + require.Len(t, tb.Rows, 4) + require.Contains(t, tb.Rows, rtr1) + require.Contains(t, tb.Rows, rtr2) + require.Contains(t, tb.Rows, rtr3) + require.Contains(t, tb.Rows, rtr4) +} + +func TestTableBuild_walk_Translate(t *testing.T) { + tbl := Table{ + Name: "atTable", + IndexAsTag: true, + Fields: []Field{ + { + Name: "ifIndex", + Oid: "1.3.6.1.2.1.3.1.1.1", + IsTag: true, + }, + { + Name: "atPhysAddress", + Oid: "1.3.6.1.2.1.3.1.1.2", + Translate: false, + }, + { + Name: "atNetAddress", + Oid: "1.3.6.1.2.1.3.1.1.3", + Translate: true, + }, + }, + } + + require.NoError(t, tbl.Init(getGosmiTr(t))) + tb, err := tbl.Build(tsc, true) + require.NoError(t, err) + + require.Equal(t, "atTable", tb.Name) + + rtr1 := RTableRow{ + Tags: map[string]string{ + "ifIndex": "foo", + "index": "0", + }, + Fields: map[string]interface{}{ + "atPhysAddress": 1, + "atNetAddress": "atNetAddress", + }, + } + rtr2 := RTableRow{ + Tags: map[string]string{ + "ifIndex": "bar", + "index": "1", + }, + Fields: map[string]interface{}{ + "atPhysAddress": 2, + }, + } + rtr3 := RTableRow{ + Tags: map[string]string{ + "index": "2", + }, + Fields: map[string]interface{}{ + "atPhysAddress": 0, + }, + } + + require.Len(t, tb.Rows, 3) + require.Contains(t, tb.Rows, rtr1) + require.Contains(t, tb.Rows, rtr2) + require.Contains(t, tb.Rows, rtr3) +} + +func TestTableBuild_noWalkGosmi(t *testing.T) { + tbl := Table{ + Name: "mytable", + Fields: []Field{ + { + Name: "myfield1", + Oid: ".1.0.0.1.1", + IsTag: true, + }, + { + Name: "myfield2", + Oid: ".1.0.0.1.2", + }, + { + Name: "myfield3", + Oid: ".1.0.0.1.2", + IsTag: true, + }, + { + Name: "empty", + Oid: ".1.0.0.0.1.1.2", + }, + { + Name: "noexist", + Oid: ".1.2.3.4.5", + }, + { + Name: "myfield4", + Oid: ".1.3.6.1.2.1.3.1.1.3.0", + Translate: true, + }, + }, + } + + require.NoError(t, tbl.Init(getGosmiTr(t))) + tb, err := tbl.Build(tsc, false) + require.NoError(t, err) + + rtr := RTableRow{ + Tags: map[string]string{"myfield1": "baz", "myfield3": "234"}, + Fields: map[string]interface{}{"myfield2": 234, "myfield4": "atNetAddress"}, + } + require.Len(t, tb.Rows, 1) + require.Contains(t, tb.Rows, rtr) +} + +func TestFieldConvertGosmi(t *testing.T) { + testTable := []struct { + input interface{} + conv string + expected interface{} + }{ + {"0.123", "float", float64(0.123)}, + {[]byte("0.123"), "float", float64(0.123)}, + {float32(0.123), "float", float64(float32(0.123))}, + {float64(0.123), "float", float64(0.123)}, + {float64(0.123123123123), "float", float64(0.123123123123)}, + {123, "float", float64(123)}, + {123, "float(0)", float64(123)}, + {123, "float(4)", float64(0.0123)}, + {int8(123), "float(3)", float64(0.123)}, + {int16(123), "float(3)", float64(0.123)}, + {int32(123), "float(3)", float64(0.123)}, + {int64(123), "float(3)", float64(0.123)}, + {uint(123), "float(3)", float64(0.123)}, + {uint8(123), "float(3)", float64(0.123)}, + {uint16(123), "float(3)", float64(0.123)}, + {uint32(123), "float(3)", float64(0.123)}, + {uint64(123), "float(3)", float64(0.123)}, + {"123", "int", int64(123)}, + {[]byte("123"), "int", int64(123)}, + {"123123123123", "int", int64(123123123123)}, + {[]byte("123123123123"), "int", int64(123123123123)}, + {float32(12.3), "int", int64(12)}, + {float64(12.3), "int", int64(12)}, + {123, "int", int64(123)}, + {int8(123), "int", int64(123)}, + {int16(123), "int", int64(123)}, + {int32(123), "int", int64(123)}, + {int64(123), "int", int64(123)}, + {uint(123), "int", int64(123)}, + {uint8(123), "int", int64(123)}, + {uint16(123), "int", int64(123)}, + {uint32(123), "int", int64(123)}, + {uint64(123), "int", int64(123)}, + {[]byte("abcdef"), "hwaddr", "61:62:63:64:65:66"}, + {"abcdef", "hwaddr", "61:62:63:64:65:66"}, + {[]byte("abcd"), "ipaddr", "97.98.99.100"}, + {"abcd", "ipaddr", "97.98.99.100"}, + {[]byte("abcdefghijklmnop"), "ipaddr", "6162:6364:6566:6768:696a:6b6c:6d6e:6f70"}, + {3, "enum", "testing"}, + {3, "enum(1)", "testing(3)"}, + } + + for _, tc := range testTable { + f := Field{ + Name: "test", + Conversion: tc.conv, + } + require.NoError(t, f.Init(getGosmiTr(t))) + + act, err := f.Convert(gosnmp.SnmpPDU{Name: ".1.3.6.1.2.1.2.2.1.8", Value: tc.input}) + require.NoError(t, err, "input=%T(%v) conv=%s expected=%T(%v)", tc.input, tc.input, tc.conv, tc.expected, tc.expected) + require.EqualValues(t, tc.expected, act, "input=%T(%v) conv=%s expected=%T(%v)", tc.input, tc.input, tc.conv, tc.expected, tc.expected) + } +} + +func TestSnmpFormatDisplayHint(t *testing.T) { + tests := []struct { + name string + oid string + input interface{} + expected string + }{ + { + name: "ifOperStatus", + oid: ".1.3.6.1.2.1.2.2.1.8", + input: 3, + expected: "testing(3)", + }, { + name: "ifPhysAddress", + oid: ".1.3.6.1.2.1.2.2.1.6", + input: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, + expected: "01:23:45:67:89:ab:cd:ef", + }, { + name: "DateAndTime short", + oid: ".1.0.0.0.1.5", + input: []byte{0x07, 0xe8, 0x09, 0x18, 0x10, 0x24, 0x27, 0x05}, + expected: "2024-9-24,16:36:39.5", + }, { + name: "DateAndTime long", + oid: ".1.0.0.0.1.5", + input: []byte{0x07, 0xe8, 0x09, 0x18, 0x10, 0x24, 0x27, 0x05, 0x2b, 0x02, 0x00}, + expected: "2024-9-24,16:36:39.5,+2:0", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tr := getGosmiTr(t) + + actual, err := tr.SnmpFormatDisplayHint(tt.oid, tt.input) + require.NoError(t, err) + + require.Equal(t, tt.expected, actual) + }) + } +} + +func TestTableJoin_walkGosmi(t *testing.T) { + tbl := Table{ + Name: "mytable", + IndexAsTag: true, + Fields: []Field{ + { + Name: "myfield1", + Oid: ".1.0.0.3.1.1", + IsTag: true, + }, + { + Name: "myfield2", + Oid: ".1.0.0.3.1.2", + }, + { + Name: "myfield3", + Oid: ".1.0.0.3.1.3", + SecondaryIndexTable: true, + }, + { + Name: "myfield4", + Oid: ".1.0.0.0.1.1", + SecondaryIndexUse: true, + IsTag: true, + }, + { + Name: "myfield5", + Oid: ".1.0.0.0.1.2", + SecondaryIndexUse: true, + }, + }, + } + + require.NoError(t, tbl.Init(getGosmiTr(t))) + tb, err := tbl.Build(tsc, true) + require.NoError(t, err) + + require.Equal(t, "mytable", tb.Name) + rtr1 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance", + "myfield4": "bar", + "index": "10", + }, + Fields: map[string]interface{}{ + "myfield2": 10, + "myfield3": 1, + "myfield5": 2, + }, + } + rtr2 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance2", + "index": "11", + }, + Fields: map[string]interface{}{ + "myfield2": 20, + "myfield3": 2, + "myfield5": 0, + }, + } + rtr3 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance3", + "index": "12", + }, + Fields: map[string]interface{}{ + "myfield2": 20, + "myfield3": 3, + }, + } + require.Len(t, tb.Rows, 3) + require.Contains(t, tb.Rows, rtr1) + require.Contains(t, tb.Rows, rtr2) + require.Contains(t, tb.Rows, rtr3) +} + +func TestTableOuterJoin_walkGosmi(t *testing.T) { + tbl := Table{ + Name: "mytable", + IndexAsTag: true, + Fields: []Field{ + { + Name: "myfield1", + Oid: ".1.0.0.3.1.1", + IsTag: true, + }, + { + Name: "myfield2", + Oid: ".1.0.0.3.1.2", + }, + { + Name: "myfield3", + Oid: ".1.0.0.3.1.3", + SecondaryIndexTable: true, + SecondaryOuterJoin: true, + }, + { + Name: "myfield4", + Oid: ".1.0.0.0.1.1", + SecondaryIndexUse: true, + IsTag: true, + }, + { + Name: "myfield5", + Oid: ".1.0.0.0.1.2", + SecondaryIndexUse: true, + }, + }, + } + + tb, err := tbl.Build(tsc, true) + require.NoError(t, err) + + require.Equal(t, "mytable", tb.Name) + rtr1 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance", + "myfield4": "bar", + "index": "10", + }, + Fields: map[string]interface{}{ + "myfield2": 10, + "myfield3": 1, + "myfield5": 2, + }, + } + rtr2 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance2", + "index": "11", + }, + Fields: map[string]interface{}{ + "myfield2": 20, + "myfield3": 2, + "myfield5": 0, + }, + } + rtr3 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance3", + "index": "12", + }, + Fields: map[string]interface{}{ + "myfield2": 20, + "myfield3": 3, + }, + } + rtr4 := RTableRow{ + Tags: map[string]string{ + "index": "Secondary.0", + "myfield4": "foo", + }, + Fields: map[string]interface{}{ + "myfield5": 1, + }, + } + require.Len(t, tb.Rows, 4) + require.Contains(t, tb.Rows, rtr1) + require.Contains(t, tb.Rows, rtr2) + require.Contains(t, tb.Rows, rtr3) + require.Contains(t, tb.Rows, rtr4) +} + +func TestTableJoinNoIndexAsTag_walkGosmi(t *testing.T) { + tbl := Table{ + Name: "mytable", + IndexAsTag: false, + Fields: []Field{ + { + Name: "myfield1", + Oid: ".1.0.0.3.1.1", + IsTag: true, + }, + { + Name: "myfield2", + Oid: ".1.0.0.3.1.2", + }, + { + Name: "myfield3", + Oid: ".1.0.0.3.1.3", + SecondaryIndexTable: true, + }, + { + Name: "myfield4", + Oid: ".1.0.0.0.1.1", + SecondaryIndexUse: true, + IsTag: true, + }, + { + Name: "myfield5", + Oid: ".1.0.0.0.1.2", + SecondaryIndexUse: true, + }, + }, + } + + tb, err := tbl.Build(tsc, true) + require.NoError(t, err) + + require.Equal(t, "mytable", tb.Name) + rtr1 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance", + "myfield4": "bar", + // "index": "10", + }, + Fields: map[string]interface{}{ + "myfield2": 10, + "myfield3": 1, + "myfield5": 2, + }, + } + rtr2 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance2", + // "index": "11", + }, + Fields: map[string]interface{}{ + "myfield2": 20, + "myfield3": 2, + "myfield5": 0, + }, + } + rtr3 := RTableRow{ + Tags: map[string]string{ + "myfield1": "instance3", + // "index": "12", + }, + Fields: map[string]interface{}{ + "myfield2": 20, + "myfield3": 3, + }, + } + require.Len(t, tb.Rows, 3) + require.Contains(t, tb.Rows, rtr1) + require.Contains(t, tb.Rows, rtr2) + require.Contains(t, tb.Rows, rtr3) +} + +func TestCanNotParse(t *testing.T) { + tr := getGosmiTr(t) + f := Field{ + Oid: "RFC1213-MIB::", + } + + require.Error(t, f.Init(tr)) +} + +func TestTrapLookup(t *testing.T) { + tests := []struct { + name string + oid string + expected MibEntry + }{ + { + name: "Known trap OID", + oid: ".1.3.6.1.6.3.1.1.5.1", + expected: MibEntry{ + MibName: "TGTEST-MIB", + OidText: "coldStart", + }, + }, + { + name: "Known trap value OID", + oid: ".1.3.6.1.2.1.1.3.0", + expected: MibEntry{ + MibName: "TGTEST-MIB", + OidText: "sysUpTimeInstance", + }, + }, + { + name: "Unknown enterprise sub-OID", + oid: ".1.3.6.1.4.1.0.1.2.3", + expected: MibEntry{ + MibName: "SNMPv2-SMI", + OidText: "enterprises.0.1.2.3", + }, + }, + { + name: "Unknown MIB", + oid: ".1.999", + expected: MibEntry{OidText: "iso.999"}, + }, + } + + // Load the MIBs + getGosmiTr(t) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Run the actual test + actual, err := TrapLookup(tt.oid) + require.NoError(t, err) + require.Equal(t, tt.expected, actual) + }) + } +} + +func TestTrapLookupFail(t *testing.T) { + tests := []struct { + name string + oid string + expected string + }{ + { + name: "New top level OID", + oid: ".3.6.1.3.0", + expected: "Could not find node for OID 3.6.1.3.0", + }, + { + name: "Malformed OID", + oid: ".1.3.dod.1.3.0", + expected: "could not convert OID .1.3.dod.1.3.0: strconv.ParseUint: parsing \"dod\": invalid syntax", + }, + } + + // Load the MIBs + getGosmiTr(t) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Run the actual test + _, err := TrapLookup(tt.oid) + require.EqualError(t, err, tt.expected) + }) + } +} diff --git a/internal/snmp/translator_netsnmp.go b/internal/snmp/translator_netsnmp.go new file mode 100644 index 0000000..4f20dbd --- /dev/null +++ b/internal/snmp/translator_netsnmp.go @@ -0,0 +1,272 @@ +package snmp + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "os/exec" + "strings" + "sync" + + "github.com/influxdata/telegraf" +) + +// struct that implements the translator interface. This calls existing +// code to exec netsnmp's snmptranslate program +type netsnmpTranslator struct { + log telegraf.Logger +} + +func NewNetsnmpTranslator(log telegraf.Logger) *netsnmpTranslator { + return &netsnmpTranslator{log: log} +} + +type snmpTableCache struct { + mibName string + oidNum string + oidText string + fields []Field + err error +} + +// execCommand is so tests can mock out exec.Command usage. +var execCommand = exec.Command + +// execCmd executes the specified command, returning the STDOUT content. +// If command exits with error status, the output is captured into the returned error. +func (n *netsnmpTranslator) execCmd(arg0 string, args ...string) ([]byte, error) { + quoted := make([]string, 0, len(args)) + for _, arg := range args { + quoted = append(quoted, fmt.Sprintf("%q", arg)) + } + n.log.Debugf("executing %q %s", arg0, strings.Join(quoted, " ")) + + out, err := execCommand(arg0, args...).Output() + if err != nil { + var exitErr *exec.ExitError + if errors.As(err, &exitErr) { + return nil, fmt.Errorf("%s: %w", bytes.TrimRight(exitErr.Stderr, "\r\n"), err) + } + return nil, err + } + return out, nil +} + +var snmpTableCaches map[string]snmpTableCache +var snmpTableCachesLock sync.Mutex + +// snmpTable resolves the given OID as a table, providing information about the +// table and fields within. +// +//nolint:revive //function-result-limit conditionally 5 return results allowed +func (n *netsnmpTranslator) SnmpTable(oid string) ( + mibName string, oidNum string, oidText string, + fields []Field, + err error) { + snmpTableCachesLock.Lock() + if snmpTableCaches == nil { + snmpTableCaches = map[string]snmpTableCache{} + } + + var stc snmpTableCache + var ok bool + if stc, ok = snmpTableCaches[oid]; !ok { + stc.mibName, stc.oidNum, stc.oidText, stc.fields, stc.err = n.snmpTableCall(oid) + snmpTableCaches[oid] = stc + } + + snmpTableCachesLock.Unlock() + return stc.mibName, stc.oidNum, stc.oidText, stc.fields, stc.err +} + +//nolint:revive //function-result-limit conditionally 5 return results allowed +func (n *netsnmpTranslator) snmpTableCall(oid string) ( + mibName string, oidNum string, oidText string, + fields []Field, + err error) { + mibName, oidNum, oidText, _, err = n.SnmpTranslate(oid) + if err != nil { + return "", "", "", nil, fmt.Errorf("translating: %w", err) + } + + mibPrefix := mibName + "::" + oidFullName := mibPrefix + oidText + + // first attempt to get the table's tags + tagOids := map[string]struct{}{} + // We have to guess that the "entry" oid is `oid+".1"`. snmptable and snmptranslate don't seem to have a way to provide the info. + if out, err := n.execCmd("snmptranslate", "-Td", oidFullName+".1"); err == nil { + scanner := bufio.NewScanner(bytes.NewBuffer(out)) + for scanner.Scan() { + line := scanner.Text() + + if !strings.HasPrefix(line, " INDEX") { + continue + } + + i := strings.Index(line, "{ ") + if i == -1 { // parse error + continue + } + line = line[i+2:] + i = strings.Index(line, " }") + if i == -1 { // parse error + continue + } + line = line[:i] + for _, col := range strings.Split(line, ", ") { + tagOids[mibPrefix+col] = struct{}{} + } + } + } + + // this won't actually try to run a query. The `-Ch` will just cause it to dump headers. + out, err := n.execCmd("snmptable", "-Ch", "-Cl", "-c", "public", "127.0.0.1", oidFullName) + if err != nil { + return "", "", "", nil, fmt.Errorf("getting table columns: %w", err) + } + scanner := bufio.NewScanner(bytes.NewBuffer(out)) + scanner.Scan() + cols := scanner.Text() + if len(cols) == 0 { + return "", "", "", nil, errors.New("could not find any columns in table") + } + for _, col := range strings.Split(cols, " ") { + if len(col) == 0 { + continue + } + _, isTag := tagOids[mibPrefix+col] + fields = append(fields, Field{Name: col, Oid: mibPrefix + col, IsTag: isTag}) + } + + return mibName, oidNum, oidText, fields, err +} + +type snmpTranslateCache struct { + mibName string + oidNum string + oidText string + conversion string + err error +} + +var snmpTranslateCachesLock sync.Mutex +var snmpTranslateCaches map[string]snmpTranslateCache + +// snmpTranslate resolves the given OID. +// +//nolint:revive //function-result-limit conditionally 5 return results allowed +func (n *netsnmpTranslator) SnmpTranslate(oid string) ( + mibName string, oidNum string, oidText string, + conversion string, + err error) { + snmpTranslateCachesLock.Lock() + if snmpTranslateCaches == nil { + snmpTranslateCaches = map[string]snmpTranslateCache{} + } + + var stc snmpTranslateCache + var ok bool + if stc, ok = snmpTranslateCaches[oid]; !ok { + // This will result in only one call to snmptranslate running at a time. + // We could speed it up by putting a lock in snmpTranslateCache and then + // returning it immediately, and multiple callers would then release the + // snmpTranslateCachesLock and instead wait on the individual + // snmpTranslation.Lock to release. But I don't know that the extra complexity + // is worth it. Especially when it would slam the system pretty hard if lots + // of lookups are being performed. + + stc.mibName, stc.oidNum, stc.oidText, stc.conversion, stc.err = n.snmpTranslateCall(oid) + snmpTranslateCaches[oid] = stc + } + + snmpTranslateCachesLock.Unlock() + + return stc.mibName, stc.oidNum, stc.oidText, stc.conversion, stc.err +} + +//nolint:revive //function-result-limit conditionally 5 return results allowed +func (n *netsnmpTranslator) snmpTranslateCall(oid string) (mibName string, oidNum string, oidText string, conversion string, err error) { + var out []byte + if strings.ContainsAny(oid, ":abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") { + out, err = n.execCmd("snmptranslate", "-Td", "-Ob", oid) + } else { + out, err = n.execCmd("snmptranslate", "-Td", "-Ob", "-m", "all", oid) + var execErr *exec.Error + if errors.As(err, &execErr) && errors.Is(execErr, exec.ErrNotFound) { + // Silently discard error if snmptranslate not found and we have a numeric OID. + // Meaning we can get by without the lookup. + return "", oid, oid, "", nil + } + } + if err != nil { + return "", "", "", "", err + } + + scanner := bufio.NewScanner(bytes.NewBuffer(out)) + ok := scanner.Scan() + if !ok && scanner.Err() != nil { + return "", "", "", "", fmt.Errorf("getting OID text: %w", scanner.Err()) + } + + oidText = scanner.Text() + + i := strings.Index(oidText, "::") + if i == -1 { + // was not found in MIB. + if bytes.Contains(out, []byte("[TRUNCATED]")) { + return "", oid, oid, "", nil + } + // not truncated, but not fully found. We still need to parse out numeric OID, so keep going + oidText = oid + } else { + mibName = oidText[:i] + oidText = oidText[i+2:] + } + + for scanner.Scan() { + line := scanner.Text() + + if strings.HasPrefix(line, " -- TEXTUAL CONVENTION ") { + tc := strings.TrimPrefix(line, " -- TEXTUAL CONVENTION ") + switch tc { + case "MacAddress", "PhysAddress": + conversion = "hwaddr" + case "InetAddressIPv4", "InetAddressIPv6", "InetAddress", "IPSIpAddress": + conversion = "ipaddr" + } + } else if strings.HasPrefix(line, "::= { ") { + objs := strings.TrimPrefix(line, "::= { ") + objs = strings.TrimSuffix(objs, " }") + + for _, obj := range strings.Split(objs, " ") { + if len(obj) == 0 { + continue + } + if i := strings.Index(obj, "("); i != -1 { + obj = obj[i+1:] + if j := strings.Index(obj, ")"); j != -1 { + oidNum += "." + obj[:j] + } else { + return "", "", "", "", fmt.Errorf("getting OID number from: %s", obj) + } + + } else { + oidNum += "." + obj + } + } + break + } + } + + return mibName, oidNum, oidText, conversion, nil +} + +func (*netsnmpTranslator) SnmpFormatEnum(string, interface{}, bool) (string, error) { + return "", errors.New("not implemented in netsnmp translator") +} + +func (*netsnmpTranslator) SnmpFormatDisplayHint(string, interface{}) (string, error) { + return "", errors.New("not implemented in netsnmp translator") +} diff --git a/internal/snmp/translator_netsnmp_mocks_generate.go b/internal/snmp/translator_netsnmp_mocks_generate.go new file mode 100644 index 0000000..7ca46ff --- /dev/null +++ b/internal/snmp/translator_netsnmp_mocks_generate.go @@ -0,0 +1,102 @@ +//go:build generate + +package main + +import ( + "bufio" + "bytes" + "fmt" + "os" + "os/exec" + "strings" +) + +// This file is a generator used to generate the mocks for the commands used by the tests. + +// These are the commands to be mocked. +var mockedCommands = [][]string{ + {"snmptranslate", "-Td", "-Ob", "-m", "all", ".1.0.0.0"}, + {"snmptranslate", "-Td", "-Ob", "-m", "all", ".1.0.0.1.1"}, + {"snmptranslate", "-Td", "-Ob", "-m", "all", ".1.0.0.1.2"}, + {"snmptranslate", "-Td", "-Ob", "-m", "all", "1.0.0.1.1"}, + {"snmptranslate", "-Td", "-Ob", "-m", "all", ".1.0.0.0.1.1"}, + {"snmptranslate", "-Td", "-Ob", "-m", "all", ".1.0.0.0.1.1.0"}, + {"snmptranslate", "-Td", "-Ob", "-m", "all", ".1.0.0.0.1.5"}, + {"snmptranslate", "-Td", "-Ob", "-m", "all", ".1.2.3"}, + {"snmptranslate", "-Td", "-Ob", "-m", "all", ".1.0.0.0.1.7"}, + {"snmptranslate", "-Td", "-Ob", ".iso.2.3"}, + {"snmptranslate", "-Td", "-Ob", "-m", "all", ".999"}, + {"snmptranslate", "-Td", "-Ob", "TEST::server"}, + {"snmptranslate", "-Td", "-Ob", "TEST::server.0"}, + {"snmptranslate", "-Td", "-Ob", "TEST::testTable"}, + {"snmptranslate", "-Td", "-Ob", "TEST::connections"}, + {"snmptranslate", "-Td", "-Ob", "TEST::latency"}, + {"snmptranslate", "-Td", "-Ob", "TEST::description"}, + {"snmptranslate", "-Td", "-Ob", "TEST::hostname"}, + {"snmptranslate", "-Td", "-Ob", "IF-MIB::ifPhysAddress.1"}, + {"snmptranslate", "-Td", "-Ob", "BRIDGE-MIB::dot1dTpFdbAddress.1"}, + {"snmptranslate", "-Td", "-Ob", "TCP-MIB::tcpConnectionLocalAddress.1"}, + {"snmptranslate", "-Td", "TEST::testTable.1"}, + {"snmptable", "-Ch", "-Cl", "-c", "public", "127.0.0.1", "TEST::testTable"}, +} + +type mockedCommandResult struct { + stdout string + stderr string + exitError bool +} + +func main() { + if err := generate(); err != nil { + fmt.Fprintf(os.Stderr, "error: %s\n", err) + os.Exit(1) + } +} + +func generate() error { + f, err := os.OpenFile("snmp_mocks_test.go", os.O_RDWR, 0644) + if err != nil { + return err + } + br := bufio.NewReader(f) + var i int64 + for l, err := br.ReadString('\n'); err == nil; l, err = br.ReadString('\n') { + i += int64(len(l)) + if l == "// BEGIN GO GENERATE CONTENT\n" { + break + } + } + f.Truncate(i) + f.Seek(i, 0) + + fmt.Fprintf(f, "var mockedCommandResults = map[string]mockedCommandResult{\n") + + for _, cmd := range mockedCommands { + ec := exec.Command(cmd[0], cmd[1:]...) + out := bytes.NewBuffer(nil) + err := bytes.NewBuffer(nil) + ec.Stdout = out + ec.Stderr = err + ec.Env = []string{ + "MIBDIRS=+./testdata", + } + + var mcr mockedCommandResult + if err := ec.Run(); err != nil { + if err, ok := err.(*exec.ExitError); !ok { + mcr.exitError = true + } else { + return fmt.Errorf("executing %v: %s", cmd, err) + } + } + mcr.stdout = string(out.Bytes()) + mcr.stderr = string(err.Bytes()) + cmd0 := strings.Join(cmd, "\000") + mcrv := fmt.Sprintf("%#v", mcr)[5:] // trim `main.` prefix + fmt.Fprintf(f, "%#v: %s,\n", cmd0, mcrv) + } + f.Write([]byte("}\n")) + f.Close() + + return exec.Command("gofmt", "-w", "translator_netsnmp_mocks_test.go").Run() +} diff --git a/internal/snmp/translator_netsnmp_mocks_test.go b/internal/snmp/translator_netsnmp_mocks_test.go new file mode 100644 index 0000000..72a00fa --- /dev/null +++ b/internal/snmp/translator_netsnmp_mocks_test.go @@ -0,0 +1,211 @@ +package snmp + +import ( + "fmt" + "os" + "os/exec" + "strings" + "testing" +) + +type mockedCommandResult struct { + stdout string + stderr string + exitError bool +} + +func mockExecCommand(arg0 string, args ...string) *exec.Cmd { + args = append([]string{"-test.run=TestMockExecCommand", "--", arg0}, args...) + cmd := exec.Command(os.Args[0], args...) + cmd.Stderr = os.Stderr // so the test output shows errors + return cmd +} + +// This is not a real test. This is just a way of mocking out commands. +// +// Idea based on https://github.com/golang/go/blob/7c31043/src/os/exec/exec_test.go#L568 +func TestMockExecCommand(_ *testing.T) { + var cmd []string //nolint:prealloc // Pre-allocated this slice would break the algorithm + for _, arg := range os.Args { + if arg == "--" { + cmd = make([]string, 0) + continue + } + if cmd == nil { + continue + } + cmd = append(cmd, arg) + } + if cmd == nil { + return + } + + cmd0 := strings.Join(cmd, "\000") + mcr, ok := mockedCommandResults[cmd0] + if !ok { + cv := fmt.Sprintf("%#v", cmd)[8:] // trim `[]string` prefix + fmt.Fprintf( + os.Stderr, + "Unmocked command. Please add the following to `mockedCommands` in snmp_mocks_generate.go, and then run `go generate`:\n\t%s,\n", + cv, + ) + //nolint:revive // error code is important for this "test" + os.Exit(1) + } + fmt.Printf("%s", mcr.stdout) + fmt.Fprintf(os.Stderr, "%s", mcr.stderr) + if mcr.exitError { + //nolint:revive // error code is important for this "test" + os.Exit(1) + } + //nolint:revive // error code is important for this "test" + os.Exit(0) +} + +func init() { + execCommand = mockExecCommand +} + +// BEGIN GO GENERATE CONTENT +var mockedCommandResults = map[string]mockedCommandResult{ + "snmptranslate\x00-Td\x00-Ob\x00-m\x00all\x00.1.0.0.0": { + stdout: "TEST::testTable\ntestTable OBJECT-TYPE\n -- FROM\tTEST\n MAX-ACCESS\tnot-accessible\n STATUS\tcurrent\n::= { iso(1) 0 testOID(0) 0 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00-m\x00all\x00.1.0.0.1.1": { + stdout: "TEST::hostname\nhostname OBJECT-TYPE\n -- FROM\tTEST\n SYNTAX\tOCTET STRING\n MAX-ACCESS\tread-only\n " + + "STATUS\tcurrent\n::= { iso(1) 0 testOID(0) 1 1 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00-m\x00all\x00.1.0.0.1.2": { + stdout: "TEST::1.2\nanonymous#1 OBJECT-TYPE\n -- FROM\tTEST\n::= { iso(1) 0 testOID(0) 1 2 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00-m\x00all\x001.0.0.1.1": { + stdout: "TEST::hostname\nhostname OBJECT-TYPE\n -- FROM\tTEST\n SYNTAX\tOCTET STRING\n MAX-ACCESS\tread-only\n " + + "STATUS\tcurrent\n::= { iso(1) 0 testOID(0) 1 1 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00-m\x00all\x00.1.0.0.0.1.1": { + stdout: "TEST::server\nserver OBJECT-TYPE\n -- FROM\tTEST\n SYNTAX\tOCTET STRING\n MAX-ACCESS\tread-only\n " + + "STATUS\tcurrent\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) 1 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00-m\x00all\x00.1.0.0.0.1.1.0": { + stdout: "TEST::server.0\nserver OBJECT-TYPE\n -- FROM\tTEST\n SYNTAX\tOCTET STRING\n MAX-ACCESS\tread-only\n " + + "STATUS\tcurrent\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) server(1) 0 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00-m\x00all\x00.1.0.0.0.1.5": { + stdout: "TEST::testTableEntry.5\ntestTableEntry OBJECT-TYPE\n -- FROM\tTEST\n MAX-ACCESS\tnot-accessible\n " + + "STATUS\tcurrent\n INDEX\t\t{ server }\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) 5 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00-m\x00all\x00.1.2.3": { + stdout: "iso.2.3\niso OBJECT-TYPE\n -- FROM\t#-1\n::= { iso(1) 2 3 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00-m\x00all\x00.1.0.0.0.1.7": { + stdout: "TEST::testTableEntry.7\ntestTableEntry OBJECT-TYPE\n -- FROM\tTEST\n MAX-ACCESS\tnot-accessible\n " + + "STATUS\tcurrent\n INDEX\t\t{ server }\n::= { iso(1) std(0) testOID(0) testTable(0) testTableEntry(1) 7 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00.iso.2.3": { + stdout: "iso.2.3\niso OBJECT-TYPE\n -- FROM\t#-1\n::= { iso(1) 2 3 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00-m\x00all\x00.999": {stdout: ".999\n [TRUNCATED]\n", stderr: "", exitError: false}, + "snmptranslate\x00-Td\x00-Ob\x00TEST::server": { + stdout: "TEST::server\nserver OBJECT-TYPE\n -- FROM\tTEST\n SYNTAX\tOCTET STRING\n MAX-ACCESS\tread-only\n " + + "STATUS\tcurrent\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) 1 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00TEST::server.0": { + stdout: "TEST::server.0\nserver OBJECT-TYPE\n -- FROM\tTEST\n SYNTAX\tOCTET STRING\n MAX-ACCESS\tread-only\n " + + "STATUS\tcurrent\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) server(1) 0 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00TEST::testTable": { + stdout: "TEST::testTable\ntestTable OBJECT-TYPE\n -- FROM\tTEST\n MAX-ACCESS\tnot-accessible\n STATUS\tcurrent\n::= { iso(1) 0 testOID(0) 0 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00TEST::connections": { + stdout: "TEST::connections\nconnections OBJECT-TYPE\n -- FROM\tTEST\n SYNTAX\tINTEGER\n MAX-ACCESS\tread-only\n " + + "STATUS\tcurrent\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) 2 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00TEST::latency": { + stdout: "TEST::latency\nlatency OBJECT-TYPE\n -- FROM\tTEST\n SYNTAX\tOCTET STRING\n MAX-ACCESS\tread-only\n " + + "STATUS\tcurrent\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) 3 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00TEST::description": { + stdout: "TEST::description\ndescription OBJECT-TYPE\n -- FROM\tTEST\n SYNTAX\tOCTET STRING\n MAX-ACCESS\tread-only\n " + + "STATUS\tcurrent\n::= { iso(1) 0 testOID(0) testTable(0) testTableEntry(1) 4 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00TEST::hostname": { + stdout: "TEST::hostname\nhostname OBJECT-TYPE\n -- FROM\tTEST\n SYNTAX\tOCTET STRING\n MAX-ACCESS\tread-only\n " + + "STATUS\tcurrent\n::= { iso(1) 0 testOID(0) 1 1 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00IF-MIB::ifPhysAddress.1": { + stdout: "IF-MIB::ifPhysAddress.1\nifPhysAddress OBJECT-TYPE\n -- FROM\tIF-MIB\n -- TEXTUAL CONVENTION PhysAddress\n SYNTAX\tOCTET STRING\n " + + "DISPLAY-HINT\t\"1x:\"\n MAX-ACCESS\tread-only\n STATUS\tcurrent\n DESCRIPTION\t\"The interface's address at its protocol sub-layer. " + + "For\n example, for an 802.x interface, this object normally\n contains a MAC address. " + + "The interface's media-specific MIB\n must define the bit and byte ordering and the format of the\n " + + "value of this object. For interfaces which do not have such\n an address (e.g., a serial line), " + + "this object should contain\n an octet string of zero length.\"\n::= " + + "{ iso(1) org(3) dod(6) internet(1) mgmt(2) mib-2(1) interfaces(2) ifTable(2) ifEntry(1) ifPhysAddress(6) 1 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00BRIDGE-MIB::dot1dTpFdbAddress.1": { + stdout: "BRIDGE-MIB::dot1dTpFdbAddress.1\ndot1dTpFdbAddress OBJECT-TYPE\n -- FROM\tBRIDGE-MIB\n -- TEXTUAL CONVENTION MacAddress\n " + + "SYNTAX\tOCTET STRING (6) \n DISPLAY-HINT\t\"1x:\"\n MAX-ACCESS\tread-only\n STATUS\tcurrent\n DESCRIPTION\t\"" + + "A unicast MAC address for which the bridge has\n forwarding and/or filtering information.\"\n::= " + + "{ iso(1) org(3) dod(6) internet(1) mgmt(2) mib-2(1) dot1dBridge(17) dot1dTp(4) dot1dTpFdbTable(3) dot1dTpFdbEntry(1) dot1dTpFdbAddress(1) 1 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00-Ob\x00TCP-MIB::tcpConnectionLocalAddress.1": { + stdout: "TCP-MIB::tcpConnectionLocalAddress.1\ntcpConnectionLocalAddress OBJECT-TYPE\n -- FROM\tTCP-MIB\n -- " + + "TEXTUAL CONVENTION InetAddress\n SYNTAX\tOCTET STRING (0..255) \n MAX-ACCESS\tnot-accessible\n " + + "STATUS\tcurrent\n DESCRIPTION\t\"The local IP address for this TCP connection. " + + "The type\n of this address is determined by the value of\n tcpConnectionLocalAddressType.\n\n " + + "As this object is used in the index for the\n tcpConnectionTable, implementors should be\n " + + "careful not to create entries that would result in OIDs\n with more than 128 subidentifiers; " + + "otherwise the information\n cannot be accessed by using SNMPv1, SNMPv2c, or SNMPv3.\"\n" + + "::= { iso(1) org(3) dod(6) internet(1) mgmt(2) mib-2(1) tcp(6) tcpConnectionTable(19) tcpConnectionEntry(1) tcpConnectionLocalAddress(2) 1 }\n", + stderr: "", + exitError: false, + }, + "snmptranslate\x00-Td\x00TEST::testTable.1": { + stdout: "TEST::testTableEntry\ntestTableEntry OBJECT-TYPE\n -- FROM\tTEST\n MAX-ACCESS\tnot-accessible\n " + + "STATUS\tcurrent\n INDEX\t\t{ server }\n::= { iso(1) 0 testOID(0) testTable(0) 1 }\n", + stderr: "", + exitError: false, + }, + "snmptable\x00-Ch\x00-Cl\x00-c\x00public\x00127.0.0.1\x00TEST::testTable": { + stdout: "server connections latency description \nTEST::testTable: No entries\n", + stderr: "", + exitError: false, + }, +} diff --git a/internal/snmp/translator_netsnmp_test.go b/internal/snmp/translator_netsnmp_test.go new file mode 100644 index 0000000..b4216b2 --- /dev/null +++ b/internal/snmp/translator_netsnmp_test.go @@ -0,0 +1,291 @@ +//go:generate go run -tags generate translator_netsnmp_mocks_generate.go +package snmp + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/influxdata/telegraf/testutil" +) + +func TestFieldInit(t *testing.T) { + translations := []struct { + inputOid string + inputName string + inputConversion string + expectedOid string + expectedName string + expectedConversion string + }{ + {".1.2.3", "foo", "", ".1.2.3", "foo", ""}, + {".iso.2.3", "foo", "", ".1.2.3", "foo", ""}, + {".1.0.0.0.1.1", "", "", ".1.0.0.0.1.1", "server", ""}, + {".1.0.0.0.1.1.0", "", "", ".1.0.0.0.1.1.0", "server.0", ""}, + {".999", "", "", ".999", ".999", ""}, + {"TEST::server", "", "", ".1.0.0.0.1.1", "server", ""}, + {"TEST::server.0", "", "", ".1.0.0.0.1.1.0", "server.0", ""}, + {"TEST::server", "foo", "", ".1.0.0.0.1.1", "foo", ""}, + {"IF-MIB::ifPhysAddress.1", "", "", ".1.3.6.1.2.1.2.2.1.6.1", "ifPhysAddress.1", "hwaddr"}, + {"IF-MIB::ifPhysAddress.1", "", "none", ".1.3.6.1.2.1.2.2.1.6.1", "ifPhysAddress.1", "none"}, + {"BRIDGE-MIB::dot1dTpFdbAddress.1", "", "", ".1.3.6.1.2.1.17.4.3.1.1.1", "dot1dTpFdbAddress.1", "hwaddr"}, + {"TCP-MIB::tcpConnectionLocalAddress.1", "", "", ".1.3.6.1.2.1.6.19.1.2.1", "tcpConnectionLocalAddress.1", "ipaddr"}, + } + + tr := NewNetsnmpTranslator(testutil.Logger{}) + for _, txl := range translations { + f := Field{Oid: txl.inputOid, Name: txl.inputName, Conversion: txl.inputConversion} + err := f.Init(tr) + require.NoError(t, err, "inputOid=%q inputName=%q", txl.inputOid, txl.inputName) + require.Equal(t, txl.expectedOid, f.Oid, "inputOid=%q inputName=%q inputConversion=%q", txl.inputOid, txl.inputName, txl.inputConversion) + require.Equal(t, txl.expectedName, f.Name, "inputOid=%q inputName=%q inputConversion=%q", txl.inputOid, txl.inputName, txl.inputConversion) + } +} + +func TestTableInit(t *testing.T) { + tbl := Table{ + Oid: ".1.0.0.0", + Fields: []Field{ + {Oid: ".999", Name: "foo"}, + {Oid: "TEST::description", Name: "description", IsTag: true}, + }, + } + err := tbl.Init(NewNetsnmpTranslator(testutil.Logger{})) + require.NoError(t, err) + + require.Equal(t, "testTable", tbl.Name) + + require.Len(t, tbl.Fields, 5) + + require.Equal(t, ".999", tbl.Fields[0].Oid) + require.Equal(t, "foo", tbl.Fields[0].Name) + require.False(t, tbl.Fields[0].IsTag) + require.Empty(t, tbl.Fields[0].Conversion) + + require.Equal(t, ".1.0.0.0.1.1", tbl.Fields[2].Oid) + require.Equal(t, "server", tbl.Fields[2].Name) + require.True(t, tbl.Fields[1].IsTag) + require.Empty(t, tbl.Fields[1].Conversion) + + require.Equal(t, ".1.0.0.0.1.2", tbl.Fields[3].Oid) + require.Equal(t, "connections", tbl.Fields[3].Name) + require.False(t, tbl.Fields[3].IsTag) + require.Empty(t, tbl.Fields[3].Conversion) + + require.Equal(t, ".1.0.0.0.1.3", tbl.Fields[4].Oid) + require.Equal(t, "latency", tbl.Fields[4].Name) + require.False(t, tbl.Fields[4].IsTag) + require.Empty(t, tbl.Fields[4].Conversion) + + require.Equal(t, ".1.0.0.0.1.4", tbl.Fields[1].Oid) + require.Equal(t, "description", tbl.Fields[1].Name) + require.True(t, tbl.Fields[1].IsTag) + require.Empty(t, tbl.Fields[1].Conversion) +} + +func TestTableBuild_walk(t *testing.T) { + tbl := Table{ + Name: "mytable", + IndexAsTag: true, + Fields: []Field{ + { + Name: "myfield1", + Oid: ".1.0.0.0.1.1", + IsTag: true, + }, + { + Name: "myfield2", + Oid: ".1.0.0.0.1.2", + }, + { + Name: "myfield3", + Oid: ".1.0.0.0.1.3", + Conversion: "float", + }, + { + Name: "myfield4", + Oid: ".1.0.0.2.1.5", + OidIndexSuffix: ".9.9", + }, + { + Name: "myfield5", + Oid: ".1.0.0.2.1.5", + OidIndexLength: 1, + }, + { + Name: "myfield6", + Oid: ".1.0.0.0.1.6", + Translate: true, + }, + { + Name: "myfield7", + Oid: ".1.0.0.0.1.6", + Translate: false, + }, + }, + } + + require.NoError(t, tbl.Init(NewNetsnmpTranslator(testutil.Logger{}))) + + tb, err := tbl.Build(tsc, true) + require.NoError(t, err) + + require.Equal(t, "mytable", tb.Name) + rtr1 := RTableRow{ + Tags: map[string]string{ + "myfield1": "foo", + "index": "0", + }, + Fields: map[string]interface{}{ + "myfield2": 1, + "myfield3": float64(0.123), + "myfield4": 11, + "myfield5": 11, + "myfield6": "testTableEntry.7", + "myfield7": ".1.0.0.0.1.7", + }, + } + rtr2 := RTableRow{ + Tags: map[string]string{ + "myfield1": "bar", + "index": "1", + }, + Fields: map[string]interface{}{ + "myfield2": 2, + "myfield3": float64(0.456), + "myfield4": 22, + "myfield5": 22, + }, + } + rtr3 := RTableRow{ + Tags: map[string]string{ + "index": "2", + }, + Fields: map[string]interface{}{ + "myfield2": 0, + "myfield3": float64(0.0), + }, + } + rtr4 := RTableRow{ + Tags: map[string]string{ + "index": "3", + }, + Fields: map[string]interface{}{ + "myfield3": float64(9.999), + }, + } + require.Len(t, tb.Rows, 4) + require.Contains(t, tb.Rows, rtr1) + require.Contains(t, tb.Rows, rtr2) + require.Contains(t, tb.Rows, rtr3) + require.Contains(t, tb.Rows, rtr4) +} + +func TestTableBuild_noWalk(t *testing.T) { + tbl := Table{ + Name: "mytable", + Fields: []Field{ + { + Name: "myfield1", + Oid: ".1.0.0.1.1", + IsTag: true, + }, + { + Name: "myfield2", + Oid: ".1.0.0.1.2", + }, + { + Name: "myfield3", + Oid: ".1.0.0.1.2", + IsTag: true, + }, + { + Name: "empty", + Oid: ".1.0.0.0.1.1.2", + }, + { + Name: "noexist", + Oid: ".1.2.3.4.5", + }, + { + Name: "myfield4", + Oid: ".1.0.0.0.1.6.0", + Translate: true, + }, + }, + } + + require.NoError(t, tbl.Init(NewNetsnmpTranslator(testutil.Logger{}))) + tb, err := tbl.Build(tsc, false) + require.NoError(t, err) + + rtr := RTableRow{ + Tags: map[string]string{"myfield1": "baz", "myfield3": "234"}, + Fields: map[string]interface{}{"myfield2": 234, "myfield4": "testTableEntry.7"}, + } + require.Len(t, tb.Rows, 1) + require.Contains(t, tb.Rows, rtr) +} + +func TestSnmpTranslateCache_miss(t *testing.T) { + snmpTranslateCaches = nil + oid := "IF-MIB::ifPhysAddress.1" + mibName, oidNum, oidText, conversion, err := NewNetsnmpTranslator(testutil.Logger{}).SnmpTranslate(oid) + require.Len(t, snmpTranslateCaches, 1) + stc := snmpTranslateCaches[oid] + require.NotNil(t, stc) + require.Equal(t, mibName, stc.mibName) + require.Equal(t, oidNum, stc.oidNum) + require.Equal(t, oidText, stc.oidText) + require.Equal(t, conversion, stc.conversion) + require.Equal(t, err, stc.err) +} + +func TestSnmpTranslateCache_hit(t *testing.T) { + snmpTranslateCaches = map[string]snmpTranslateCache{ + "foo": { + mibName: "a", + oidNum: "b", + oidText: "c", + conversion: "d", + }, + } + mibName, oidNum, oidText, conversion, err := NewNetsnmpTranslator(testutil.Logger{}).SnmpTranslate("foo") + require.Equal(t, "a", mibName) + require.Equal(t, "b", oidNum) + require.Equal(t, "c", oidText) + require.Equal(t, "d", conversion) + require.NoError(t, err) + snmpTranslateCaches = nil +} + +func TestSnmpTableCache_miss(t *testing.T) { + snmpTableCaches = nil + oid := ".1.0.0.0" + mibName, oidNum, oidText, fields, err := NewNetsnmpTranslator(testutil.Logger{}).SnmpTable(oid) + require.Len(t, snmpTableCaches, 1) + stc := snmpTableCaches[oid] + require.NotNil(t, stc) + require.Equal(t, mibName, stc.mibName) + require.Equal(t, oidNum, stc.oidNum) + require.Equal(t, oidText, stc.oidText) + require.Equal(t, fields, stc.fields) + require.Equal(t, err, stc.err) +} + +func TestSnmpTableCache_hit(t *testing.T) { + snmpTableCaches = map[string]snmpTableCache{ + "foo": { + mibName: "a", + oidNum: "b", + oidText: "c", + fields: []Field{{Name: "d"}}, + }, + } + mibName, oidNum, oidText, fields, err := NewNetsnmpTranslator(testutil.Logger{}).SnmpTable("foo") + require.Equal(t, "a", mibName) + require.Equal(t, "b", oidNum) + require.Equal(t, "c", oidText) + require.Equal(t, []Field{{Name: "d"}}, fields) + require.NoError(t, err) +} diff --git a/internal/snmp/wrapper.go b/internal/snmp/wrapper.go new file mode 100644 index 0000000..aaab0a4 --- /dev/null +++ b/internal/snmp/wrapper.go @@ -0,0 +1,201 @@ +package snmp + +import ( + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/gosnmp/gosnmp" +) + +// Connection is an interface which wraps a *gosnmp.GoSNMP object. +// We interact through an interface so we can mock it out in tests. +type Connection interface { + Host() string + // BulkWalkAll(string) ([]gosnmp.SnmpPDU, error) + Walk(string, gosnmp.WalkFunc) error + Get(oids []string) (*gosnmp.SnmpPacket, error) + Reconnect() error +} + +// GosnmpWrapper wraps a *gosnmp.GoSNMP object so we can use it as a snmpConnection. +type GosnmpWrapper struct { + *gosnmp.GoSNMP +} + +// Host returns the value of GoSNMP.Target. +func (gs GosnmpWrapper) Host() string { + return gs.Target +} + +// Walk wraps GoSNMP.Walk() or GoSNMP.BulkWalk(), depending on whether the +// connection is using SNMPv1 or newer. +func (gs GosnmpWrapper) Walk(oid string, fn gosnmp.WalkFunc) error { + if gs.Version == gosnmp.Version1 { + return gs.GoSNMP.Walk(oid, fn) + } + return gs.GoSNMP.BulkWalk(oid, fn) +} + +func NewWrapper(s ClientConfig) (GosnmpWrapper, error) { + gs := GosnmpWrapper{&gosnmp.GoSNMP{}} + + gs.Timeout = time.Duration(s.Timeout) + + gs.Retries = s.Retries + + gs.UseUnconnectedUDPSocket = s.UnconnectedUDPSocket + + switch s.Version { + case 3: + gs.Version = gosnmp.Version3 + case 2, 0: + gs.Version = gosnmp.Version2c + case 1: + gs.Version = gosnmp.Version1 + default: + return GosnmpWrapper{}, errors.New("invalid version") + } + + if s.Version < 3 { + if s.Community == "" { + gs.Community = "public" + } else { + gs.Community = s.Community + } + } + + gs.MaxRepetitions = s.MaxRepetitions + + if s.Version == 3 { + gs.ContextName = s.ContextName + + sp := &gosnmp.UsmSecurityParameters{} + gs.SecurityParameters = sp + gs.SecurityModel = gosnmp.UserSecurityModel + + switch strings.ToLower(s.SecLevel) { + case "noauthnopriv", "": + gs.MsgFlags = gosnmp.NoAuthNoPriv + case "authnopriv": + gs.MsgFlags = gosnmp.AuthNoPriv + case "authpriv": + gs.MsgFlags = gosnmp.AuthPriv + default: + return GosnmpWrapper{}, errors.New("invalid secLevel") + } + + sp.UserName = s.SecName + + switch strings.ToLower(s.AuthProtocol) { + case "md5": + sp.AuthenticationProtocol = gosnmp.MD5 + case "sha": + sp.AuthenticationProtocol = gosnmp.SHA + case "sha224": + sp.AuthenticationProtocol = gosnmp.SHA224 + case "sha256": + sp.AuthenticationProtocol = gosnmp.SHA256 + case "sha384": + sp.AuthenticationProtocol = gosnmp.SHA384 + case "sha512": + sp.AuthenticationProtocol = gosnmp.SHA512 + case "": + sp.AuthenticationProtocol = gosnmp.NoAuth + default: + return GosnmpWrapper{}, errors.New("invalid authProtocol") + } + + if !s.AuthPassword.Empty() { + p, err := s.AuthPassword.Get() + if err != nil { + return GosnmpWrapper{}, fmt.Errorf("getting authentication password failed: %w", err) + } + sp.AuthenticationPassphrase = p.String() + p.Destroy() + } + + switch strings.ToLower(s.PrivProtocol) { + case "des": + sp.PrivacyProtocol = gosnmp.DES + case "aes": + sp.PrivacyProtocol = gosnmp.AES + case "aes192": + sp.PrivacyProtocol = gosnmp.AES192 + case "aes192c": + sp.PrivacyProtocol = gosnmp.AES192C + case "aes256": + sp.PrivacyProtocol = gosnmp.AES256 + case "aes256c": + sp.PrivacyProtocol = gosnmp.AES256C + case "": + sp.PrivacyProtocol = gosnmp.NoPriv + default: + return GosnmpWrapper{}, errors.New("invalid privProtocol") + } + + if !s.PrivPassword.Empty() { + p, err := s.PrivPassword.Get() + if err != nil { + return GosnmpWrapper{}, fmt.Errorf("getting private password failed: %w", err) + } + sp.PrivacyPassphrase = p.String() + p.Destroy() + } + sp.AuthoritativeEngineID = s.EngineID + sp.AuthoritativeEngineBoots = s.EngineBoots + sp.AuthoritativeEngineTime = s.EngineTime + } + return gs, nil +} + +// SetAgent takes a url (scheme://host:port) and sets the wrapped +// GoSNMP struct's corresponding fields. This shouldn't be called +// after using the wrapped GoSNMP struct, for example after +// connecting. +func (gs *GosnmpWrapper) SetAgent(agent string) error { + if !strings.Contains(agent, "://") { + agent = "udp://" + agent + } + + u, err := url.Parse(agent) + if err != nil { + return err + } + + // Only allow udp{4,6} and tcp{4,6}. + // Allowing ip{4,6} does not make sense as specifying a port + // requires the specification of a protocol. + // gosnmp does not handle these errors well, which is why + // they can result in cryptic errors by net.Dial. + switch u.Scheme { + case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6": + gs.Transport = u.Scheme + default: + return fmt.Errorf("unsupported scheme: %v", u.Scheme) + } + + gs.Target = u.Hostname() + + portStr := u.Port() + if portStr == "" { + portStr = "161" + } + port, err := strconv.ParseUint(portStr, 10, 16) + if err != nil { + return fmt.Errorf("parsing port: %w", err) + } + gs.Port = uint16(port) + return nil +} + +func (gs GosnmpWrapper) Reconnect() error { + if gs.Conn == nil { + return gs.Connect() + } + + return nil +} diff --git a/internal/snmp/wrapper_test.go b/internal/snmp/wrapper_test.go new file mode 100644 index 0000000..3f41627 --- /dev/null +++ b/internal/snmp/wrapper_test.go @@ -0,0 +1,89 @@ +package snmp + +import "github.com/gosnmp/gosnmp" + +type testSNMPConnection struct { + host string + values map[string]interface{} +} + +func (tsc *testSNMPConnection) Host() string { + return tsc.host +} + +func (tsc *testSNMPConnection) Get(oids []string) (*gosnmp.SnmpPacket, error) { + sp := &gosnmp.SnmpPacket{} + for _, oid := range oids { + v, ok := tsc.values[oid] + if !ok { + sp.Variables = append(sp.Variables, gosnmp.SnmpPDU{ + Name: oid, + Type: gosnmp.NoSuchObject, + }) + continue + } + sp.Variables = append(sp.Variables, gosnmp.SnmpPDU{ + Name: oid, + Value: v, + }) + } + return sp, nil +} +func (tsc *testSNMPConnection) Walk(oid string, wf gosnmp.WalkFunc) error { + for void, v := range tsc.values { + if void == oid || (len(void) > len(oid) && void[:len(oid)+1] == oid+".") { + if err := wf(gosnmp.SnmpPDU{ + Name: void, + Value: v, + }); err != nil { + return err + } + } + } + return nil +} +func (*testSNMPConnection) Reconnect() error { + return nil +} + +var tsc = &testSNMPConnection{ + host: "tsc", + values: map[string]interface{}{ + ".1.0.0.0.1.1.0": "foo", + ".1.0.0.0.1.1.1": []byte("bar"), + ".1.0.0.0.1.1.2": []byte(""), + ".1.0.0.0.1.102": "bad", + ".1.0.0.0.1.2.0": 1, + ".1.0.0.0.1.2.1": 2, + ".1.0.0.0.1.2.2": 0, + ".1.0.0.0.1.3.0": "0.123", + ".1.0.0.0.1.3.1": "0.456", + ".1.0.0.0.1.3.2": "0.000", + ".1.0.0.0.1.3.3": "9.999", + ".1.0.0.0.1.5.0": 123456, + ".1.0.0.0.1.6.0": ".1.0.0.0.1.7", + ".1.0.0.1.1": "baz", + ".1.0.0.1.2": 234, + ".1.0.0.1.3": []byte("byte slice"), + ".1.0.0.2.1.5.0.9.9": 11, + ".1.0.0.2.1.5.1.9.9": 22, + ".1.0.0.3.1.1.10": "instance", + ".1.0.0.3.1.1.11": "instance2", + ".1.0.0.3.1.1.12": "instance3", + ".1.0.0.3.1.2.10": 10, + ".1.0.0.3.1.2.11": 20, + ".1.0.0.3.1.2.12": 20, + ".1.0.0.3.1.3.10": 1, + ".1.0.0.3.1.3.11": 2, + ".1.0.0.3.1.3.12": 3, + ".1.3.6.1.2.1.3.1.1.1.0": "foo", + ".1.3.6.1.2.1.3.1.1.1.1": []byte("bar"), + ".1.3.6.1.2.1.3.1.1.1.2": []byte(""), + ".1.3.6.1.2.1.3.1.1.102": "bad", + ".1.3.6.1.2.1.3.1.1.2.0": 1, + ".1.3.6.1.2.1.3.1.1.2.1": 2, + ".1.3.6.1.2.1.3.1.1.2.2": 0, + ".1.3.6.1.2.1.3.1.1.3.0": "1.3.6.1.2.1.3.1.1.3", + ".1.3.6.1.2.1.3.1.1.5.0": 123456, + }, +} diff --git a/internal/templating/engine.go b/internal/templating/engine.go new file mode 100644 index 0000000..cb0a6f1 --- /dev/null +++ b/internal/templating/engine.go @@ -0,0 +1,88 @@ +package templating + +import ( + "sort" + "strings" +) + +const ( + // DefaultSeparator is the default separation character to use when separating template parts. + DefaultSeparator = "." +) + +// Engine uses a Matcher to retrieve the appropriate template and applies the template +// to the input string +type Engine struct { + joiner string + matcher *matcher +} + +// Apply extracts the template fields from the given line and returns the measurement +// name, tags and field name +// +//nolint:revive //function-result-limit conditionally 4 return results allowed +func (e *Engine) Apply(line string) (measurementName string, tags map[string]string, field string, err error) { + return e.matcher.match(line).Apply(line, e.joiner) +} + +// NewEngine creates a new templating engine +func NewEngine(joiner string, defaultTemplate *Template, templates []string) (*Engine, error) { + engine := Engine{ + joiner: joiner, + matcher: newMatcher(defaultTemplate), + } + templateSpecs := parseTemplateSpecs(templates) + + for _, templateSpec := range templateSpecs { + if err := engine.matcher.addSpec(templateSpec); err != nil { + return nil, err + } + } + + return &engine, nil +} + +func parseTemplateSpecs(templates []string) templateSpecs { + tmplts := templateSpecs{} + for _, pattern := range templates { + tmplt := templateSpec{ + separator: DefaultSeparator, + } + + // Format is [separator] [filter]